在android上使用短阵列混合两个文件音频wav

时间:2013-05-31 08:46:52

标签: java android audio

写我的程序,但它不能很好地工作,我不知道我错在哪里。在此之前我使用byte []来存储来自wav的数据(它工作得很好但很吵)所以我切换到short [],但结果非常糟糕。

这是我的代码:

public class Mix extends Activity {


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    try {
        mixSound();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private void mixSound() throws IOException {

    in1 = getResources().openRawResource(R.raw.media_b); //16-bit little-endian, 1411kbps, 44100Hz, 2 channels 
    in2 = getResources().openRawResource(R.raw.media_c); //16-bit little-endian, 1411kbps, 44100Hz, 2 channels 

    List<Short> music1  =  createMusicArray(in1);
    List<Short> music2  =  createMusicArray(in2);

    completeStreams(music1, music2);

    short[] arrayMusic1 = buildShortArray(music1);;
    short[] arrayMusic2 = buildShortArray(music2);

    output = new short[arrayMusic1.length];

    for (int i = 0; i < output.length; i++) {


    }

    saveToFile();
}




/**
 * createMusicArray reads the stream and returns a list of short objects (the samples)
 */
public List<Short> createMusicArray (InputStream ins) throws IOException {
    List<Short> musicList = new ArrayList<Short>();

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] byteArray           = new byte[50*1024];
    int i = Integer.MAX_VALUE;
    while ((i = ins.read(byteArray, 0, byteArray.length)) > 0) {
        baos.write(byteArray, 0, i);
    }

    for (int j = 0; j < byteArray.length; j++) {
        short objShort = (short)(byteArray[j]); 
        musicList.add(objShort);
    }

    return musicList;

}

/**
 * completeStreams normalizes the streams by adding  a series of '0' shorts at the end of smaller files. At the end the 2 files have all the same length.
 */
public void completeStreams(List<Short> mListShort_1, List<Short> mListShort_2) {
    //TODO: check length
    int size_a = mListShort_1.size();
    int size_b = mListShort_2.size();

    if (size_a > size_b){
        // adding series of '0'
        for (int i = size_b+1; i <= size_a; i++) {
            mListShort_2.set(i, (short) 0);
        }
    } else if (size_a < size_b) {
        for (int i = size_a+1; i <= size_b; i++) {
            mListShort_1.set(i, (short) 0);
        }
    } else {
        //do nothing
    }
}




private byte[] shortArrayToByteArray(short[] shortArr) {
    /**
    int index;
    int iterations = shortArr.length;
    ByteBuffer byteBuffer = ByteBuffer.allocate(shortArr.length * 2);

    for(index = 0; index != iterations; ++index){
      byteBuffer.putShort(shortArr[index]);    
    }

    return byteBuffer.array();
    */

    int short_index, byte_index;
    int iterations = shortArr.length;

    byte [] buffer = new byte[shortArr.length * 2];

    short_index = byte_index = 0;

    for(/*NOP*/; short_index != iterations; /*NOP*/) {
        buffer[byte_index]      =   (byte) (shortArr[short_index] & 0x00FF); 
        buffer[byte_index + 1]  =   (byte) ((shortArr[short_index] & 0xFF00) >> 8);

        ++short_index; byte_index += 2;
    }

    return buffer;
}

private byte[] intToByteArray(int i) {
    byte[] b = new byte[4];
    b[0]     = (byte) (i & 0x00FF);
    b[1]     = (byte) ((i >> 8)  & 0x000000FF);
    b[2]     = (byte) ((i >> 16) & 0x000000FF);
    b[3]     = (byte) ((i >> 24) & 0x000000FF);
    return b;
}

private byte[] shortToByteArray(short data) {
    byte[] b = new byte[2];
    b[0] = (byte) (data & 0xff);
    b[1] = (byte) ((data >> 8) & 0xff);
    return b;
}

public static long byteArrayToLong(byte[] b) {
    int  start = 0;
    int      i = 0;
    int    len = 4;
    int    cnt = 0;
    byte[] tmp = new byte[len];
    for (i = start; i < (start + len); i++) {
        tmp[cnt] = b[i];
        cnt++;
    }
    long accum = 0;
    i = 0;
    for (int shiftBy = 0; shiftBy < 32; shiftBy += 8) {
        accum |= ((long) (tmp[i] & 0xff)) << shiftBy;
        i++;
    }
    return accum;
}

}

你能帮我吗?非常感谢你!

1 个答案:

答案 0 :(得分:1)

您的主要问题在于此功能:

/**
 * createMusicArray reads the stream and returns a list of short objects (the samples)
 */
public List<Short> createMusicArray (InputStream ins) throws IOException {
    List<Short> musicList = new ArrayList<Short>();

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] byteArray           = new byte[50*1024];
    int i = Integer.MAX_VALUE;
    while ((i = ins.read(byteArray, 0, byteArray.length)) > 0) {
        baos.write(byteArray, 0, i);
    }

    for (int j = 0; j < byteArray.length; j++) {
        short objShort = (short)(byteArray[j]); 
        musicList.add(objShort);
    }

    return musicList;
}

看起来你正在接受原始字节并简单地将它们转换为短路,但每个短路需要文件中两个字节的数据。 (请参阅shortArrayToByteArray函数中的处理方法)。从文件读取原始短路的最简单方法是使用DataInputStream。不幸的是,您还需要担心字节顺序,因此您需要从guava获取LittleEndianDataInputStream,或者您可以编写自己的类来执行相同的操作,例如this,如果您不想要导入整个番石榴库。试试这个(未经测试,所以你可能需要调整它):

/**
 * createMusicArray reads the stream and returns a list of short objects (the samples)
 */
public List<Short> createMusicArray (InputStream ins) throws IOException {
    LittleEndianDataInputStream dis = new LittleEndianDataInputStream(ins);

    while (true) {
        try {
            short d = dis.readShort();
            musicList.add(d);
        } catch( EOFException e ) {
            break;
        }
    }

    return musicList;
}

作为旁注,将所有数据存储在列表中然后将其传输到数组是非常低效(并且令人困惑)。您应该考虑使用ArrayList,或者更好地获取媒体数据的大小,并使用它来构建一个正确大小的数组。但是,这些都不会确保您仍然可以执行操作,因为您尝试将整个文件放在内存中。相反,尝试阅读每个文件的较小的chucnks,并混合它们,然后读取下一个块。

但是在你开始工作之前我不会担心这一切。