Síntese granular no iOS 6 usando AudioFileServices

Eu tenho uma pergunta sobre um aplicativo de síntese de som em que estou trabalhando. Eu estou tentando ler em um arquivo de áudio, criar 'grãos' randomizados usandotécnicas de síntese granular, coloque-os em um buffer de saída e, em seguida, ser capaz de reproduzir isso para o usuário usando o OpenAL. Para fins de teste, estou simplesmente escrevendo o buffer de saída em um arquivo que eu possa ouvir de volta.

A julgar pelos meus resultados, eu estou no caminho certo, mas estou recebendo alguns problemas de aliasing e sons de reprodução que simplesmente não parecem muito bem. Geralmente, há um pop bastante alto no meio do arquivo de saída e os níveis de volume são muito altos às vezes.

Aqui estão os passos que tomei para obter os resultados que preciso, mas estou um pouco confuso sobre algumas coisas, ou seja, os formatos que estou especificando para o meu AudioStreamBasicDescription.

Leia em um arquivo de áudio do meu mainBundle, que é um arquivo mono no formato .aiff:

ExtAudioFileRef extAudioFile;
CheckError(ExtAudioFileOpenURL(loopFileURL,
                           &extAudioFile),
       "couldn't open extaudiofile for reading");
memset(&player->dataFormat, 0, sizeof(player->dataFormat));

player->dataFormat.mFormatID = kAudioFormatLinearPCM;
player->dataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
player->dataFormat.mSampleRate = S_RATE;
player->dataFormat.mChannelsPerFrame = 1;
player->dataFormat.mFramesPerPacket = 1;
player->dataFormat.mBitsPerChannel = 16;
player->dataFormat.mBytesPerFrame = 2;
player->dataFormat.mBytesPerPacket = 2;

// tell extaudiofile about our format
CheckError(ExtAudioFileSetProperty(extAudioFile,
                               kExtAudioFileProperty_ClientDataFormat,
                               sizeof(AudioStreamBasicDescription),
                               &player->dataFormat),
       "couldnt set client format on extaudiofile");

SInt64 fileLengthFrames;
UInt32 propSize = sizeof(fileLengthFrames);
ExtAudioFileGetProperty(extAudioFile,
                    kExtAudioFileProperty_FileLengthFrames,
                    &propSize,
                    &fileLengthFrames);

player->bufferSizeBytes = fileLengthFrames * player->dataFormat.mBytesPerFrame;

Em seguida, declaro meu AudioBufferList e defino mais algumas propriedades

AudioBufferList *buffers;
UInt32 ablSize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * 1);
buffers = (AudioBufferList *)malloc(ablSize);

player->sampleBuffer = (SInt16 *)malloc(sizeof(SInt16) * player->bufferSizeBytes);

buffers->mNumberBuffers = 1;
buffers->mBuffers[0].mNumberChannels = 1;
buffers->mBuffers[0].mDataByteSize = player->bufferSizeBytes;
buffers->mBuffers[0].mData = player->sampleBuffer;

Meu entendimento é que .mData será o que foi especificado no formatFlags (nesse caso, digite SInt16). Desde que é do tipo (vazio*), Eu quero converter isso em dados flutuantes, o que é óbvio para manipulação de áudio. Antes de configurar um loop for que apenas iterava pelo buffer e lançava cada amostra em um float *. Isso parecia desnecessário, então agora eu passo meu buffer .mData para uma função que criei e granularizei o áudio:

    float *theOutBuffer = [self granularizeWithData:(float *)buffers->mBuffers[0].mData with:framesRead];

Nesta função, eu aloco dinamicamente alguns buffers, crio grãos de tamanho aleatório, coloco-os no meu buffer de saída depois de usar o janelamento deles usando uma janela de hamming e retorno esse buffer (que é dados flutuantes). Tudo é legal até este ponto.

Em seguida eu configurei todo o meu arquivo de saída ASBD e tal:

AudioStreamBasicDescription outputFileFormat;

bzero(audioFormatPtr, sizeof(AudioStreamBasicDescription));

outputFileFormat->mFormatID = kAudioFormatLinearPCM;
outputFileFormat->mSampleRate = 44100.0;
outputFileFormat->mChannelsPerFrame = numChannels;
outputFileFormat->mBytesPerPacket = 2 * numChannels;
outputFileFormat->mFramesPerPacket = 1;
outputFileFormat->mBytesPerFrame = 2 * numChannels;
outputFileFormat->mBitsPerChannel = 16;
outputFileFormat->mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;

UInt32 flags = kAudioFileFlags_EraseFile;
ExtAudioFileRef outputAudioFileRef = NULL;
NSString *tmpDir = NSTemporaryDirectory();
NSString *outFilename = @"Decomp.caf";
NSString *outPath = [tmpDir stringByAppendingPathComponent:outFilename];
NSURL *outURL = [NSURL fileURLWithPath:outPath];


AudioBufferList *outBuff;
UInt32 abSize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * 1);
outBuff = (AudioBufferList *)malloc(abSize);

outBuff->mNumberBuffers = 1;
outBuff->mBuffers[0].mNumberChannels = 1;
outBuff->mBuffers[0].mDataByteSize = abSize;
outBuff->mBuffers[0].mData = theOutBuffer;

CheckError(ExtAudioFileCreateWithURL((__bridge CFURLRef)outURL,
                                 kAudioFileCAFType,
                                 &outputFileFormat,
                                 NULL,
                                 flags,
                                 &outputAudioFileRef),
       "ErrorCreatingURL_For_EXTAUDIOFILE");

CheckError(ExtAudioFileSetProperty(outputAudioFileRef,
                               kExtAudioFileProperty_ClientDataFormat,
                               sizeof(outputFileFormat),
                               &outputFileFormat),
       "ErrorSettingProperty_For_EXTAUDIOFILE");

CheckError(ExtAudioFileWrite(outputAudioFileRef,
                         framesRead,
                         outBuff),
       "ErrorWritingFile");

O arquivo está escrito corretamente, no formato CAF. Minha pergunta é esta: estou processando o buffer .mData corretamente em que estou lançando as amostras para flutuar dados, manipulando (granulando) vários tamanhos de janela e, em seguida, gravá-lo em um arquivo usando ExtAudioFileWrite (no formato CAF)? Existe uma maneira mais elegante de fazer isso, como declarar meu formato ASBD como kAudioFlagIsFloat? Meu arquivo CAF de saída tem alguns cliques e quando eu abri-lo no Logic, parece que há muito alias. Isso faz sentido se eu estou tentando enviá-lo dados flutuantes, mas há algum tipo de conversão acontecendo que eu não tenho conhecimento.

Agradecemos antecipadamente por qualquer conselho sobre o assunto! Eu tenho sido um leitor ávido de praticamente todo o material de origem on-line, incluindo o Core Audio Book, vários blogs, tutoriais, etc. O objetivo final do meu aplicativo é reproduzir o áudio granularizado em tempo real para um usuário com fones de ouvido. escrever para o arquivo só está sendo usado para testes no momento. Obrigado!

questionAnswers(1)

yourAnswerToTheQuestion