首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ExtAudioFileWrite创建静默m4a

ExtAudioFileWrite创建静默m4a
EN

Stack Overflow用户
提问于 2015-06-24 16:02:44
回答 1查看 222关注 0票数 0

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

但是,我想将新声音保存到一个文件中;我认为最好的方法是使用泛型输出而不是RemoteIO。该文件已成功写入,并且是正确的长度(以秒为单位),但在播放时是无声的。下面是我如何创建AUGraph的方法(为了简洁起见,我将尽可能删除)

代码语言:javascript
复制
- (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);
}

我就是这样保存文件的

代码语言:javascript
复制
- (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工作的事实使我相信这些函数没有什么问题。那么,为什么输出文件是由我的图形无声创建的呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-06-24 17:20:10

在调用AudioUnitRender之后,需要为下一次迭代增加时间戳的示例时间。

代码语言:javascript
复制
AudioUnitRender(iOUnit, &flags, &inTimeStamp, busNumber, numberFrames, bufferList);
inTimeStamp.mSampleTime += numberFrames;
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31031473

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档