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

Java 在android上混合两个文件音频wav使用短阵列,java,android,audio,Java,Android,Audio,写我的程序,但它不太好用,我不知道我哪里错了。在此之前,我使用byte[]存储来自wav的数据(它工作得很好,但有噪音),所以我切换到short[],但结果非常糟糕 这是我的代码: public class Mix extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView

写我的程序,但它不太好用,我不知道我哪里错了。在此之前,我使用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;
}
公共类混合扩展活动{
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
试一试{
混音();
}捕获(IOE异常){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
私有void mixSound()引发IOException{
in1=getResources().openRawResource(R.raw.media_b);//16位little-endian,1411kbps,44100Hz,2个通道
in2=getResources().openRawResource(R.raw.media_c);//16位little-endian,1411kbps,44100Hz,2个通道
List music1=创建MUSICARRAY(in1);
List music2=创建MUSICARRAY(in2);
完整流程(音乐1、音乐2);
short[]arrayMusic1=buildShortArray(music1);;
short[]arrayMusic2=构建短数组(music2);
输出=新短[arrayMusic1.length];
for(int i=0;i0){
写(byteArray,0,i);
}
对于(int j=0;j尺寸b){
//正在添加“0”的系列
对于(int i=尺寸_b+1;i 8);
++短索引;字节索引+=2;
}
返回缓冲区;
}
专用字节[]intToByteArray(int i){
字节[]b=新字节[4];
b[0]=(字节)(i&0x00FF);
b[1]=(字节)((i>>8)&0x000000FF);
b[2]=(字节)((i>>16)和0x000000FF);
b[3]=(字节)((i>>24)&0x000000FF);
返回b;
}
专用字节[]短字节数组(短数据){
字节[]b=新字节[2];
b[0]=(字节)(数据和0xff);
b[1]=(字节)((数据>>8)和0xff);
返回b;
}
公共静态long byteArrayToLong(字节[]b){
int start=0;
int i=0;
int len=4;
int-cnt=0;
字节[]tmp=新字节[len];
对于(i=开始;i<(开始+长度);i++){
tmp[cnt]=b[i];
cnt++;
}
长累计=0;
i=0;
对于(int-shiftBy=0;shiftBy<32;shiftBy+=8){

accum |=((长)(tmp[i]&0xff))您的主要问题在于此函数:

/**
 * 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;
}
/**
*createMusicArray读取流并返回短对象列表(示例)
*/
公共列表createMusicArray(InputStream ins)引发IOException{
List musicList=new ArrayList();
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
字节[]字节数组=新字节[50*1024];
int i=整数的最大值;
而((i=ins.read(byteArray,0,byteArray.length))>0){
写(byteArray,0,i);
}
对于(int j=0;j
似乎您正在获取原始字节并简单地将它们转换为short,但每个short都需要文件中的两个字节的数据rom(请参阅shortArrayToByteArray函数中如何正确处理此问题)。从文件中读取原始短消息的最简单方法是使用DataInputStream。不幸的是,您还需要担心字节顺序,因此您需要从中获取少量的NDI和TAInputStream,或者您可以编写自己的类来执行相同的操作,例如,如果您不想导入整个guava库。请尝试此方法(未经测试,因此可能需要调整):

/**
*createMusicArray读取流并返回短对象列表(示例)
*/
公共列表createMusicArray(InputStream ins)引发IOException{
LittleEndAndaindPutStream dis=新的LittleEndAndaindPutStream(ins);
while(true){
试一试{
short d=dis.readShort();
音乐列表。添加(d);
}捕获(EOFEException e){
打破
}
}
回归音乐家;
}
顺便说一句,它效率很低(而且令人困惑)将所有数据存储在列表中,然后将其转换成一个数组。您应该考虑只使用ARARYLIST,或者更好地获取媒体数据的大小,并使用它来构建一个正确大小的数组。但是,这些东西中没有一个会确保您仍然可以执行该操作,因为您正试图将其放在整个文件在内存中。相反,尝试读取每个文件的较小chucnk,并混合它们,然后读取下一个块


但我不会担心所有这些,直到你让它工作。

你的主要问题在于这个函数:

/**
 * 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;
}
/**
*createMusicArray读取流并返回短对象列表(示例)
*/
公共列表createMusicArray(InputStream ins)引发IOException{
List musicList=new ArrayList();
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
字节[]字节数组=新字节[50*1024];
int i=整数的最大值;
而((i=ins.read(byteArray,0,byteArray.length))>0){
写(byteArray,0,i);
}
对于(int j=0;j