Планирование нескольких уровней громкости для воспроизведения AVAudioPlayerNode
У меня есть аудиофайл на диске, который я воспроизводю с помощью AVAudioPlayerNode, например:
AVAudioFile *playbackFile = [[AVAudioFile alloc] initForReading:audioUrl error:&fileError];
[self startEngine];
[playerNode scheduleFile:playbackFile atTime:nil completionHandler:^{}];
[playerNode play];
У меня также есть то, что я называю "временной шкалой объема", которая в основном представляет собой массив кортежей. Первое значение кортежа - это число с плавающей точкой, представляющее количество секунд между 0 и длительностью файла. Другое значение кортежа - логическое значение, представляющее, должно ли аудио быть уменьшено до значения "секунд" этого кортежа. В качестве простого примера ниже приводится временная шкала для 3-секундного аудиофайла, где громкость должна быть уменьшена в течение первой и последней секунд воспроизведения:
-----------------------------------
| shouldRampDown | playbackSeconds|
-----------------------------------
| 1 | 0.0 |
| 1 | 0.1 |
| 1 | 0.2 |
| 1 | 0.3 |
| 1 | 0.4 |
| 1 | 0.5 |
| 1 | 0.6 |
| 1 | 0.7 |
| 1 | 0.8 |
| 1 | 0.9 |
| 1 | 1.0 |
| 0 | 1.1 |
| 0 | 1.2 |
| 0 | 1.3 |
| 0 | 1.4 |
| 0 | 1.5 |
| 0 | 1.6 |
| 0 | 1.7 |
| 0 | 1.8 |
| 0 | 1.9 |
| 1 | 2.0 |
| 1 | 2.1 |
| 1 | 2.2 |
| 1 | 2.3 |
| 1 | 2.4 |
| 1 | 2.5 |
| 1 | 2.6 |
| 1 | 2.7 |
| 1 | 2.8 |
| 1 | 2.9 |
| 1 | 3.0 |
-----------------------------------
Я использую эту временную шкалу для увеличения громкости при построении AVMutableComposition
, но теперь я хочу использовать ту же технику линейного изменения для воспроизведения живого аудио. Мое текущее решение состоит в том, чтобы установить кран на узле проигрывателя непосредственно перед воспроизведением, сравнить AVAudioTime
к значениям моей временной шкалы и установите громкость узла игрока вручную:
[playerNode installTapOnBus:0 bufferSize:4096 format:[playerNode outputFormatForBus:0] block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
NSTimeInterval seconds = [AVAudioTime secondsForHostTime:when.hostTime];
double volumeForTime = // check the timeline for if the volume should be ramped or not
playerNode.volume = volumeForTime;
}];
Это решение не является идеальным по многим причинам. Во-первых, я не могу контролировать, как часто installTapOnBus
Блок обработчика называется (installTapOnBus
кажется игнорировать bufferSize
параметр полностью: я хочу вызывать 20 раз в секунду метод installTapOnBus: bufferSize: format: block:), который может привести к проблемам синхронизации с линейными изменениями громкости в зависимости от значений "секунд" в моей временной шкале. Во-вторых, изменение громкости является "жестким" вместо постепенного изменения, обеспечиваемого AVMutableAudioMixInputParameters
"s setVolumeRamp
метод. Я мог бы вручную реализовать постепенное изменение громкости внутри installTapOnBus
обработчик, но это потребовало бы немного больше работы для чего-то, на что я надеюсь AVAudioEngine
может справиться внутренне.
Буду очень признателен за любые идеи о том, как это сделать (или улучшить мой нынешний метод). Я видел несколько ссылок на AVAudioUnitEQ
это упоминание об изменении громкости во время воспроизведения узла, но документация / примеры кажутся очень скудными. Спасибо за любую помощь или предложения