iOS: как прочитать аудиофайл в плавающий буфер - PullRequest
9 голосов
/ 24 сентября 2011

У меня очень короткий аудиофайл, скажем, с точностью до одной десятой секунды в (скажем) формате .PCM

Я хочу использовать RemoteIO для многократного циклического просмотра файла для получения непрерывного музыкального тона.Так как мне прочитать это в массив с плавающей точкой?

РЕДАКТИРОВАТЬ: хотя я мог бы, вероятно, выкопать формат файла, извлечь файл в NSData и обработать его вручную, я предполагаю, что есть более разумныйобщий подход ... (который, например, справляется с различными форматами)

Ответы [ 3 ]

17 голосов
/ 04 октября 2011

Вы можете использовать ExtAudioFile для чтения данных из любого поддерживаемого формата данных в многочисленных клиентских форматах. Вот пример для чтения файла в виде 16-разрядных целых чисел:

CFURLRef url = /* ... */;
ExtAudioFileRef eaf;
OSStatus err = ExtAudioFileOpenURL((CFURLRef)url, &eaf);
if(noErr != err)
  /* handle error */

AudioStreamBasicDescription format;
format.mSampleRate = 44100;
format.mFormatID = kAudioFormatLinearPCM;
format.mFormatFlags = kAudioFormatFormatFlagIsPacked;
format.mBitsPerChannel = 16;
format.mChannelsPerFrame = 2;
format.mBytesPerFrame = format.mChannelsPerFrame * 2;
format.mFramesPerPacket = 1;
format.mBytesPerPacket = format.mFramesPerPacket * format.mBytesPerFrame;

err = ExtAudioFileSetProperty(eaf, kExtAudioFileProperty_ClientDataFormat, sizeof(format), &format);

/* Read the file contents using ExtAudioFileRead */

Если вам нужны данные Float32, вы должны настроить format следующим образом:

format.mFormatID = kAudioFormatLinearPCM;
format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
format.mBitsPerChannel = 32;
5 голосов
/ 15 января 2014

Это код, который я использовал для преобразования моих аудиоданных (аудиофайла) в представление с плавающей запятой и сохранение в массиве.

-(void) PrintFloatDataFromAudioFile {

NSString *  name = @"Filename";  //YOUR FILE NAME
NSString * source = [[NSBundle mainBundle] pathForResource:name ofType:@"m4a"]; // SPECIFY YOUR FILE FORMAT

const char *cString = [source cStringUsingEncoding:NSASCIIStringEncoding];

CFStringRef str = CFStringCreateWithCString(
                                            NULL,
                                            cString,
                                            kCFStringEncodingMacRoman
                                            );
CFURLRef inputFileURL = CFURLCreateWithFileSystemPath(
                                                      kCFAllocatorDefault,
                                                      str,
                                                      kCFURLPOSIXPathStyle,
                                                      false
                                                      );

ExtAudioFileRef fileRef;
ExtAudioFileOpenURL(inputFileURL, &fileRef);


  AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate = 44100;   // GIVE YOUR SAMPLING RATE 
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
audioFormat.mBitsPerChannel = sizeof(Float32) * 8;
audioFormat.mChannelsPerFrame = 1; // Mono
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * sizeof(Float32);  // == sizeof(Float32)
audioFormat.mFramesPerPacket = 1;
audioFormat.mBytesPerPacket = audioFormat.mFramesPerPacket * audioFormat.mBytesPerFrame; // = sizeof(Float32)

// 3) Apply audio format to the Extended Audio File
ExtAudioFileSetProperty(
                        fileRef,
                        kExtAudioFileProperty_ClientDataFormat,
                        sizeof (AudioStreamBasicDescription), //= audioFormat
                        &audioFormat);

int numSamples = 1024; //How many samples to read in at a time
UInt32 sizePerPacket = audioFormat.mBytesPerPacket; // = sizeof(Float32) = 32bytes
UInt32 packetsPerBuffer = numSamples;
UInt32 outputBufferSize = packetsPerBuffer * sizePerPacket;

// So the lvalue of outputBuffer is the memory location where we have reserved space
UInt8 *outputBuffer = (UInt8 *)malloc(sizeof(UInt8 *) * outputBufferSize);



AudioBufferList convertedData ;//= malloc(sizeof(convertedData));

convertedData.mNumberBuffers = 1;    // Set this to 1 for mono
convertedData.mBuffers[0].mNumberChannels = audioFormat.mChannelsPerFrame;  //also = 1
convertedData.mBuffers[0].mDataByteSize = outputBufferSize;
convertedData.mBuffers[0].mData = outputBuffer; //

UInt32 frameCount = numSamples;
float *samplesAsCArray;
int j =0;
    double floatDataArray[882000]   ; // SPECIFY YOUR DATA LIMIT MINE WAS 882000 , SHOULD BE EQUAL TO OR MORE THAN DATA LIMIT

while (frameCount > 0) {
    ExtAudioFileRead(
                     fileRef,
                     &frameCount,
                     &convertedData
                     );
    if (frameCount > 0)  {
        AudioBuffer audioBuffer = convertedData.mBuffers[0];
        samplesAsCArray = (float *)audioBuffer.mData; // CAST YOUR mData INTO FLOAT

       for (int i =0; i<1024 /*numSamples */; i++) { //YOU CAN PUT numSamples INTEAD OF 1024

            floatDataArray[j] = (double)samplesAsCArray[i] ; //PUT YOUR DATA INTO FLOAT ARRAY
              printf("\n%f",floatDataArray[j]);  //PRINT YOUR ARRAY'S DATA IN FLOAT FORM RANGING -1 TO +1
            j++;


        }
    }
}}
5 голосов
/ 04 октября 2011

Я не знаком с RemoteIO, но я знаком с WAV и думал, что опубликую некоторую информацию о формате на них. Если вам нужно, вы сможете легко анализировать такую ​​информацию, как длительность, скорость передачи и т. Д. ...

Во-первых, отличный веб-сайт, в котором подробно описан формат WAVE PCM . Этот сайт также отлично справляется с задачей, иллюстрируя, на что ссылаются различные байтовые адреса внутри подкадра "fmt".

WAVE Формат файла

  • WAVE состоит из фрагмента "RIFF" и последующих подчастей
  • Каждый фрагмент занимает не менее 8 байтов
  • Первые 4 байта - это идентификатор чанка.
  • Следующие 4 байта - это размер куска (Размер куска дает размер оставшейся части куска, исключая 8 байтов, используемых для идентификатора куска и размера куска)
  • Каждый WAVE имеет следующие чанки / суб чанки
    • «RIFF» (первый и единственный фрагмент. Все остальные являются технически подчастями.)
    • "fmt" (обычно первый суб-блок после "RIFF", но может быть где-то между "RIFF" и "данными". Этот блок имеет информацию о WAV, такую ​​как количество каналов, частота дискретизации и частота байтов)
    • «данные» (должен быть последним суб-чанком и содержать все звуковые данные)

Общие форматы аудио WAVE:

  • PCM
  • IEEE_Float
  • PCM_EXTENSIBLE (с подформатом PCM или IEEE_FLOAT)

WAVE Продолжительность и размер

Продолжительность файла WAVE можно рассчитать следующим образом:

seconds = DataChunkSize / ByteRate

Где

ByteRate = SampleRate * NumChannels * BitsPerSample/8

и DataChunkSize не включает 8 байтов, зарезервированных для идентификатора и размера субблока «data».

Зная это, DataChunkSize можно рассчитать, если вы знаете продолжительность WAV и ByteRate.

DataChunkSize = seconds * ByteRate

Это может быть полезно для расчета размера wav-данных при конвертации из форматов, таких как mp3 или wma. Обратите внимание, что типичный заголовок wav составляет 44 байта, за которым следует DataChunkSize (это всегда имеет место, если wav был преобразован с использованием инструмента нормализатора - по крайней мере, на момент написания этой статьи).

...