1

to write my programs, but it does not work so well, I do not know where I was wrong. Before that I used byte [] to store data from wav (it works pretty good but noisy) so I switched to short [], but the results were very bad.

This my code:

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;
}

}

Can you help me. Thank you very much!

coffee
  • 23
  • 1
  • 7

1 Answers1

1

Your main problem is in this function:

/**
 * 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;
}

It seems you are taking raw bytes and simply casting them to shorts, but each short needs the data rom two bytes in the file. (see how you handled this correctly in your shortArrayToByteArray function). The easiest way to read raw shorts off a file is with a DataInputStream. Unfortunately, you also need to worry about byte order, so you need to get LittleEndianDataInputStream from guava, or you could write your own class to do the same thing, like this, if you don't want to import the whole guava library. Try this (untested, so you might have to tweak it):

/**
 * 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;
}

As a side note, it's pretty inefficient (and confusing) to store all that data in list and then transfer it to an array. You should consider just using an ArrayList, or better yet getting the size of the media data and using that to build an array of the correct size in the first place. However, none of those things will ensure that you can still perform the operation because you are trying to put the whole file in memory. Instead, try reading smaller chucnks of each file, and mixing those, and then reading the next chunk.

But I wouldn't worry about all that until you get this working.

Community
  • 1
  • 1
Bjorn Roche
  • 11,279
  • 6
  • 36
  • 58
  • Thank you very much! You're good. I will try your suggestion. Thank you for taking your time to suggest solutions to my problem. I will try. You are great. – coffee May 31 '13 at 15:30
  • I had run unsuccessfully, force close.I just mix the small file (even when using bit[] saved data wav): **java.lang.OutOfMemoryError** on line musicList.add(d); What do you think about this issue? – coffee Jun 01 '13 at 05:41
  • Your overall strategy of loading the entire file into a list of Shorts, then converting to an array do shorts is very memory intensive. This is what I was talking about in my "side note" at the end of my answer. I would try with VERY small wave files until you get this working, then optimize. Hint: work in chunks, not the entire file, and use arrays. – Bjorn Roche Jun 01 '13 at 13:51
  • In my Android ArrayVector unavailable. It looks like I did not understand much of what you suggest. I tried to change the ArrayList List but things seem so bad. You can tell me specifically how to edit code and where. Wav files of my large size 44.8 MB. It's too big :) – coffee Jun 02 '13 at 02:52
  • I understand that you want to split wav file and segment mix together. But I do not know how this code at all. Anyway, I will try. This problem is hard. Thank you very much. – coffee Jun 02 '13 at 17:01