Извлечение амплитудных данных из линейного PCM на iPhone - PullRequest
10 голосов
/ 30 сентября 2010

У меня возникают трудности с извлечением амплитудных данных из линейной PCM на iPhone, хранящихся в файле audio.caf.

Мои вопросы:

  1. Линейный PCM сохраняет выборки амплитуд как 16-битные значения.Это правильно?
  2. Как амплитуда сохраняется в пакетах, возвращаемых AudioFileReadPacketData ()?Разве при записи моно линейного PCM каждый сэмпл (в одном кадре, в одном пакете) не является просто массивом для SInt16?Каков порядок байтов (порядковый номер с прямым порядком байтов против младшего)?
  3. Что физически означает каждый шаг в линейной амплитуде PCM?
  4. Когда на iPhone записывается линейный PCM, является ли центральная точка0 (SInt16) или 32768 (UInt16)?Что означают максимальные минимальные значения в форме физической волны / давления воздуха?

и дополнительный вопрос: существуют ли формы волны звука / давления воздуха, которые микрофон iPhone не может измерить?

Мой код следующий:

// get the audio file proxy object for the audio
AudioFileID fileID;
AudioFileOpenURL((CFURLRef)audioURL, kAudioFileReadPermission, kAudioFileCAFType, &fileID);

// get the number of packets of audio data contained in the file
UInt64 totalPacketCount = [self packetCountForAudioFile:fileID];

// get the size of each packet for this audio file
UInt32 maxPacketSizeInBytes = [self packetSizeForAudioFile:fileID];

// setup to extract the audio data
Boolean inUseCache = false;
UInt32 numberOfPacketsToRead = 4410; // 0.1 seconds of data
UInt32 ioNumPackets = numberOfPacketsToRead;
UInt32 ioNumBytes = maxPacketSizeInBytes * ioNumPackets;
char *outBuffer = malloc(ioNumBytes);
memset(outBuffer, 0, ioNumBytes);

SInt16 signedMinAmplitude = -32768;
SInt16 signedCenterpoint = 0;
SInt16 signedMaxAmplitude = 32767;

SInt16 minAmplitude = signedMaxAmplitude;
SInt16 maxAmplitude = signedMinAmplitude;

// process each and every packet
for (UInt64 packetIndex = 0; packetIndex < totalPacketCount; packetIndex = packetIndex + ioNumPackets)
{
   // reset the number of packets to get
   ioNumPackets = numberOfPacketsToRead;

   AudioFileReadPacketData(fileID, inUseCache, &ioNumBytes, NULL, packetIndex, &ioNumPackets, outBuffer);

   for (UInt32 batchPacketIndex = 0; batchPacketIndex < ioNumPackets; batchPacketIndex++)
   {
      SInt16 packetData = outBuffer[batchPacketIndex * maxPacketSizeInBytes];
      SInt16 absoluteValue = abs(packetData);

      if (absoluteValue < minAmplitude) { minAmplitude = absoluteValue; }
      if (absoluteValue > maxAmplitude) { maxAmplitude = absoluteValue; }
   }
}

NSLog(@"minAmplitude: %hi", minAmplitude);
NSLog(@"maxAmplitude: %hi", maxAmplitude);

С этим кодом я почти всегда получаю минус 0 и максимум 128!Это не имеет смысла для меня.

Я записываю аудио с помощью AVAudioRecorder следующим образом:

// specify mono, 44.1 kHz, Linear PCM with Max Quality as recording format
NSDictionary *recordSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
   [NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
   [NSNumber numberWithInt: kAudioFormatLinearPCM], AVFormatIDKey,
   [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
   [NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
   nil];

// store the sound file in the app doc folder as calibration.caf
NSString *documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *audioFileURL = [NSURL fileURLWithPath:[documentsDir stringByAppendingPathComponent: @"audio.caf"]];

// create the audio recorder
NSError *createAudioRecorderError = nil;
AVAudioRecorder *newAudioRecorder = [[AVAudioRecorder alloc] initWithURL:audioFileURL settings:recordSettings error:&createAudioRecorderError];
[recordSettings release];

if (newAudioRecorder)
{
   // record the audio
   self.recorder = newAudioRecorder;
   [newAudioRecorder release];

   self.recorder.delegate = self;
   [self.recorder prepareToRecord];
   [self.recorder record];
}
else
{
   NSLog(@"%@", [createAudioRecorderError localizedDescription]);
}

Спасибо за любые идеи, которые вы можете предложить.Это мой первый проект, использующий Core Audio, поэтому не стесняйтесь разорвать мой подход!

PS Я пытался выполнить поиск в архивах списка Core Audio, но запрос продолжает выдавать ошибку: (* http://search.lists.apple.com/?q=linear+pcm+amplitude&cmd=Search%21&ul=coreaudio-api)

PPS Я смотрел:

http://en.wikipedia.org/wiki/Sound_pressure

http://en.wikipedia.org/wiki/Linear_PCM

http://wiki.multimedia.cx/index.php?title=PCM

Получить амплитуду в определенный момент времени в звуковом файле?

http://music.columbia.edu/pipermail/music-dsp/2002-April/048341.html

Я также прочитал полный обзор Core Audio и большую часть Руководства по программированию аудиосеанса,но мои вопросы остаются.

Ответы [ 2 ]

7 голосов
/ 30 сентября 2010

1) процедуры чтения файла os x / iphone позволяют определить примерный формат, как правило, один из SInt8, SInt16, SInt32, Float32, Float64 или смежный 24-битный int со знаком для LPCM

2)для форматов int MIN_FOR_TYPE представляет максимальную амплитуду в отрицательной фазе, а MAX_FOR_TYPE представляет максимальную амплитуду в положительной фазе.0 равняется тишине.Форматы с плавающей точкой модулируются между [-1 ... 1], с нулем, как с плавающей точкой.при чтении, записи, записи или работе с определенным форматом значение порядка байтов будет иметь значение - для файла может потребоваться определенный формат, и вы, как правило, хотите манипулировать данными с собственным порядком байтов.некоторые подпрограммы в библиотеках звуковых файлов apple позволяют передавать флаг, обозначающий порядковый номер источника, а не преобразовывать его вручную.CAF немного сложнее - он действует как мета-оболочка для одного или нескольких аудиофайлов и поддерживает множество типов.

3) представление амплитуды для lpcm представляет собой просто линейное представление амплитуды (без преобразования)/ декодирование требуется для воспроизведения, и шаги амплитуды равны).

4) см. # 2.значения не связаны с давлением воздуха, они связаны с 0 дБфс;например, если вы выводите поток прямо в ЦАП, то int max (или -1/1, если с плавающей запятой) представляет уровень, на котором будет отсекать отдельный сэмпл.

Bonus), как и каждыйАЦП и цепь компонентов имеют ограничения на то, что он может обрабатывать на входе с точки зрения напряжения.Кроме того, частота дискретизации определяет самую высокую частоту, которая может быть захвачена (самая высокая - половина частоты дискретизации).АЦП может использовать фиксированную или выбираемую битовую глубину, но максимальное входное напряжение обычно не изменяется при выборе другой битовой глубины.

одна ошибка, которую вы делаете на уровне кода: вы манипулируете `outBuffer 'как символы - не SInt16

2 голосов
/ 30 сентября 2010
  1. Если вы запрашиваете 16-битные сэмплы в вашем формате записи, то вы получаете 16-битные сэмплы. Но другие форматы существуют во многих API-интерфейсах записи / воспроизведения Core Audio и в возможных форматах файлов caf.

  2. В моно вы просто получаете массив 16-битных целых чисел со знаком. В некоторых API-интерфейсах записи Core Audio вы можете задать запрос с прямым или прямым порядком байтов.

  3. Если вы не хотите выполнить калибровку для микрофона вашей конкретной модели устройства или внешнего микрофона (и убедитесь, что обработка звука / AGC отключена), вы можете считать уровни звука произвольно масштабированными. Кроме того, отклик также зависит от направленности микрофона и частоты звука.

  4. Центральная точка для 16-битных аудиосэмплов обычно равна 0 (диапазон от -32k до 32k). Нет смещения.

...