【发布时间】:2016-01-11 05:38:24
【问题描述】:
我正在尝试根据从我的 macbook 的默认输入设备(内置麦克风)获得的声音输入创建一个 wav 文件。但是,当作为原始数据导入 Audacity 时,生成的文件完全是垃圾。
首先我初始化音频文件引用,以便稍后在音频单元输入回调中写入它。
// struct contains audiofileID as member
MyAUGraphPlayer player = {0};
player.startingByte = 0;
// describe a PCM format for audio file
AudioStreamBasicDescription format = { 0 };
format.mBytesPerFrame = 2;
format.mBytesPerPacket = 2;
format.mChannelsPerFrame = 1;
format.mBitsPerChannel = 16;
format.mFramesPerPacket = 1;
format.mFormatFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsFloat;
format.mFormatID = kAudioFormatLinearPCM;
CFURLRef myFileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("./test.wav"), kCFURLPOSIXPathStyle, false);
//CFShow (myFileURL);
CheckError(AudioFileCreateWithURL(myFileURL,
kAudioFileWAVEType,
&format,
kAudioFileFlags_EraseFile,
&player.recordFile), "AudioFileCreateWithURL failed");
这里我分配了一些缓冲区来保存来自 AUHAL 单元的音频数据。
UInt32 bufferSizeFrames = 0;
propertySize = sizeof(UInt32);
CheckError (AudioUnitGetProperty(player->inputUnit,
kAudioDevicePropertyBufferFrameSize,
kAudioUnitScope_Global,
0,
&bufferSizeFrames,
&propertySize), "Couldn't get buffer frame size from input unit");
UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32);
printf("buffer num of frames %i", bufferSizeFrames);
if (player->streamFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) {
int offset = offsetof(AudioBufferList, mBuffers[0]);
int sizeOfAB = sizeof(AudioBuffer);
int chNum = player->streamFormat.mChannelsPerFrame;
int inputBufferSize = offset + sizeOfAB * chNum;
//malloc buffer lists
player->inputBuffer = (AudioBufferList *)malloc(inputBufferSize);
player->inputBuffer->mNumberBuffers = chNum;
for (UInt32 i = 0; i < chNum ; i++) {
player->inputBuffer->mBuffers[i].mNumberChannels = 1;
player->inputBuffer->mBuffers[i].mDataByteSize = bufferSizeBytes;
player->inputBuffer->mBuffers[i].mData = malloc(bufferSizeBytes);
}
}
为了检查数据是否实际合理,我渲染了音频单元,然后在每个回调中记录每组帧的前 4 个字节 (4096)。原因是检查这些值是否与进入麦克风的值一致。当我对着麦克风说话时,我注意到这个内存位置中的注销值对应于输入。因此,这方面的事情似乎正在发挥作用:
// render into our buffer
OSStatus inputProcErr = noErr;
inputProcErr = AudioUnitRender(player->inputUnit,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
player->inputBuffer);
// copy from our buffer to ring buffer
Float32 someDataL = *(Float32*)(player->inputBuffer->mBuffers[0].mData);
printf("L2 input: % 1.7f \n",someDataL);
最后,在输入回调中,我将音频字节写入文件。
UInt32 numOfBytes = 4096*player->streamFormat.mBytesPerFrame;
AudioFileWriteBytes(player->recordFile,
FALSE,
player->startingByte,
&numOfBytes,
&ioData[0].mBuffers[0].mData);
player->startingByte += numOfBytes;
所以我还没有弄清楚为什么数据出来时听起来有问题、失真或根本不存在。一件事是生成的音频文件大约与我实际录制的时间一样长。 (点击返回停止音频单元并关闭音频文件)。
我不确定接下来要看什么。有没有人尝试从 AUHAL 回调写入音频文件并得到类似的结果?
【问题讨论】:
-
AudioFileWriteBytes 是异步的吗? Apple 的文档说“在大多数情况下,您应该使用 AudioFileWritePackets 而不是这个函数。”developer.apple.com/library/ios/documentation/MusicAudio/…
-
那么你能听到你对着麦克风说的话吗?还是音频完全是垃圾?
-
有人告诉我,缺乏异步性是问题所在。我无法使用 audioFileWriteBytes,因为它访问文件系统,我将其调用到实时线程回调中。我的选择是使用异步版本 ExtAudioFileWriteAsync 或将传入的样本传递到环形缓冲区并将它们卸载到其他地方的文件中。我仍在努力。
标签: macos core-audio audiounit