Как я могу изменить высоту звука / частоту дискретизации звука не в реальном времени?

#objective-c #macos #cocoa #audio #avfoundation

#objective-c #macos #какао #Аудио #avfoundation

Вопрос:

У меня есть звук mp3, который я хотел бы воспроизвести с помощью настроек панорамирования, высоты тона / частоты дискретизации и громкости, установленных один раз (не изменяющихся в реальном времени). В данный момент я использую AVAudioPlayer, который работает, но настройка скорости растягивает время вместо изменения частоты дискретизации, когда более низкие значения приводят к замедлению и снижению звука, а более высокие — к ускорению и повышению звука (что-то вроде скорости ленты). Например, установка частоты дискретизации на 88200 Гц, когда ваш звук на самом деле равен 44100, приведет к его воспроизведению на скорости / высоте 200%. Возможно ли что-то подобное с AVAudioPlayer или есть другой способ добиться этого? Вот что у меня есть на данный момент:

 player=[[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath: @"sound.mp3"] error: nil];
player.volume=0.4f;
player.pan=-1f;
player.enableRate=YES;
player.rate=2.0f;
[player play];
 

Примечание: я не имею в виду метод высоты тона, в котором растяжение времени используется в комбинации, чтобы сохранить длину звука примерно одинаковой, или какие-либо «продвинутые» алгоритмы.

Комментарии:

1. Не похоже, что AVAudioPlayer предоставляет такую функциональность developer.apple.com/documentation/avfoundation/avaudioplayer

2. Изменение скорости воспроизведения не обязательно так просто, как изменение частоты дискретизации. Поддерживается определенное количество частот дискретизации, поэтому вам, вероятно, придется использовать другой подход. Самый очевидный способ, о котором я могу думать, — это использовать аудиоустройство, которое интерполирует значения выборки, либо уменьшая, либо добавляя значение соответственно

3. @fdcpp Есть ли другой способ, которым я могу это сделать? Возможно, другой класс? Другой фреймворк?

4. Если это не в реальном времени, вы можете использовать аудиофайл, получить сэмплы, применить интерполяцию, сохранить новый аудиофайл и воспроизвести его.

5. Для фреймворков: JUCE, возможно, слишком жесток. OpenAL мог бы это сделать, но он старомоден. AudioUnits, похоже, является наиболее вероятным претендентом

Ответ №1:

AVAudioEngine может задать вам высоту звука, скорость, панорамирование и регулятор громкости:

 self.engine = [[AVAudioEngine alloc] init];

NSError *error;

AVAudioPlayerNode *playerNode = [[AVAudioPlayerNode alloc] init];
AVAudioMixerNode *mixer = [[AVAudioMixerNode alloc] init];
AVAudioUnitVarispeed *varispeed = [[AVAudioUnitVarispeed alloc] init];

[self.engine attachNode:playerNode];
[self.engine attachNode:varispeed];
[self.engine attachNode:mixer];

[self.engine connect:playerNode to:varispeed format:nil];
[self.engine connect:varispeed to:mixer format:nil];
[self.engine connect:mixer to:self.engine.mainMixerNode format:nil];

BOOL result = [self.engine startAndReturnError: amp;error];
assert(result);

AVAudioFile *audioFile = [[AVAudioFile alloc] initForReading:url error:amp;error];
assert(audioFile);

// rate amp; pitch (fused), pan and volume controls
varispeed.rate = 0.5; // half pitch amp; rate
mixer.pan = -1;       // left speaker
mixer.volume = 0.5;   // half volume

[playerNode scheduleFile:audioFile atTime:nil completionHandler:nil];
[playerNode play];
 

Если вы хотите отдельное управление скоростью и высотой звука, замените AVAudioUnitVarispeed узел на AVAudioUnitTimePitch узел.

Комментарии:

1. Это, безусловно, лучший способ достичь желаемого результата. Единственное дополнение, которое я могу предложить, — это связать высоту звука с частотой с pitch.pitch = 1200 * log2(pitch.rate)

2. Спасибо @fdcpp Я был слишком ленив, чтобы сделать этот шаг

3. @Rhythmic Fistman Большое вам спасибо! Это работает отлично, за исключением того, что изменение высоты звука приводит к растягиванию во времени, т. Е. Звук не замедляется и не ускоряется при изменении высоты звука, даже если оставить его на скорости по умолчанию. Я бы ожидал, что высота звука -1200 будет примерно в два раза медленнее, чем исходная высота звука и т.д. Это то, что должна делать формула 1200 * log2 (pitch.rate)?

4. Да! Попробуйте это.

5. Ах, подождите, вы можете захотеть AVAudioUnitVarispeed . Одна секунда, обновление ответа.