2

我正在为各种实时 FX 使用 Superpowered,它们都非常简单。然而,音高变化是另一回事,我认为事实上因为它基于时间拉伸算法,当然必须处理随时间变化的输出,这比应用 EQ 或混响等 FX 复杂得多。但是我只对改变我的麦克风输入的音高感兴趣。

我查看了在 GitHub 上可以找到的唯一示例,并对其进行了微调以适合我的工作:

static bool audioProcessing(void *clientdata,
                            float **buffers,
                            unsigned int inputChannels,
                            unsigned int outputChannels,
                            unsigned int numberOfSamples,
                            unsigned int samplerate,
                            uint64_t hostTime) {
    __unsafe_unretained Superpowered *self = (__bridge Superpowered *)clientdata;

    SuperpoweredAudiobufferlistElement inputBuffer;

    inputBuffer.startSample = 0;
    inputBuffer.samplesUsed = 0;
    inputBuffer.endSample = self->timeStretcher->numberOfInputSamplesNeeded;
    inputBuffer.buffers[0] = SuperpoweredAudiobufferPool::getBuffer(self->timeStretcher->numberOfInputSamplesNeeded * 8 + 64);
    inputBuffer.buffers[1] = inputBuffer.buffers[2] = inputBuffer.buffers[3] = NULL;

    self->outputBuffers->clear();
    self->timeStretcher->process(&inputBuffer, self->outputBuffers);
    int samples = self->timeStretcher->numberOfInputSamplesNeeded;
    float *timeStretchedAudio = (float *)self->outputBuffers->nextSliceItem(&samples);
    if (timeStretchedAudio != 0) {
        SuperpoweredDeInterleave(timeStretchedAudio, buffers[0], buffers[1], numberOfSamples);
    }

    //self->outputBuffers->rewindSlice();

    return true;
}

我已经删除了大部分我认为没有必要的代码。例如,有一个似乎处理时间拉伸场景的 while 循环,我只是输出与输入相同的时间。

一些观察:

  • 如果我不这样做clearoutputBuffers我的内存使用量就会飙升
  • 如果我使用self->outputBuffers->rewindSlice();该应用程序变得静音,可能意味着缓冲区被静音覆盖
  • 如果我不使用self->outputBuffers->rewindSlice();,我可以听到自己的声音回来,但timeStretchedAudio总是0第一次除外
4

2 回答 2

1

我终于让它工作了:

static bool audioProcessing(void *clientdata,
                                float **buffers,
                                unsigned int inputChannels,
                                unsigned int outputChannels,
                                unsigned int numberOfSamples,
                                unsigned int samplerate,
                                uint64_t hostTime) {
    __unsafe_unretained Superpowered *self = (__bridge Superpowered *)clientdata;

    //timeStretching->setRateAndPitchShift(realTimeRate, realTimePitch);
    SuperpoweredAudiobufferlistElement inputBuffer;
    inputBuffer.startSample = 0;
    inputBuffer.samplesUsed = 0;
    inputBuffer.endSample = numberOfSamples;
    inputBuffer.buffers[0] = SuperpoweredAudiobufferPool::getBuffer((unsigned int) (numberOfSamples * 8 + 64));
    inputBuffer.buffers[1] = inputBuffer.buffers[2] = inputBuffer.buffers[3] = NULL;

    // Converting the 16-bit integer samples to 32-bit floating point.
    SuperpoweredInterleave(buffers[0], buffers[1], (float *)inputBuffer.buffers[0], numberOfSamples);
    //SuperpoweredShortIntToFloat(audioInputOutput, (float *)inputBuffer.buffers[0], (unsigned int) numberOfSamples);

    self->timeStretcher->process(&inputBuffer, self->outputBuffers);

    // Do we have some output?
    if (self->outputBuffers->makeSlice(0, self->outputBuffers->sampleLength)) {
        while (true) { // Iterate on every output slice.
            // Get pointer to the output samples.
            int numSamples = 0;
            float *timeStretchedAudio = (float *)self->outputBuffers->nextSliceItem(&numSamples);
            if (!timeStretchedAudio || *timeStretchedAudio == 0) {
                break;
            }

            // Convert the time stretched PCM samples from 32-bit floating point to 16-bit integer.
            //SuperpoweredFloatToShortInt(timeStretchedAudio, audioInputOutput,
            //                            (unsigned int) numSamples);
            SuperpoweredDeInterleave(timeStretchedAudio, buffers[0], buffers[1], numSamples);
            self->recorder->process(timeStretchedAudio, numSamples);

            // Write the audio to disk.
            //fwrite(audioInputOutput, 1, numSamples * 4, fd);
        }
        // Clear the output buffer list.
        self->outputBuffers->clear();
        // If we have enough samples in the fifo output buffer, pass them to the audio output.
        //SuperpoweredFloatToShortInt((float *)inputBuffer.buffers[0], audioInputOutput, (unsigned int) numberOfSamples);
    }

    return true;
}

我不确定更改费率是否也有效,但我不关心这个应用程序。YMMV。

于 2017-11-14T19:43:44.680 回答
0

实现标有 TODO 的部分。这就是您需要为 timeStretcher 提供输入的地方。还要注意将输出与输入分开。输出可以在输入被消耗之前被写入。

于 2017-10-23T18:50:04.537 回答