ボイチェンみたいに音声を高くしたり低くしたり、速くしたり遅くしたりできます。
変換した音声をファイルに書き込むこともできます。
#手順
音声ファイルから読み込んだ音声を変換します。
###1.AVAudioEngine を初期化
var audioEngine = AVAudioEngine()
###2.AVAudioEngine に音声ファイルを流し込む PlayerNode を用意
let playerNode = AVAudioPlayerNode()
let audioFile = try! AVAudioFile(forReading: audioFileURL) // URLからファイル読み込み
playerNode.scheduleFile(audioFile, at:nil) // playerNodeにファイルをセット
###3.音声を変換する AVAudioUnitTimeEffect を用意
let audioUnitTimePitch = AVAudioUnitTimePitch()
audioUnitTimePitch.pitch = 1200 // 1200で1オクターブ高くなる。可能な値は -2400 ~ 2400
###4.AudioEngine に PlayerNodeとAudioUnitTimeEffect を取り付けて接続
|==================AudioEngine================|
PlayerNode → AudioUnitTimePitch → OutputNode
|============================================|
// 取り付け
audioEngine.attach(playerNode)
audioEngine.attach(audioUnitTimePitch)
// 接続
audioEngine.connect(playerNode, to: audioUnitTimePitch, format: audioFile.processingFormat)
audioEngine.connect(audioUnitTimePitch, to: audioEngine.outputNode, format: audioFile.processingFormat)
###5.音声を流し込む
変換された音声が再生されます。
匿名インタビューみたいな声になります。
try! audioEngine.start()
playerNode.play()
###6.変換した音声をファイルとしてエクスポート
AudioUnitTimePitch にタップ(蛇口)というのを取り付けて、音声バッファを取り出してファイルに書き込みます。
|==================AudioEngine================|
PlayerNode → AudioUnitTimePitch → OutputNode
↓ Tap(蛇口)
|============================================|
Tap をつけるのは AudioUnitTimePitch ですが、その後の OutputNode も一応つけておかないと動かないようです。
// 書き込み先ファイルをつくる
let outputFile = try! AVAudioFile(forWriting: outputURL, settings: audioUnitTimePitch.outputFormat(forBus: 0).settings)
// タップ(蛇口)をつけてバッファを取り出してファイルに書き込み
audioUnitTimePitch.installTap(onBus: 0, bufferSize: AVAudioFrameCount(audioUnitTimePitch.outputFormat(forBus: 0).sampleRate), format: audioUnitTimePitch.outputFormat(forBus: 0)) { (buffer, when) in
do {
try outputFile.write(from: buffer)
} catch let error {
print(error)
}
}
書き込みを終了するにはタップ(蛇口)を取り除く必要があります。
PlayerNode が再生し終わった時に書き込み終了したいので、上記手順2.の PlayerNode に音声ファイルをセットするときに、完了した時に呼ばれる完了ハンドラーを仕込んでおきます。録音するときは以下のよう書き換えます。
playerNode.scheduleFile(audioFile, at:nil, completionCallbackType: .dataPlayedBack) { [self] _ in // 再生完了時に呼ばれる
audioUnitTimePitch.removeTap(onBus: 0) // これで書き込み終了の合図を送る。書き込みには音声の長さによって数秒かかります。
}
###エフェクトの種類
それぞれ使い方は上記のピッチ変更の例と同じです(AudioEngine にアタッチして、接続)。
ディレイとディストーションとリバーブとイコイライザーはマイクからのリアルタイム音声に適用できます。
AVAudioUnitTimePitch と AVAudioUnitVarispeed はファイル音声しか無理みたいです。
AVAudioUnitTimePitch
プロパティ | 効果 | 値 |
---|---|---|
overlap | 入力オーディオ信号のセグメント間のオーバーラップの量 | Float |
pitch | 高さ | Float |
rate | 速さ | Float |
AVAudioUnitVarispeed
プロパティ | 効果 | 値 |
---|---|---|
rate | 高さの変化を伴った速さの変化 | Float |
AVAudioUnitEQ
プロパティ | 効果 | 値 |
---|---|---|
bands | 周波数帯 | [AVAudioUnitEQFilterParameters] |
globalGain | 増幅 | Float |
AVAudioUnitDistortion
プロパティ | 効果 | 値 |
---|---|---|
loadFactoryPreset | プリセットのディストーション(エイリアンの声とか) | AVAudioUnitDistortionPreset |
preGain | 増幅 | Float |
wetDryMix | 歪み具合 | Float |
AVAudioUnitDelay
プロパティ | 効果 | 値 |
---|---|---|
delayTime | 遅延時間 | Float |
feedback | フィードバック | Float |
lowPassCutoff | これ以上の周波数をカット | Float |
wetDryMix | ウェット信号とドライ信号のブレンド具合 | Float |
AVAudioUnitReverb
プロパティ | 効果 | 値 |
---|---|---|
loadFactoryPreset | プリセットの音の広がり(大きなホールなど) | AVAudioUnitReverbPreset |
wetDryMix | ウェット信号とドライ信号のブレンド具合 | Float |
🐣
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com
Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。