iOS Core Audio: Conversion entre kAudioFormatFlagsCanonical et kAudioFormatFlagsAudioUnitCanonical

J'ai besoin de convertir entre ce format:

format.mSampleRate = 44100.0; format.mFormatID = kAudioFormatLinearPCM; format.mFormatFlags = kAudioFormatFlagsCanonical | kLinearPCMFormatFlagIsNonInterleaved; format.mBytesPerPacket = sizeof(AudioUnitSampleType); format.mFramesPerPacket = 1; format.mBytesPerFrame = sizeof(AudioUnitSampleType); format.mChannelsPerFrame = 2 ; format.mBitsPerChannel = sizeof(AudioUnitSampleType)*8; 

et ce format

 format.mSampleRate = 44100.0; format.mFormatID = kAudioFormatLinearPCM; format.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical; format.mBytesPerPacket = sizeof(AudioUnitSampleType); format.mFramesPerPacket = 1; format.mBytesPerFrame = sizeof(AudioUnitSampleType); format.mChannelsPerFrame = 2; format.mBitsPerChannel = sizeof(AudioUnitSampleType)*8; 

dans les limites d'un callback de rendu audio où il y a le code suivant et le tampon [] est au deuxième format et le tableau [] requirejs le premier format.

 for (k = 0; k < channels; k++){ buffer = (AudioUnitSampleType *) ioData->mBuffers[k].mData; for(j=0; j < samples; j++){ array[j] = buffer[j]; } } 

Je sais que vous pouvez utiliser l'unité de conversion Apple, mais je ne peux pas utiliser l'unité audio Apple Converter dans ma situation (il y a une raison).

Fondamentalement, la seule différence entre les 2 formats l'indicateur suivant pour format.mFormatFlags (kAudioUnitSampleFractionBits << kLinearPCMFormatFlagsSampleFractionShift).

Comment puis-je convertir le buffer [] (contenant datatables au 2ème format) en array [] (contenant datatables au 1er format) et vice-versa?

Je vous remercie.

Eh bien, si vous vous référez aux documents sur kAudioFormatFlagsAudioUnitCanonical , vous voyez:

 kAudioFormatFlagsAudioUnitCanonical The flags for the canonical audio unit sample type. This matches AudioUnitSampleType. 

et

 The canonical audio sample type for audio units and other audio processing in iPhone OS is noninterleaved linear PCM with 8.24-bit fixed-point samples. 

Ainsi, les échantillons du tableau buffer[] sont au format à virgule fixe de 8,24 bits. Qu'est-ce que ça veut dire?

Le format à virgule fixe de 8,24 bits est utilisé pour représenter les nombres flottants avec une précision fixe – un entier de 32 bits où les 8 premiers bits représentent la partie entière et les 24 derniers bits représentent la partie décimale (les nombres après la décimale). ( Plus loin )

Dans les unités audio iOS, il y a une différence mineure – ce nombre flottant (habituellement) est compris entre [-1, 1) ( [-1.000000000000, +0.999969482421875] pour être exact ). Les valeurs en dehors de cette plage sont simplement tronquées lors de la conversion en PCM 16 bits. Vous pouvez valider que les 8 premiers bits seront 0x00 ou 0xff (-1 dans le compliment de deux) pour la plupart.

Pour convertir cette représentation en un nombre de 16 bits, utilisez ceci:

 SIGN((SInt8)(val >> 24)) * 32768 * (val & 0xFFFFFF)/(float)(1<<24) 

C'est-à-dire: extraire le signe du MSB 8, extraire la valeur fractionnaire de 24 LSB et split par intervalle de 24 bits (2 ^ 24) résultant en un flottant entre 0 et 1, et enfin le multiplier par 32768 pour get une valeur dans la gamme désirée.

Je n'ai pas essayé moi-même cependant – vous devrez peut-être ajuster quelques choses ici et là.

Peut-être une réponse tardive, mais puisque la méthode des bits de décalage n'a pas fonctionné pour moi pour une raison quelconque, j'ai trouvé cette alternative qui fonctionne bien, dans l'audiographe https://github.com/tkzic/audiograph

J'ai adapté un peu une méthode à partir de là et voilà:

 void ConvertInputToInt16(AudioStreamBasicDescription inFormat, void *buf, void *outputBuf, size_t capacity) { AudioConverterRef converter; OSStatus err; size_t bytesPerSample = sizeof(SInt16); AudioStreamBasicDescription outFormat = {0}; outFormat.mFormatID = kAudioFormatLinearPCM; outFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; outFormat.mBitsPerChannel = 8 * bytesPerSample; outFormat.mFramesPerPacket = 1; outFormat.mChannelsPerFrame = 1; outFormat.mBytesPerPacket = bytesPerSample * outFormat.mFramesPerPacket; outFormat.mBytesPerFrame = bytesPerSample * outFormat.mChannelsPerFrame; outFormat.mSampleRate = inFormat.mSampleRate; NSLog(@"description for in format: %@", descriptionForAudioFormat(inFormat)); NSLog(@"description for out format: %@", descriptionForAudioFormat(outFormat)); UInt32 inSize = capacity*sizeof(SInt32); UInt32 outSize = capacity*sizeof(SInt16); // this is the famed audio converter err = AudioConverterNew(&inFormat, &outFormat, &converter); if(noErr != err) { NSLog(@"error in audioConverterNew: %d", (int)err); } err = AudioConverterConvertBuffer(converter, inSize, buf, &outSize, outputBuf); if(noErr != err) { NSLog(@"error in audioConverterConvertBuffer: %d", err); } }