使用 iOS 的 ExtAudioFileWrite 将音频样本缓冲区写入 aac 文件

2023-11-22

更新:我已经弄清楚了这一点并发布了我的解决方案作为我自己的问题的答案(如下)

我正在尝试使用 AAC 格式的 ExtAudioFileWrite 将简单的音频样本缓冲区写入文件。

我已经通过下面的代码实现了这一点,将单声道缓冲区写入 .wav 文件 - 但是,我无法对立体声或 AAC 文件执行此操作,而这正是我想要做的。

这是我到目前为止所拥有的......

CFStringRef fPath;
fPath = CFStringCreateWithCString(kCFAllocatorDefault,
                                  "/path/to/my/audiofile/audiofile.wav",
                                  kCFStringEncodingMacRoman);


OSStatus err;

int mChannels = 1;
UInt32 totalFramesInFile = 100000;

Float32 *outputBuffer = (Float32 *)malloc(sizeof(Float32) * (totalFramesInFile*mChannels)); 


////////////// Set up Audio Buffer List ////////////

AudioBufferList outputData; 
outputData.mNumberBuffers = 1;
outputData.mBuffers[0].mNumberChannels = mChannels; 
outputData.mBuffers[0].mDataByteSize = 4 * totalFramesInFile * mChannels;
outputData.mBuffers[0].mData = outputBuffer;

Float32 audioFile[totalFramesInFile*mChannels];


for (int i = 0;i < totalFramesInFile*mChannels;i++)
{
    audioFile[i] = ((Float32)(rand() % 100))/100.0;
    audioFile[i] = audioFile[i]*0.2;
}

outputData.mBuffers[0].mData = &audioFile;


CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,fPath,kCFURLPOSIXPathStyle,false);

ExtAudioFileRef audiofileRef;

// WAVE FILES

AudioFileTypeID fileType = kAudioFileWAVEType;
AudioStreamBasicDescription clientFormat;
clientFormat.mSampleRate = 44100.0;
clientFormat.mFormatID = kAudioFormatLinearPCM;
clientFormat.mFormatFlags = 12;
clientFormat.mBitsPerChannel = 16;
clientFormat.mChannelsPerFrame = mChannels;
clientFormat.mBytesPerFrame = 2*clientFormat.mChannelsPerFrame;
clientFormat.mFramesPerPacket = 1;
clientFormat.mBytesPerPacket = 2*clientFormat.mChannelsPerFrame;


// open the file for writing
err = ExtAudioFileCreateWithURL((CFURLRef)fileURL, fileType, &clientFormat, NULL, kAudioFileFlags_EraseFile, &audiofileRef);

if (err != noErr)
{
    cout << "Problem when creating audio file: " << err << "\n";
}

// tell the ExtAudioFile API what format we'll be sending samples in
err = ExtAudioFileSetProperty(audiofileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(clientFormat), &clientFormat);

if (err != noErr)
{
    cout << "Problem setting audio format: " << err << "\n";
}

UInt32 rFrames = (UInt32)totalFramesInFile;
// write the data
err = ExtAudioFileWrite(audiofileRef, rFrames, &outputData);

if (err != noErr)
{
    cout << "Problem writing audio file: " << err << "\n";
}

// close the file
ExtAudioFileDispose(audiofileRef);



NSLog(@"Done!");

我的具体问题是:

  • 如何设置 AAC 的 AudioStreamBasicDescription?
  • 为什么我无法让立体声在这里正常工作?如果我将通道数 ('mChannels') 设置为 2,那么我会正确获得左通道,而右通道会出现失真。

我非常感谢任何帮助 - 我想我已经阅读了几乎所有我能找到的页面,但我一无所知,因为虽然存在类似的问题,但他们通常从某些输入音频文件中派生 AudioStreamBasicDescription 参数,我无法看到结果。苹果文档也没有帮助。

提前谢谢了,

Adam


好吧,经过一番探索我已经弄清楚了。我将其包装为一个将随机噪声写入文件的函数。具体来说,它可以:

  • 写入 .wav 或 .m4a 文件
  • 以任一格式写入单声道或立体声
  • 将文件写入指定路径

函数参数是:

  • 要创建的音频文件的路径
  • 通道数(最多 2 个)
  • 布尔值:使用 m4a 压缩(如果为 false,则使用 pcm)

对于立体声 M4A 文件,该函数应调用为:

writeNoiseToAudioFile("/path/to/my/audiofile.m4a",2,true);

该函数的来源如下。我已尝试尽可能多地评论它 - 我希望它是正确的,它当然对我有用,但如果我错过了某些内容,请说“亚当,你做得有点错误”。祝你好运!这是代码:

void writeNoiseToAudioFile(char *fName,int mChannels,bool compress_with_m4a)
{
OSStatus err; // to record errors from ExtAudioFile API functions

// create file path as CStringRef
CFStringRef fPath;
fPath = CFStringCreateWithCString(kCFAllocatorDefault,
                                  fName,
                                  kCFStringEncodingMacRoman);


// specify total number of samples per channel
UInt32 totalFramesInFile = 100000;      

/////////////////////////////////////////////////////////////////////////////
////////////// Set up Audio Buffer List For Interleaved Audio ///////////////
/////////////////////////////////////////////////////////////////////////////

AudioBufferList outputData; 
outputData.mNumberBuffers = 1;
outputData.mBuffers[0].mNumberChannels = mChannels;    
outputData.mBuffers[0].mDataByteSize = sizeof(AudioUnitSampleType)*totalFramesInFile*mChannels;



/////////////////////////////////////////////////////////////////////////////
//////// Synthesise Noise and Put It In The AudioBufferList /////////////////
/////////////////////////////////////////////////////////////////////////////

// create an array to hold our audio
AudioUnitSampleType audioFile[totalFramesInFile*mChannels];

// fill the array with random numbers (white noise)
for (int i = 0;i < totalFramesInFile*mChannels;i++)
{
    audioFile[i] = ((AudioUnitSampleType)(rand() % 100))/100.0;
    audioFile[i] = audioFile[i]*0.2;
    // (yes, I know this noise has a DC offset, bad)
}

// set the AudioBuffer to point to the array containing the noise
outputData.mBuffers[0].mData = &audioFile;


/////////////////////////////////////////////////////////////////////////////
////////////////// Specify The Output Audio File Format /////////////////////
/////////////////////////////////////////////////////////////////////////////


// the client format will describe the output audio file
AudioStreamBasicDescription clientFormat;

// the file type identifier tells the ExtAudioFile API what kind of file we want created
AudioFileTypeID fileType;

// if compress_with_m4a is tru then set up for m4a file format
if (compress_with_m4a)
{
    // the file type identifier tells the ExtAudioFile API what kind of file we want created
    // this creates a m4a file type
    fileType = kAudioFileM4AType;

    // Here we specify the M4A format
    clientFormat.mSampleRate         = 44100.0;
    clientFormat.mFormatID           = kAudioFormatMPEG4AAC;
    clientFormat.mFormatFlags        = kMPEG4Object_AAC_Main;
    clientFormat.mChannelsPerFrame   = mChannels;
    clientFormat.mBytesPerPacket     = 0;
    clientFormat.mBytesPerFrame      = 0;
    clientFormat.mFramesPerPacket    = 1024;
    clientFormat.mBitsPerChannel     = 0;
    clientFormat.mReserved           = 0;
}
else // else encode as PCM
{
    // this creates a wav file type
    fileType = kAudioFileWAVEType;

    // This function audiomatically generates the audio format according to certain arguments
    FillOutASBDForLPCM(clientFormat,44100.0,mChannels,32,32,true,false,false);
}



/////////////////////////////////////////////////////////////////////////////
///////////////// Specify The Format of Our Audio Samples ///////////////////
/////////////////////////////////////////////////////////////////////////////

// the local format describes the format the samples we will give to the ExtAudioFile API
AudioStreamBasicDescription localFormat;
FillOutASBDForLPCM (localFormat,44100.0,mChannels,32,32,true,false,false);



/////////////////////////////////////////////////////////////////////////////
///////////////// Create the Audio File and Open It /////////////////////////
/////////////////////////////////////////////////////////////////////////////

// create the audio file reference
ExtAudioFileRef audiofileRef;

// create a fileURL from our path
CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,fPath,kCFURLPOSIXPathStyle,false);

// open the file for writing
err = ExtAudioFileCreateWithURL((CFURLRef)fileURL, fileType, &clientFormat, NULL, kAudioFileFlags_EraseFile, &audiofileRef);

if (err != noErr)
{
    cout << "Problem when creating audio file: " << err << "\n";
}


/////////////////////////////////////////////////////////////////////////////
///// Tell the ExtAudioFile API what format we'll be sending samples in /////
/////////////////////////////////////////////////////////////////////////////

// Tell the ExtAudioFile API what format we'll be sending samples in 
err = ExtAudioFileSetProperty(audiofileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(localFormat), &localFormat);

if (err != noErr)
{
    cout << "Problem setting audio format: " << err << "\n";
}

/////////////////////////////////////////////////////////////////////////////
///////// Write the Contents of the AudioBufferList to the AudioFile ////////
/////////////////////////////////////////////////////////////////////////////

UInt32 rFrames = (UInt32)totalFramesInFile;
// write the data
err = ExtAudioFileWrite(audiofileRef, rFrames, &outputData);

if (err != noErr)
{
    cout << "Problem writing audio file: " << err << "\n";
}


/////////////////////////////////////////////////////////////////////////////
////////////// Close the Audio File and Get Rid Of The Reference ////////////
/////////////////////////////////////////////////////////////////////////////

// close the file
ExtAudioFileDispose(audiofileRef);


NSLog(@"Done!");
}

不要忘记导入 AudioToolbox 框架并包含头文件:

#import <AudioToolbox/AudioToolbox.h>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 iOS 的 ExtAudioFileWrite 将音频样本缓冲区写入 aac 文件 的相关文章

随机推荐

  • 文本对齐:对齐和图像

    我有一个图像列表 不在列表中 但如果可以解决问题的话可能是 我想填充 div 的整个宽度 我已经尝试过底部的代码 虽然它确实证明了 p 标记中的任何文本合理 但它对图像的作用却不同 我怎样才能让它在 div 的整个宽度上均匀地间隔图像 di
  • 从数据库填充 DropDownList 的正确方法是什么?

    我正在从 SQL Server 数据库填充 DropDownList 如下所示 它工作得很好 但我不确定这是一个好方法 有人可以阐明这种方法并进行一些改进吗 private void LoadSubjects ddlSubjects Ite
  • Android Gradle 代码覆盖率

    我有一个带有测试用例的简单 Android 项目 ProjNameProject build gradle ProjName build gradle 我看到默认情况下android的新构建系统默认提供基本的测试结果 万岁 现在我还想查看代
  • 错误 - 多次出现具有不同值的“contentType”是非法的

    我在 Eclipse 中有一个动态 Web 项目 在 Glassfish4 上运行 在项目中 有一个如下所示的index jsp文件 当我在服务器上运行这个jsp时 出现错误 org apache jasper JasperExceptio
  • 在Windows上构建hadoop 2.2

    我正在尝试在windows上安装hadoop 到目前为止还很麻烦 这是我不断收到的错误 ERROR Failed to execute goal org codehaus mojo exec maven plugin 1 2 exec co
  • 我可以使用 Laravel 5 中间件来允许包覆盖应用程序路由吗?

    我希望能够使用包中的路由覆盖 app Http routes php 中定义的路由 例如 在 app Http routes php 中我可能有这个 Route get search type as gt search uses gt Se
  • 如何在没有科学记数法的 R 数据框中显示数字列('e+07')

    我有一个 R 数据框 其中一列包含一串数字 但我想将它们视为一个因素 主要是为了阻止 R 使用 e 04 等缩短数字 我发现解决此问题的一种方法是编辑从中获取数据的 csv 文件 并添加一个在所需列中包含单词的虚拟条目 然后重新导入它 如何
  • 如何将 facebook、twitter 和 google plus 集成到 Android 应用程序中

    我喜欢将 Facebook Twitter 和 Google plus 集成到我的应用程序中 以便使用该应用程序的用户可以更新他们的状态 因此我想知道如何做到这一点 Thanks 我强烈建议不要使用这些 SDK 因为它们包含很多错误 而且据
  • 如何获取默认 NIC 连接名称

    重要编辑 再次回到这个话题 正如您所说不应该有默认的网卡 我试图了解是否有一种方法可以检测实际连接的所有网卡 有了我的物理接口的 MAC 地址 是否有一种编程方式来获取接口名称 接口状态 等 比如我的XP机器 设备 Realtek RTL8
  • 自动递增 bigint 列?

    我想要插入表中的每一行数据都有一个 bigint ID 列 我想要 Sql 服务器生成数字 我尝试创建一个具有 bigint 列 ID 的表 我希望这是自动增量 第一个值为 1 我尝试使用 ID bigint AUTO INCREMENT
  • 将数据从 Props 传递到 vue.js 中的数据

    我有以下 vue 组件
  • 在 Rust 中使用枚举实现动态多态性

    当人们已经知道某些需要动态多态性的代码中涉及的所有有限数量的类型时 使用enum与使用相比 可以更好地提高性能Box因为后者使用动态内存分配 并且您需要使用也具有虚拟函数调用的特征对象 也就是说 与 C 中使用的等效代码相比std vari
  • 如何配置 IIS,以便在连接到 SQL Server 时使用用户的域凭据?

    我们最近发布了最新版本的 Intranet 应用程序 该应用程序现在使用 Windows 身份验证作为标准 并且需要能够使用最终用户的域凭据连接到已配置的 SQL 服务器 最近我们发现 在一些客户部署中 尽管 IIS 可以看到用户的域凭据
  • 是否可以在 .NET 4 中动态创建路由?

    在我们的应用程序中 我们使用新的 NET 4 路由系统将某些请求路由到站点的其他部分 我们只允许在深夜发布我们的网站代码 这意味着我们必须加班到很晚才能发布任何代码更改 我们经常需要创建自定义路由来支持旧内容的旧链接并将其路由到新内容 这些
  • Adobe Media Encoder 是否可以使用 ExtendScript 编写脚本?

    Adobe Media Encoder AME 是否可以编写脚本 我听人们提到它是 官方可编写脚本的 但我找不到任何对其可编写脚本的对象集的引用 有人有编写 AME 脚本的经验吗 Adobe 媒体编码器 正式 不可编写脚本 但我们可以使用扩
  • Windows 窗体:如何更改禁用标签的字体颜色

    我正在尝试为标签控件设置禁用的字体特征 我可以设置所有字体特征 大小 粗体等 但颜色被默认的窗口行为覆盖 这似乎是这两种颜色之一 如果背景颜色是透明的 则前景色与文本框禁用颜色相同 如果背景颜色设置为其他颜色 则前景色为深灰色 下图演示了该
  • SQLAlchemy:将查询结果插入到另一个表中

    所以我得到了一些结果install表 像这样 install metadata tables install results session query install
  • Activiti / Camunda 用变量改变边界计时器

    我有一个关于 Activiti Camunda 中用户任务的计时器边界事件的特殊问题 启动流程时 我使用流程变量设置计时器持续时间 并使用边界定义中的表达式来解析该变量 边界事件是在用户任务上定义的
  • Javascript - .innerHTML 更改自动关闭标签

    我正在尝试使用 Javascript 动态地将元素放入其他元素中 而无需刷新页面 它的 AJAX 部分可以工作并且功能正常 然而 由于某种未知的原因 我的代码自动关闭 这是代码片段 您可以看到它实际上并未关闭 但是在浏览器中运行代码后它被关
  • 使用 iOS 的 ExtAudioFileWrite 将音频样本缓冲区写入 aac 文件

    更新 我已经弄清楚了这一点并发布了我的解决方案作为我自己的问题的答案 如下 我正在尝试使用 AAC 格式的 ExtAudioFileWrite 将简单的音频样本缓冲区写入文件 我已经通过下面的代码实现了这一点 将单声道缓冲区写入 wav 文