方法
AVAudioUnitSampler
を用いてMIDIと同種のノートを鳴らすことができる。複雑なことはしたくないけど、とにかく単音を任意の時間鳴らしたいという場合に有効。ただし、SoundFontを使わないと音の停止時に微妙にノイズが入る。
import AVFoundation
class Sampler {
let audioEngine = AVAudioEngine()
let unitSampler = AVAudioUnitSampler()
init() {
audioEngine.attach(unitSampler)
audioEngine.connect(unitSampler, to: audioEngine.mainMixerNode, format: nil)
try? audioEngine.start()
}
deinit {
if audioEngine.isRunning {
audioEngine.stop()
audioEngine.disconnectNodeOutput(unitSampler)
audioEngine.detach(unitSampler)
}
}
func play() {
// 一つ目の引数はMIDIのNote番号60は基本のド
// withVelocityは音量に関係する値 0 ~ 127
// onChannelはチャンネルを構成しないなら基本0
unitSampler.startNote(60, withVelocity: 80, onChannel: 0)
}
func stop() {
unitSampler.stopNote(60, onChannel: 0)
}
}
let sampler = Sampler()
// 音を再生
sampler.play()
// 音を停止
sampler.stop()
SoundFontを使う場合
音質は使うSoundFontファイルに依存するが、基本的には終了時のノイズはなくなるので綺麗に音を鳴らすことができるようになる。例えば、よくあるピアノ音源のSoundFontファイルは100MB〜300MBくらいあるので、アプリの容量を抑えたい場合は軽量なSoundFontを探すか、自作するといいかもしれない。
init() {
audioEngine.attach(unitSampler)
audioEngine.connect(unitSampler, to: audioEngine.mainMixerNode, format: nil)
if let _ = try? audioEngine.start() {
loadSoundFont()
}
}
func loadSoundFont() {
guard let url = Bundle.main.url(forResource: "SoundFontファイル名", withExtension: "sf2") else { return }
try? unitSampler.loadSoundBankInstrument(
at: url, program: 0,
bankMSB: UInt8(kAUSampler_DefaultMelodicBankMSB),
bankLSB: UInt8(kAUSampler_DefaultBankLSB)
)
}