将浮点数组写入音频文件

Posted

技术标签:

【中文标题】将浮点数组写入音频文件【英文标题】:Writing array of floats to audio file 【发布时间】:2014-06-12 15:49:17 【问题描述】:

我有一个名为 _recordingSamples 的 Float32 值数组,我希望将其写入音频文件。 _recordingLength 的值约为 390000。我正在使用以下代码:

NSString *outputPath = @"/Users/evanjackson/output.caf";
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager createFileAtPath:outputPath contents:nil attributes:nil];

AudiostreamBasicDescription _audioFormat;
_audioFormat.mSampleRate = 44100.0;
_audioFormat.mFormatID = kAudioFormatLinearPCM;
_audioFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
_audioFormat.mChannelsPerFrame = 1;
_audioFormat.mBitsPerChannel = 32;
_audioFormat.mBytesPerFrame = 4;
_audioFormat.mFramesPerPacket = 1;
_audioFormat.mBytesPerPacket = _audioFormat.mFramesPerPacket * _audioFormat.mBytesPerFrame;

UInt32 lengthPropertySize = sizeof(SInt64);
ExtAudioFileRef filteredAudio;
NSURL *destinationURL = [NSURL URLWithString:outputPath];
OSStatus status = ExtAudioFileCreateWithURL((__bridge CFURLRef)destinationURL, kAudioFileCAFType, &_audioFormat, NULL, kAudioFileFlags_EraseFile, &filteredAudio);
printf("Status: %d\n", status);
//ExtAudioFileOpenURL((__bridge CFURLRef)[NSURL fileURLWithPath:outputPath], &filteredAudio);
const AudioStreamBasicDescription audioFormat = [del audioFormat];
status = ExtAudioFileSetProperty(filteredAudio, kExtAudioFileProperty_ClientDataFormat, sizeof(audioFormat), &audioFormat);
printf("Status: %d\n", status);
status = ExtAudioFileGetProperty(filteredAudio, kExtAudioFileProperty_FileLengthFrames, &lengthPropertySize, &_recordingLength);
printf("Status: %d\n", status);
AudioBufferList *buffers = (AudioBufferList *)malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer));
buffers->mNumberBuffers = 1;
for (int i = 0; i < buffers->mNumberBuffers; i++) 
    buffers->mBuffers[0].mData = _recordingSamples;
    buffers->mBuffers[0].mNumberChannels = 1;
    buffers->mBuffers[0].mDataByteSize = _recordingLength * sizeof(Float32);


status = ExtAudioFileWrite(filteredAudio, _recordingLength, buffers);
printf("Status: %d\n", status);

所有状态都返回 0,文件被创建(4 个字节),但 Quicktime 不会打开它并返回错误 -12842,编译器会传递以下消息:

libc++abi.dylib: terminating with uncaught exception of type std::bad_alloc: std::bad_alloc
(lldb) 

有人知道怎么回事吗?提前致谢。

【问题讨论】:

【参考方案1】:

废弃我在问题中发布的代码。我在这里找到了解决方案:How to write array of float values to audio file in Core Audio?。看第一个答案。我去了给定的链接,下载了源代码,然后将 EAFWrite.h 和 EAFWrite.mm 添加到我的项目中。该类假设音频将从多个缓冲区(即:2D 数组)中读取,但需要它与 1D 数组一起使用,因此我将函数 writeToFloats 修改如下:

-(OSStatus) writeFloats:(long)numFrames fromArray:(float *)data

    OSStatus    err = noErr;

    if (!data)      return -1;
    if (!numFrames) return -1;

    AudioBufferList *abl = AllocateAudioBufferList(mStreamFormat.mChannelsPerFrame, numFrames*sizeof(short));
    if (!abl)       return -1;

    abl->mBuffers[0].mNumberChannels = 1;
    abl->mBuffers[0].mDataByteSize = numFrames*sizeof(short);
    short *buffer = (short*)abl->mBuffers[0].mData;
    for (long v = 0; v < numFrames; v++) 
        if (data[v] > 0.999)
            data[v] = 0.999;
        else if (data[v] < -1)
            data[v] = -1;
        buffer[v] = (short)(data[v]*32768.f);
    

    abl->mBuffers[0].mData = buffer;

    err = ExtAudioFileWrite(mOutputAudioFile, numFrames, abl);

    DestroyAudioBufferList(abl);

    if(err != noErr)
    
        char formatID[5];
        *(UInt32 *)formatID = CFSwapInt32HostToBig(err);
        formatID[4] = '\0';
        fprintf(stderr, "ExtAudioFileWrite FAILED! %d '%-4.4s'\n",(int)err, formatID);
        return err;
    

    return err;


要调用这个函数,你需要:

NSString *outputPath = @"outputFile.caf"
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager createFileAtPath:outputPath contents:nil attributes:nil];
NSURL* fileURL = [NSURL URLWithString:outputPath];

EAFWrite *writer = [[EAFWrite alloc] init];
[writer openFileForWrite:fileURL sr:44100.0 channels:1 wordLength:32 type:kAudioFileCAFType];
[writer writeFloats:_recordingLength fromArray:_recordingSamples];

【讨论】:

【参考方案2】:

那是一堆相当麻烦的代码。

这一行:

AudioBufferList *buffers = 
  (AudioBufferList *)malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer));

我觉得很可疑。它正在分配一个固定大小的缓冲区,即 sizeof(AudioBufferList) 和 sizeof(AudioBuffer) 之和

这两个变量的类型是什么?

Sizeof 返回结构的大小,而不是它指向的内容的大小。我猜你需要一个分配给单个浮点大小的缓冲区乘以一个保存数组中浮点总数的值。 (那是 _recordingLength 吗?)

这段代码是从哪里来的?你能详细解释一下它应该做什么吗?你的花车数组来自哪里?什么告诉你的代码有多少字节?数据存储在内存中的什么位置?是什么将值缓冲区写入磁盘?

您说您的文件已创建并且长度为 4 个字节。如果您尝试存储大约 390000 个浮点数,这听起来肯定是个问题。

【讨论】:

我将音频文件 (.caf) 读入浮点数组 _recordingSamples 的原始代码。我使用了该代码并且基本上试图反转它,即将浮点数组写回音频文件,但我不确定这是否是正确的方法。

以上是关于将浮点数组写入音频文件的主要内容,如果未能解决你的问题,请参考以下文章

用脚编码音频:将 32 位浮点数转换为 mp3

将 32 位浮点数转换为 16 位 PCM 范围

用于浮点数或 int 的 Python 正则表达式,而不是将浮点数分成两个浮点数

C++ 将浮点数保存并加载到二进制文件中,由指针寻址

wav音频文件解析读取 定点转浮点分析 幅值提取(C语言实现)

如何播放音频样本而不将其写入文件?