Search code examples
cloopsaudioopensllibsndfile

Sound recorded is slower that the original one


I'm trying to implement a loop feature. Basically I save the music sample in a buffer. Then when I press the loop in button I set the initial loop in time, when press the loop out set the loop out time. To get the loop part i make loop out time - loop in time, that gives me the seconds of loop. Then I multiply the seconds * sample rate (44100), allocate a new buffer with that size and fill it with sound data. Everything works good but when I listen to the loop buffer via Open SL ES the sound is slower than the original one. I really don't know why...

SLmillisecond loopInPosition, loopOutPosition;
float loopDuration;
const char *lastPath;
short *sampleBuffer, *loopBuffer;
int xSampleBufferSize, xLoopBuffersize;

void playBuffer();

// get the position in the music sample when loop in or out button is pressed
SLmillisecond getCurrentPosition(jint playerIndex, SLmillisecond* whereToSave) {

    Player player = players[playerIndex];
    if (player.isReady == 1) {
        (*(player.playerPlayItf))->GetPosition(player.playerPlayItf,
                whereToSave);

        __android_log_print(ANDROID_LOG_DEBUG, "jajaja",
                ">>NATIVE position is: %d", *whereToSave);
    }
}

void loopIn(JNIEnv* env,
        jclass clazz, jint selectedSlot, jstring filename) {

    lastPath = (*env)->GetStringUTFChars(env, filename, NULL);
    assert(NULL != path);

    getCurrentPosition(selectedSlot, &loopInPosition);
}

void loopOut(JNIEnv* env,
        jclass clazz, jint selectedSlot) {

    getCurrentPosition(selectedSlot, &loopOutPosition);

    loopDuration = (float) ((float) (loopOutPosition - loopInPosition) / 1000);

    __android_log_print(ANDROID_LOG_DEBUG, "jajaja",
            ">>NATIVE loop duration is: %f", loopDuration);

    SF_INFO sndInfo;
    SNDFILE *sndFile = sf_open(lastPath, SFM_READ, &sndInfo);

    if (sndInfo.format != (SF_FORMAT_WAV | SF_FORMAT_PCM_16)) {
        fprintf(stderr, "Input should be 16bit Wav\n");
        sf_close(sndFile);
    } else {

        __android_log_print(ANDROID_LOG_DEBUG, "jajaja",
                ">>NATIVE File info samplerate %d, channels %d, format %d, sections %d, seekable %d",
                sndInfo.samplerate, sndInfo.channels, sndInfo.format,
                sndInfo.sections, sndInfo.seekable);
    }

    // Sample Buffer
    int sampleBufferSize = sndInfo.frames * sizeof(short);
    xSampleBufferSize = sampleBufferSize;
    sampleBuffer = malloc(sampleBufferSize);


    __android_log_print(ANDROID_LOG_DEBUG, "jajaja",
            ">>NATIVE allocated sample buffer: size %d, frames %d",
            sampleBufferSize, sndInfo.frames);

    sf_readf_short(sndFile, sampleBuffer, sndInfo.frames);

    // Loop Buffer
    int loopBufferSize = loopDuration * 44100 * sizeof(short);
    int loopBufferFrames = loopDuration * 44100;
    xLoopBuffersize = loopBufferSize;
    loopBuffer = malloc(loopBufferSize);

    __android_log_print(ANDROID_LOG_DEBUG, "jajaja",
            ">>NATIVE allocated loop buffer: size %d, frames %d",
            loopBufferSize, loopBufferFrames);

    int index, i = 0;
    int startIndex = (int) ((float) (loopInPosition / 1000) * 44100);

    __android_log_print(ANDROID_LOG_DEBUG, "jajaja",
            ">>NATIVE start index is %d", startIndex);

    for (index = startIndex, i = 0; index < startIndex + loopBufferFrames;
            ++index, ++i) {

        loopBuffer[i] = sampleBuffer[index];
    }
}

thanks for your time


Solution

  • What seems to be happening is that you're dealing with an interleaved stereo data. This means that both channels are stored as one contiguous block: a sample for the first channel, a sample for the second channel, a sample for the first channel again and so on.

    But, your buffer is played as mono, so when it's being played it thinks every sample intended for the second channel is intended for the first (and only) channel. This creates duplicate samples, making it sound slower.

    When you're doing loopBuffer[i] = sampleBuffer[index * 2], you're actually skipping every sample intended for the first channel, copying only the samples intended for the second channel.

    You may want to configure your audio player to interpret your buffer as interleaved stereo data.