Как использовать Superpowered TimeStretching в реальном времени в AUInternalRenderBlock - PullRequest
0 голосов
/ 19 сентября 2018

Я пытаюсь использовать SuperpoweredTimeStretching в блоке рендеринга AU.Например на одном канале для простого кода.

В данный момент я не изменяю скорость звука (поэтому мне не нужно использовать «кольцевой буфер» или что-то в этом роде - количество входных и выходных выборок в буферах фиксировано).Но у меня очень странная ситуация.Этот мой код работает хорошо, но если я не изменю тональность!

Если я не меняю высоту тона - у меня есть один срез (1024 семпла).Но если я изменю параметр высоты тона - у меня будет два среза (512 сэмплов каждый). Это кажется абсолютно нормальным (я реализовал итератор).Но когда срезов будет больше одного (два 512, а не один 1024) - это звучит с артефактами.

Я не понимаю, что я делаю неправильно.

- (AUInternalRenderBlock)internalRenderBlock {

AudioBufferList *renderABLCapture = &renderABL;

SuperpoweredTimeStretching *timeStretch = new SuperpoweredTimeStretching(48000);

//If I change pitch it sounds very "ugly" with artefacts. If nothig to change - everything is ok.
timeStretch->setRateAndPitchShift(1.0f, 1); // Speed is fixed. Only pitch changed.

// This buffer list will receive the time-stretched samples.
SuperpoweredAudiopointerList *outputBuffers = new SuperpoweredAudiopointerList(8, 16);


return ^AUAudioUnitStatus(AudioUnitRenderActionFlags    *actionFlags,
                          const AudioTimeStamp        *timestamp,
                          AVAudioFrameCount            frameCount,
                          NSInteger                outputBusNumber,
                          AudioBufferList            *outputBufferListPtr,
                          const AURenderEvent        *realtimeEventListHead,
                          AURenderPullInputBlock        pullInputBlock ) {

    int numBuffers = outputBufferListPtr->mNumberBuffers;

    pullInputBlock(actionFlags, timestamp, frameCount, 0, renderABLCapture);

    Float32 *sampleDataOutLeft  = (Float32*)outputBufferListPtr->mBuffers[0].mData;
    Float32 *sampleDataOutRight = (Float32*)outputBufferListPtr->mBuffers[1].mData;


    size_t sampleSize = sizeof(Float32);
    //***********

    SuperpoweredAudiobufferlistElement inputBuffer;
    inputBuffer.samplePosition = 0;
    inputBuffer.startSample = 0;
    inputBuffer.samplesUsed = 0;
    inputBuffer.endSample = frameCount; //
    inputBuffer.buffers[0] = SuperpoweredAudiobufferPool::getBuffer(frameCount * 18 + 64);
    inputBuffer.buffers[1] = inputBuffer.buffers[2] = inputBuffer.buffers[3] = NULL;


    //Input sample data to inputBuffer for timeStretch

    memcpy((float*)inputBuffer.buffers[0], renderABLCapture->mBuffers[0].mData, sampleSize * frameCount);

    timeStretch->process(&inputBuffer, outputBuffers); //Process

    if (outputBuffers->makeSlice(0, outputBuffers->sampleLength)) {

        int count = 0;
        int numSamples = 0;

        while (true) { // Iterate on every output slice.

            //If I have more than one slice - it sounds very "ugly" with artefacts.

            // Get pointer to the output samples.
            float *timeStretchedAudio = (float *)outputBuffers->nextSliceItem(&numSamples);
            if (!timeStretchedAudio) break;

            for (int i = 0; i < numSamples; i++) {

                Float32 *sample = &timeStretchedAudio[i];
                sampleDataOutLeft[i + count] = *sample;

            }

            count += numSamples;

        };

        outputBuffers->clear();

    }

    return noErr;
};

}

1 Ответ

0 голосов
/ 21 сентября 2018

Моей проблемой была ошибка с чередованными каналами.

Это правильный код

return ^AUAudioUnitStatus(AudioUnitRenderActionFlags    *actionFlags,
                              const AudioTimeStamp      *timestamp,
                              AVAudioFrameCount         frameCount,
                              NSInteger             outputBusNumber,
                              AudioBufferList           *outputBufferListPtr,
                              const AURenderEvent       *realtimeEventListHead,
                              AURenderPullInputBlock        pullInputBlock ) {

        pullInputBlock(actionFlags, timestamp, frameCount, 0, renderABLCapture);

        Float32 *sampleDataInLeft = (Float32*) renderABLCapture->mBuffers[0].mData;
        Float32 *sampleDataInRight = (Float32*) renderABLCapture->mBuffers[1].mData;

        Float32 *sampleDataOutLeft  = (Float32*)outputBufferListPtr->mBuffers[0].mData;
        Float32 *sampleDataOutRight = (Float32*)outputBufferListPtr->mBuffers[1].mData;


        SuperpoweredAudiobufferlistElement inputBuffer;
        inputBuffer.samplePosition = 0;
        inputBuffer.startSample = 0;
        inputBuffer.samplesUsed = 0;
        inputBuffer.endSample = frameCount;
        inputBuffer.buffers[0] = SuperpoweredAudiobufferPool::getBuffer(frameCount * 8 + 64);
        inputBuffer.buffers[1] = inputBuffer.buffers[2] = inputBuffer.buffers[3] = NULL;

        SuperpoweredInterleave(sampleDataInLeft, sampleDataInRight, (Float32*)inputBuffer.buffers[0], frameCount);

        timeStretch->setRateAndPitchShift(1.0f, -2);
        timeStretch->setSampleRate(48000);
        timeStretch->process(&inputBuffer, outputBuffers);

        if (outputBuffers->makeSlice(0, outputBuffers->sampleLength)) {

            int numSamples = 0;
            int samplesOffset =0;

            while (true) {

                Float32 *timeStretchedAudio = (Float32 *)outputBuffers->nextSliceItem(&numSamples);
                if (!timeStretchedAudio) break;

                  SuperpoweredDeInterleave(timeStretchedAudio, sampleDataOutLeft + samplesOffset, sampleDataOutRight + samplesOffset, numSamples);

                samplesOffset += numSamples;

            };

            outputBuffers->clear();

        }

        return noErr;
    };
...