#ios #swift #avaudiorecorder
#iOS #swift #avaudiorecorder
Вопрос:
Я создал UIView, который отображает форму волны через ввод значений с плавающей запятой. Я хочу, чтобы мое представление отображало форму сигнала звука, записанного через микрофонный вход, во время его записи. Я изучил некоторые фреймворки, но, похоже, не могу найти ни одного, который бы делал это так, как я упоминал, и у меня возникают некоторые проблемы с моей реализацией. Я использую:
audioRecorder = try AVAudioRecorder(URL: soundURL, settings: settings)
audioRecorder.meteringEnabled = true
audioRecorder.recordForDuration(NSTimeInterval(20.0))
И затем:
audioRecorder.updateMeters()
//this turns dBFS to a linear value from 0 to 1
let x = pow(10.0, ( Double(audioRecorder.peakPowerForChannel(0))/20 ))
//here I add the new meter value to my plotter view
waveForm.addnewValue(x)
Как вы можете видеть по ссылке ниже, есть много простых областей, не только в области «отсечения», но и на более низких уровнях. Я предполагаю, что это происходит из формы, в которой peakPowerForChannel()
возвращает свои значения «метрическим» способом, сглаживая весь вывод.
https://i.stack.imgur.com/vuTCG.jpg
Мне не нравится такой способ построения аудио, потому что я хотел бы получить что-то вроде:
https://i.stack.imgur.com/eSOtV.png
Получая фактические значения с плавающей запятой для записываемых сэмплов, я полагаю, я могу получить фактические значения, соответствующие амплитуде каждого сэмпла, и получить результат, более похожий на то, что я ищу.
Спасибо за вашу помощь!
После внедрения таймера отправки, предложенного Робом Нейпиром, и изменения делителя в моей dBFS на линейное преобразование, единственное, что я получил, — это более сжатый по вертикали сигнал, не достигающий вообще того эффекта, который мне действительно нужен для моего представления (см. Ссылку выше).
В разных точках все еще есть ровные участки, и, по-видимому, своего рода среднее значение влияет на форму сигнала при переходе от звука к тишине.
Это мой текущий код:
var dTimer: DispatchTimer!
dTimer = DispatchTimer(seconds: 0.1) {
self.audioRecorder.updateMeters()
let x = pow(10.0, (Double(self.audioRecorder.peakPowerForChannel(0))/50))
self.waveForm.addnewValue(x)
}
Вопрос в следующем: есть ли способ получить значения, записываемые AVAudioRecorder, чтобы я мог установить эти значения в качестве значений для моего волнового плоттера?
Комментарии:
1. Посмотрите
averagePower
, а неpeakPower
. Вероятно, вы не хотите пытаться работать с 20-40 тысячами выборок в секунду (и обрабатывать данные в режиме реального времени, чтобы избежать помех записи), просто чтобы рисовать малоинформативные кривые. Если вы действительно это сделаете, вам, вероятно, придется перейти к Core Audio, а не использовать высокоуровневые интерфейсы, такие как AVAudioRecorder. Как часто вы звонитеupdateMeters
? Возможно, вы вызываете слишком часто или недостаточно часто (или не последовательно).2. Я уже использовал
averagePower
, но результаты очень похожи. Я вызываюaudioRecorder.updateMeters()
,let x = pow(10.0, ( Double(audioRecorder.peakPowerForChannel(0))/20 ))
иwaveForm.addnewValue(x)
каждые 0,1 секунды, только 10 раз в секунду3. Что вы используете для сохранения времени?
NSTimer
например, не обещает очень высокой точности. Вы проверяете, сколько сейчас времени на самом деле, и корректируете свое значение x для соответствия? (и это также даст вам знать, если вы дрейфуете.) Я бы также посмотрел на более высокую частоту дискретизации. 10 Гц может быть слишком медленным, чтобы получить нужный график. И вы много обрезаете, поэтому я бы проверил ваши выходные данные и убедился, что они действительно находятся в диапазоне 0-1 (действительно ли пиковая мощность 0 так часто?)4. Я на самом деле использую
NSTimer
. Вы имеете в виду частоту дискретизации для построения графика или фактическую частоту дискретизации звука? Большое количество отсечений связано с тем, что мой график настолько нечувствителен, что мне нужно издавать громкие звуки, чтобы он регистрировал заметное изменение амплитуды сигнала…5. Я имею в виду, как часто срабатывает ваш таймер. И если у вас возникли проблемы с усилением, не делите на 20. Разделите на 40 или 80 (или умножьте конечный результат на что-то). Вы контролируете свой масштаб. Технически умножение немного точнее, но настройка вашего логарифмического / линейного преобразования может на самом деле масштабироваться намного больше по вашему вкусу.