tags:

views:

31

answers:

1

Hi! I want to mix to multiple ULAW samples together in Java. Is there a way to do so without converting to PCM? Im trying to do a 8000Hz 8bit VoIP app. Im testing with AU files (created in goldwave) since they use the ULAW encoding. My current implementation is:

[code]

    AudioFormat f = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 8000, 16, 1, 2, 8000, false);
    SourceDataLine sdl = AudioSystem.getSourceDataLine(f);
    sdl.open(f);
    sdl.start();

    File file1 = new File("C:\\Scream3.au");
    AudioInputStream ais1 = AudioSystem.getAudioInputStream(file1);
    AudioInputStream aisTarget1 = AudioSystem.getAudioInputStream(f, ais1);

    File file2 = new File("C:\\Blackout3.au");
    AudioInputStream ais2 = AudioSystem.getAudioInputStream(file2);
    AudioInputStream aisTarget2 = AudioSystem.getAudioInputStream(f, ais2);

    byte[] data = new byte[10000];
    int[] calc = new int[5000];
    AudioInputStream[] streams = {aisTarget1, aisTarget2};
    int count = streams.length + 1;
    while (true) {
        int r = -1;
        for (int i = 0; i < streams.length; i++) {
            r = streams[i].read(data, 0, data.length);
            if (r == -1) break;
            for (int j = 0; j < calc.length; j++) {
                int tempVal = ((data[j * 2 + 1] << 8) | (data[j * 2] & 0xFF));
                calc[j] += tempVal;
            }
        }
        for (int i = 0; i < calc.length; i++) {
            calc[i] /= count;
            data[i * 2 + 0] = (byte) (calc[i] & 0xFF);
            data[i * 2 + 1] = (byte) (calc[i] >> 8);
        }
        if (r == -1) break;
        sdl.write(data, 0, data.length);
    }

[/code]

If its not possible to mix the ulaw samples directly and I have to convert to PCM, how do I convert from PCM Format (AudioFormat.Encoding.PCM_SIGNED, 8000 Hz, 16bits, 1 channel, 2 byte framesize, 8000 frame rate, little endian) to ULAW (8bit 8000Hz).

Do I do something like: 1) Write a WAVE header to a Byte stream 2) Write the PCM data to the byte stream 3) Get PCM AIS with AudioSystem.getAudioInputStream(byte stream) 4) Get ULAW Target AIS with AudioSystem.getAudioInputStream(ulawFormat, PCM AIS)

Any help is appreciated.

EDIT: Trying to convert from Mu-LAW to PCM (Trying to use equation from http://en.wikipedia.org/wiki/Ulaw):

[CODE]

    AudioFormat f = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 8000, 8, 1, 1, 8000, false);
    SourceDataLine sdl = AudioSystem.getSourceDataLine(f);
    sdl.open(f);
    sdl.start();
    File file1 = new File("C:\\scream3.au");
    FileInputStream fis = new FileInputStream(file1);
    // Skip header
    fis.skip(24);
    byte[] data = new byte[8196];

    while (true) {
        int r = fis.read(data, 0, data.length);
        if (r == -1) break;
        for (int i = 0; i < r; i++) {
            float y = ((float) data[i] / Byte.MAX_VALUE);
            float sample = -1.0f * (float) (Math.signum(y) * (1.0f / 255.0f) * (Math.pow(1 + 255, Math.abs(y)) - 1.0f));
            data[i] = (byte) (sample * Byte.MAX_VALUE);
        }
        sdl.write(data, 0, data.length);
    }
    sdl.drain();
    sdl.stop();
    sdl.close();
    fis.close();

[/CODE]

+1  A: 

I would convert from/to linear encoding by hand, one sample at a time, using the formulas from Wikipedia:μ-law algorithm.

Example code (based on OP's code):

float sample1 = Math.signum(y1)/255.0*(Math.pow(256, Math.abs(y1))-1);
float sample2 = Math.signum(y2)/255.0*(Math.pow(256, Math.abs(y2))-1);
float combined = somethig * sample1 + (1-something) * sample2;
float result = Math.signum(combined)*Math.log(1+255*Math.abs(combined))/Math.log(256);
Edgar Bonet
Thanks for the reply! Im trying to do this, unfortunately I'm not that good at maths. Can you help me out?
Xiphias3
How is this not the same as converting to PCM and back?
Gabe
@Gabe: It _is_ the same. I just mean that you do not need to write headers, use byte streams and so on.
Edgar Bonet
@Xiphias3: I added an example, based on your own code.
Edgar Bonet
@Edgar Bonet: Thanks for your help.
Xiphias3