Generating sound on Android with OpenSL ES

611 Views Asked by At

I'm making audio app on Android and I have simple generation of three types of sound waves - Sine, Sawtooth and Square.

Generating of waves is fine. I printed out the result and it's looking good. But the sound is weird. Here is what I recorded. https://soundcloud.com/syntey/synth-sine-wave-test-nothing-to-do-here

It's same for sawtooth and square, but when I play with sawtooth any A, then sound is normal.

Does someone know what is wrong? If I increase size of buffer, then period is longer, but still the same problem

Code for generating sine wave:

play(JNIEnv* env, jclass clazz, jint which, jint count, jdouble freqOfTone)
{
    unsigned i;
    int j = 0;
    double sampleRate = SAMPLERATE/freqOfTone;
    switch (which) {
case SINE:
        for (i = 0; i < TONE_FRAMES; ++i) {
            toneBuffer[i] = sin(2.0*M_PI * i/sampleRate) * 32768;                
        }
        nextBuffer = createResampledBuf(SINE, SL_SAMPLINGRATE_8, &nextSize);
        if(!nextBuffer) {
            nextBuffer = (short*) toneBuffer;
            nextSize  = sizeof(toneBuffer);
        }
        break;
    }
    nextCount = count;
    if (nextSize > 0) {
        SLresult result;
        result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
        if (SL_RESULT_SUCCESS != result) {
            bqPlayerRecorderBusy = 1;
            return JNI_FALSE;
        }
    }

    return JNI_TRUE;
}
2

There are 2 best solutions below

4
On

You're not printing out anything while generating the wave?

But also the main problem is your synthesis loop. I'm going to guess the clicks you hear is because you're skipping samples (you increment i twice, in your for loop and in your synthesis block. It should be this to avoid the clicks:

for (i = 0; i < SIZE_OF_BUFFER; i++) {
        toneBuffer[i] = sin(2.0*M_PI * i/(44100/freqOfTone)) * 32768;
}

But I would recommend you work with phases, to me it just makes more sense in a signal processing process

float generateSineWave(float freq) {
    // Get phase, then get sample
    phase = 2 * M_PI * freq / 44100 + prev_phase;
    sample = sin(phase);

    // wrap phase
    if (phase > (2 * M_PI)) phase -= (2 * M_PI);

    prev_phase = phase

    return sample;
}

void yourSynthesisLoop() {
    for (int i = 0; i < SIZE_OF_BUFFER; i++) {
        toneBuffer[i] = generateSineWave(freqOfTone) * 32768;
    }
}
0
On

Try to use short data type instead of double from the core. OpenSLEL converts it to short anyways, hence there may be data loss or noise added. Also for good quality use higher sample rate.