Извлечение данных амплитуды из линейного PCM на iPhone

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

Мои вопросы:

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

и бонусный вопрос: существуют ли звуковые/воздушные волны давления, которые микрофон 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);

С этим кодом я почти всегда получаю min 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, поэтому не стесняйтесь оторвать мой подход!

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

P.P.S. Я посмотрел:

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 и большую часть руководства по программированию аудиозаписей, но мои вопросы остаются.

Ответ 1

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 dBFS; например если вы выводите поток прямо на ЦАП, то int max (или -1/1, если с плавающей запятой) представляет уровень, на котором будет кликать отдельный образец.

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

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

Ответ 2

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

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

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

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