我正在使用音频单元进行一些自定义音频后期处理。我有两个文件正在合并(下面的链接),但是在输出中出现了一些奇怪的噪音。我做错了什么?
我已经确认在此步骤之前,2个文件(workTrack1
和workTrack2
)处于正常状态并且听起来不错。此过程中也没有出现任何错误。
缓冲区处理代码:
- (BOOL)mixBuffersWithBuffer1:(const int16_t *)buffer1 buffer2:(const int16_t *)buffer2 outBuffer:(int16_t *)mixbuffer outBufferNumSamples:(int)mixbufferNumSamples {
BOOL clipping = NO;
for (int i = 0 ; i < mixbufferNumSamples; i++) {
int32_t s1 = buffer1[i];
int32_t s2 = buffer2[i];
int32_t mixed = s1 + s2;
if ((mixed < -32768) || (mixed > 32767)) {
clipping = YES; // don't break here because we dont want to lose data, only to warn the user
}
mixbuffer[i] = (int16_t) mixed;
}
return clipping;
}
混合代码:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////// PHASE 4 ////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// In phase 4, open workTrack1 and workTrack2 for reading,
// mix together, and write out to outfile.
// open the outfile for writing -- this will erase the infile if they are the same, but its ok cause we are done with it
err = [self openExtAudioFileForWriting:outPath audioFileRefPtr:&outputAudioFileRef numChannels:numChannels];
if (err) { [self cleanupInBuffer1:inBuffer1 inBuffer2:inBuffer2 outBuffer:outBuffer err:err]; return NO; }
// setup vars
framesRead = 0;
totalFrames = [self totalFrames:mixAudioFile1Ref]; // the long one.
NSLog(@"Mix-down phase, %d frames (%0.2f secs)", totalFrames, totalFrames / RECORD_SAMPLES_PER_SECOND);
moreToProcess = YES;
while (moreToProcess) {
conversionBuffer1.mBuffers[0].mDataByteSize = LOOPER_BUFFER_SIZE;
conversionBuffer2.mBuffers[0].mDataByteSize = LOOPER_BUFFER_SIZE;
UInt32 frameCount1 = framesInBuffer;
UInt32 frameCount2 = framesInBuffer;
// Read a buffer of input samples up to AND INCLUDING totalFrames
int numFramesRemaining = totalFrames - framesRead; // Todo see if we are off by 1 here. Might have to add 1
if (numFramesRemaining == 0) {
moreToProcess = NO; // If no frames are to be read, then this phase is finished
} else {
if (numFramesRemaining < frameCount1) { // see if we are near the end
frameCount1 = numFramesRemaining;
frameCount2 = numFramesRemaining;
conversionBuffer1.mBuffers[0].mDataByteSize = (frameCount1 * bytesPerFrame);
conversionBuffer2.mBuffers[0].mDataByteSize = (frameCount2 * bytesPerFrame);
}
NSbugLog(@"Attempting to read %d frames from mixAudioFile1Ref", (int)frameCount1);
err = ExtAudioFileRead(mixAudioFile1Ref, &frameCount1, &conversionBuffer1);
if (err) { [self cleanupInBuffer1:inBuffer1 inBuffer2:inBuffer2 outBuffer:outBuffer err:err]; return NO; }
NSLog(@"Attempting to read %d frames from mixAudioFile2Ref", (int)frameCount2);
err = ExtAudioFileRead(mixAudioFile2Ref, &frameCount2, &conversionBuffer2);
if (err) { [self cleanupInBuffer1:inBuffer1 inBuffer2:inBuffer2 outBuffer:outBuffer err:err]; return NO; }
NSLog(@"Read %d frames from mixAudioFile1Ref in mix-down phase", (int)frameCount1);
NSLog(@"Read %d frames from mixAudioFile2Ref in mix-down phase", (int)frameCount2);
// If no frames were returned, phase is finished
if (frameCount1 == 0) {
moreToProcess = NO;
} else { // Process pcm data
// if buffer2 was not filled, fill with zeros
if (frameCount2 < frameCount1) {
bzero(inBuffer2 + frameCount2, (frameCount1 - frameCount2));
frameCount2 = frameCount1;
}
const int numSamples = (frameCount1 * bytesPerFrame) / sizeof(int16_t);
if ([self mixBuffersWithBuffer1:(const int16_t *)inBuffer1
buffer2:(const int16_t *)inBuffer2
outBuffer:(int16_t *)outBuffer
outBufferNumSamples:numSamples]) {
NSLog(@"Clipping");
}
// Write pcm data to the main output file
conversionOutBuffer.mBuffers[0].mDataByteSize = (frameCount1 * bytesPerFrame);
err = ExtAudioFileWrite(outputAudioFileRef, frameCount1, &conversionOutBuffer);
framesRead += frameCount1;
} // frame count
} // else
if (err) {
moreToProcess = NO;
}
} // while moreToProcess
// Check for errors
TTDASSERT(framesRead == totalFrames);
if (err) {
if (error) *error = [NSError errorWithDomain:kUAAudioSelfCrossFaderErrorDomain
code:UAAudioSelfCrossFaderErrorTypeMixDown
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:err],@"Underlying Error Code",[self commonExtAudioResultCode:err],@"Underlying Error Name",nil]];
[self cleanupInBuffer1:inBuffer1 inBuffer2:inBuffer2 outBuffer:outBuffer err:err];
return NO;
}
NSLog(@"Done with mix-down phase");
的的假设
mixAudioFile1Ref
总是超过mixAudioFile2Ref
mixAudioFile2Ref
用完字节后,outputAudioFileRef
听起来与mixAudioFile2Ref
完全相同当轨道循环时,预期的声音应该是在淡入淡出时混合淡入淡出以产生自交叉渐变。请听输出,查看代码并告诉我出错的地方。
音源声音:http://cl.ly/2g2F2A3k1r3S36210V23
产生的音调:http://cl.ly/3q2w3S3Y0x0M3i2a1W3v
答案 0 :(得分:1)
原来这里有两个问题。
缓冲区处理代码
int32_t mixed = s1 + s2;
导致裁剪。更好的方法是除以混合的通道数:int32_t mixed = (s1 + s2)/2;
然后在另一通道中标准化。
帧!=字节 当声音用完时将第二个音轨的缓冲区清零时,我错误地将偏移和持续时间设置为帧而不是字节。这会在缓冲区中产生垃圾并产生您定期听到的噪音。易于修复:
if (frameCount2 < frameCount1) {
bzero(inBuffer2 + (frameCount2 * bytesPerFrame), (frameCount1 - frameCount2) * bytesPerFrame);
frameCount2 = frameCount1;
}
答案 1 :(得分:0)
您发布的答案看起来不错;我只能看到一个小问题。你的削波解决方案除以2将有所帮助,但它也相当于应用50%的增益减少。这与不与规范化相同; normalization是查看整个音频文件,找到最高峰值并应用给定增益减少以使此峰值达到一定水平(通常为0.0dB)的过程。结果是在正常(即非削波)情况下,输出信号将非常低并需要再次提升。
在混音期间,毫无疑问会遇到导致失真的溢出,因为该值会环绕并导致信号跳跃。你想要做的是应用一种称为“brick-wall limiter”的技术,它基本上对剪切的样本应用硬顶。最简单的方法是:
int32_t mixed = s1 + s2;
if(mixed >= 32767) {
mixed = 32767;
}
else if(mixed <= -32767) {
mixed = -32767;
}
这种技术的结果是你会听到裁剪样本周围的一些失真,但声音不会像整数溢出一样完全被破坏。失真虽然存在,但不会破坏听力体验。