iphone — запись буфера аудиосэмплов в aac-файл с использованием ExtAudioFileWrite для iOS

ОБНОВЛЕНИЕ: я понял это и разместил свое решение как ответ на мой собственный вопрос (ниже)

Я пытаюсь записать простой буфер аудиосэмплов в файл, используя ExtAudioFileWrite в формате AAC.

Я добился этого с помощью приведенного ниже кода для записи монобуфера в файл .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!");

Мои конкретные вопросы:

  • Как мне настроить AudioStreamBasicDescription для AAC?
  • Почему я не могу заставить стерео работать правильно? Если я установлю количество каналов («mChannels») на 2, тогда я получу правильный левый канал и искажения в правом канале.

Я был бы очень признателен за любую помощь — я думаю, что я прочитал почти каждую страницу, которую я могу найти на этом, и я не мудрый, поскольку, хотя есть подобные вопросы, они обычно получают параметры AudioStreamBasicDescription из некоторого входного аудиофайла, который я не может видеть результат. Документация Apple тоже не поможет.

Спасибо заранее,

Адам

5

Решение

Хорошо, после некоторого исследования я понял это. Я обернул его как функцию, которая записывает случайный шум в файл. В частности, он может:

  • записывать файлы .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 Framework и включить заголовочный файл:

#import <AudioToolbox/AudioToolbox.h>
6

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]