如何在iOS上跳过音频缓冲区中的样本

如何在iOS上跳过音频缓冲区中的样本,ios,audio,Ios,Audio,我正在尝试跳过或缩短iOS上音频播放的静音。使用RemoteIO,我将使用以下代码片段作为消除静默的逻辑。但是,它不能正常工作。基于代码,我希望从样本中删除静音,并使音频至少播放得更快(因为样本将被删除)。然而,我偶尔会听到奇怪的砰砰声/咔哒声,而且音频时间是一样的(没有任何东西会向前跳过,就好像沉默被消除了一样) 知道我做错了什么吗?这是错误的做法吗 // original samples are stored in renderBufferList // loop through the s

我正在尝试跳过或缩短iOS上音频播放的静音。使用RemoteIO,我将使用以下代码片段作为消除静默的逻辑。但是,它不能正常工作。基于代码,我希望从
样本中删除静音,并使音频至少播放得更快(因为样本将被删除)。然而,我偶尔会听到奇怪的砰砰声/咔哒声,而且音频时间是一样的(没有任何东西会向前跳过,就好像沉默被消除了一样)

知道我做错了什么吗?这是错误的做法吗

// original samples are stored in renderBufferList
// loop through the samples and replace anything less than amplitudeThreshold 
// with the next "non-silent" sample

SInt16 *samples = renderBufferList->mBuffers[0].mData;
int sampleCount = renderBufferList->mBuffers[0].mDataByteSize / sizeof(SInt16);
int currentSampleIndex = 0;
int amplitudeThreshold = 15;
int channels = 2;
for (int i = 0; i < sampleCount; i+=channels) {
    SInt16 sampleL = samples[i];
    SInt16 sampleR = samples[i+1];
    // check if amplitude of sample is > amplitudeThreshold
    if (abs(sampleL) > amplitudeThreshold || abs(sampleR) > amplitudeThreshold) {
        // set samples and increase to next sample set
        samples[currentSampleIndex] = sampleL;
        samples[currentSampleIndex+1] = sampleR;
        currentSampleIndex+=channels;
    }
}

// how many bytes should be in non-amplitudeThreshold samples
int bytesToCopy = currentSampleIndex * sizeof(SInt16);

if (bytesToCopy > 0) {
    // store samples in circular buffer
    TPCircularBufferProduceBytes(&circularBuffer, samples, bytesToCopy);
} else {
    // set buffer to silence
    memset((SInt16*)inIoData->mBuffers[0].mData, 0, bytesToCopy);
    return noErr;
}

int outputDataByteSize = inIoData->mBuffers[0].mDataByteSize;
SInt16 *outputBuffer = (SInt16*)inIoData->mBuffers[0].mData;

// if circularBuffer is filled more than outputDataByteSize * 10 (large buffer)
if (circularBuffer.fillCount > outputDataByteSize * 10) {

    int32_t availableBytes;
    SInt16 *buffer = TPCircularBufferTail(&circularBuffer, &availableBytes);
    if(buffer == NULL) {
        NSLog(@"circular buffer is empty. end of track.");
        return noErr;
    }

    int numBytes = MIN(bytesToCopy, availableBytes);
    memcpy(outputBuffer, buffer, numBytes);

    // consume (remove) bytes from circular buffer that are being copied to output buffer
    TPCircularBufferConsume(&circularBuffer, numBytes);
}
else {
    NSLog(@"buffering");
    memset(targetBuffer, 0, outputDataByteSize);
    return noErr;
}
//原始样本存储在renderBufferList中
//循环检查样本,并替换任何小于AmplicateThreshold的内容
//使用下一个“非静默”示例
SInt16*samples=renderBufferList->mBuffers[0].mData;
int sampleCount=renderBufferList->mbuffer[0].mDataByteSize/sizeof(SInt16);
int currentSampleIndex=0;
int-amplitethreshold=15;
int通道=2;
对于(int i=0;i振幅Threshold
if(abs(采样)>AmplicateThreshold | | abs(采样器)>AmplicateThreshold){
//设置样本并增加到下一个样本集
样本[currentSampleIndex]=样本;
样本[currentSampleIndex+1]=采样器;
currentSampleIndex+=通道;
}
}
//非AmplicateThreshold示例中应包含多少字节
int bytesToCopy=currentSampleIndex*sizeof(SInt16);
如果(bytesToCopy>0){
//将样本存储在循环缓冲区中
TPCircularBufferProduceBytes(&circularBuffer,samples,bytesToCopy);
}否则{
//将缓冲区设置为静默
memset((SInt16*)在iodata->mBuffers[0].mData,0,bytesToCopy);
返回noErr;
}
int outputDataByteSize=inIoData->mBuffers[0].mDataByteSize;
SInt16*outputBuffer=(SInt16*)inodata->mbuffer[0].mData;
//如果circularBuffer的填充量大于outputDataByteSize*10(大缓冲区)
if(circularBuffer.fillCount>outputDataByteSize*10){
int32_t可用字节;
SInt16*buffer=TPCircularBufferTail(&circularBuffer,&availableBytes);
if(buffer==NULL){
NSLog(@“循环缓冲区为空。轨道结束。”);
返回noErr;
}
int numBytes=MIN(bytesToCopy,可用字节);
memcpy(输出缓冲区,缓冲区,单位);
//使用(删除)循环缓冲区中要复制到输出缓冲区的字节
tpcircularbuffer消耗量(&circularBuffer,numBytes);
}
否则{
NSLog(“缓冲”);
memset(targetBuffer,0,outputDataByteSize);
返回noErr;
}

查看静默检测逻辑(我不是IOS/swift程序员),似乎您是在逐个示例的基础上定义静默。这不是音频的工作方式,基本上你所要做的就是切割波形中低于amplitudeThreshold的部分-导致咔嗒声,并且,由于波形的上部仍然存在,静音/低振幅数据仍然存在(尽管损坏)

我建议计算一帧音频的振幅,即一些样本的子集,而不是硬切为0,加入一个线性渐变向上/向下,以消除咔嗒声


还有一点,你的样品是什么格式的-1:1 PCM?如果您还没有这样做,那么根据分贝而不是原始数据检测静音也是值得的。

样本是LPCM。检测/跳过样本的逻辑现在似乎起作用了(尽管可能更好?)。我偶尔会听到咔嗒声/砰砰声,这似乎是由于循环缓冲区不够大,因此音频停止得太频繁(导致咔嗒声),而缓冲区的容量足以播放。增加缓冲区大小似乎可以解决这个问题。我还得再测试一下,但现在看来可能还可以。在iOS上,我的理解是单声道1帧=1个采样,立体声1帧是2个采样。所以在我的例子中,我相信我已经在使用帧了,对吗?