gpt4 book ai didi

ios - ExtAudioFileWrite 创建静音 m4a

转载 作者:行者123 更新时间:2023-11-29 01:54:31 26 4
gpt4 key购买 nike

我正在制作一款应用程序,需要将不同数量的音频文件合并为一个。为了实现这一点,我使用多 channel 混音器音频单元。混音器成功地混合了音轨,并且,如果我将 AUGraph 中的 I/O 单元设置为 RemoteIO,它就会成功播放声音。

但是,我想将新声音保存到文件中;我认为最好的方法是使用通用输出而不是 RemoteIO。文件已成功写入并且长度正确(以秒为单位),但播放时没有声音。这是我创建 AUGraph 的方法(为了简洁起见,我将删除尽可能多的内容)

- (void)createGraph
{
OSStatus result = NewAUGraph(&graph);

AudioComponentDescription mixerDescription;
mixerDescription.componentType = kAudioUnitType_Mixer;
mixerDescription.componentSubType = kAudioUnitSubType_MultiChannelMixer;
mixerDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
mixerDescription.componentFlags = 0;
mixerDescription.componentFlagsMask = 0;

AudioComponentDescription remoteIODescription;
remoteIODescription.componentType = kAudioUnitType_Output;
remoteIODescription.componentSubType = kAudioUnitSubType_GenericOutput;
remoteIODescription.componentManufacturer = kAudioUnitManufacturer_Apple;
remoteIODescription.componentFlags = 0;
remoteIODescription.componentFlagsMask = 0;

AUNode iONode, mixerNode;

result = AUGraphAddNode(graph, &remoteIODescription, &iONode);
result = AUGraphAddNode(graph, &mixerDescription, &mixerNode);
result = AUGraphOpen(graph);
result = AUGraphNodeInfo(graph, mixerNode, NULL, &mixerUnit);
result = AUGraphNodeInfo(graph, iONode, NULL, &iOUnit);
result = AUGraphConnectNodeInput(graph, mixerNode, 0, iONode, 0);

UInt32 busCount = (UInt32)fileCount;

result = AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, sizeof(busCount));

UInt32 maximumFramesPerSlice = 4096;

result = AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maximumFramesPerSlice, sizeof(maximumFramesPerSlice));

for (UInt16 busNumber = 0; busNumber < busCount; busNumber++)
{
AURenderCallbackStruct renderCallback;
renderCallback.inputProc = &inputRenderCallback;
renderCallback.inputProcRefCon = (__bridge void *)self;

result = AUGraphSetNodeInputCallback(graph, mixerNode, busNumber, &renderCallback);

//sets certain parameters for the mixer; I don't believe this is the cause of the problem
AudioUnitSetParameter(mixerUnit, kMultiChannelMixerParam_Pan, kAudioUnitScope_Input, busNumber, fileSettings[busNumber].pan, 0);
AudioUnitSetParameter(mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, busNumber, fileSettings[busNumber].volume, 0);
AudioUnitSetParameter(mixerUnit, kMultiChannelMixerParam_Enable, kAudioUnitScope_Input, busNumber, fileSettings[busNumber].enabled, 0);

if (soundStructs[busNumber].isStereo == YES)
{
result = AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, busNumber, &stereoDescription, sizeof(stereoDescription));
}
else
{
result = AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, busNumber, &monoDescription, sizeof(monoDescription));
}
}

Float64 sampleRate = SAMPLE_RATE; // 44100.0
result = AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, sizeof(sampleRate));

CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:ofn];

AudioStreamBasicDescription destinationFormat;
memset(&destinationFormat, 0, sizeof(destinationFormat));
destinationFormat.mChannelsPerFrame = 2;
destinationFormat.mFormatID = kAudioFormatMPEG4AAC;
destinationFormat.mFormatFlags = kMPEG4Object_AAC_Main;
destinationFormat.mSampleRate = sampleRate;

UInt32 size = sizeof(destinationFormat);
result = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &destinationFormat);

result = ExtAudioFileCreateWithURL(url, kAudioFileM4AType, &destinationFormat, NULL, kAudioFileFlags_EraseFile, &outputFile);

AudioStreamBasicDescription clientFormat;
memset(&clientFormat, 0, sizeof(clientFormat));

size = sizeof(clientFormat);
result = AudioUnitGetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, & clientFormat, &size);

UInt32 codec = kAppleHardwareAudioCodecManufacturer;
ExtAudioFileSetProperty(outputFile, kExtAudioFileProperty_CodecManufacturer, sizeof(codec), &codec);

ExtAudioFileSetProperty(outputFile, kExtAudioFileProperty_ClientDataFormat, sizeof(clientFormat), &clientFormat);

result = AUGraphInitialize(graph);
}

这就是我保存文件的方式

- (void)startGraph
{
AudioUnitRenderActionFlags flags = 0;
AudioTimeStamp inTimeStamp;
memset(&inTimeStamp, 0, sizeof(AudioTimeStamp));
inTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
UInt32 busNumber = 0;
UInt32 numberFrames = 1024;
inTimeStamp.mSampleTime = 0;
int channelCount = 2;
SInt64 totFrms = 0;

for (int i = 0; i < fileCount; i++) //gets the length for the longest recording in the new track
{
SInt64 len = soundStructs[i].totalFrames;
if (len > totFrms && fileSettings[i].enabled == YES)
totFrms = len;
}
while (totFrms > 0)
{
if (totFrms < numberFrames)
numberFrames = (UInt32)totFrms;
else
totFrms -= numberFrames;
AudioBufferList *bufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList)+sizeof(AudioBuffer)*(channelCount-1));
bufferList->mNumberBuffers = channelCount;
for (int j=0; j<channelCount; j++)
{
AudioBuffer buffer = {0};
buffer.mNumberChannels = 1;
buffer.mDataByteSize = numberFrames*sizeof(SInt32);
buffer.mData = calloc(numberFrames, sizeof(SInt32));

bufferList->mBuffers[j] = buffer;
}
AudioUnitRender(iOUnit, &flags, &inTimeStamp, busNumber, numberFrames, bufferList);

OSStatus res = ExtAudioFileWrite(outputFile, numberFrames, bufferList);
NSAssert(res == noErr, @"Res != noerr");
}

ExtAudioFileDispose(outputFile);
}

因为问题已经很长了,所以我不会添加混合器用于输入的回调函数或用于将文件加载到内存的方法,因为 RemoteIO 工作的事实让我相信没有任何问题用这些。那么,为什么我的图表创建的输出文件是静默的?

最佳答案

调用 AudioUnitRender 后,您需要为下一次迭代增加时间戳的采样时间。

AudioUnitRender(iOUnit, &flags, &inTimeStamp, busNumber, numberFrames, bufferList);
inTimeStamp.mSampleTime += numberFrames;

关于ios - ExtAudioFileWrite 创建静音 m4a,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31031473/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com