発端
好きな曲のハーモニカを吹きたいのだが採譜がめんどくさいという万人に共通の悩み、、、ありますよね。
例えば Jukeはハーモニカ界のスタンダードですけど、これの冒頭(チャララララーラッ♪)はもちろん**+3-3-4-5-6**です。
このフレーズなら皆さん暗譜していることでしょう。。。しかしこんな調子で1フレーズ毎に耳コピしてたら日が暮れるっちゅーことで自動採譜ツールを作り、、、作ろうとしました。
ベートーベン
ちゅーことで、iphoneのマイクに聞かせてフレーズを自動で作らせればええやん、swiftも勉強できるし一石二鳥!!ということでswiftのライブラリを漁ったところ、ありました。Beethovenです。最初ビートバンと読んだのは内緒です。何かと思いました。。。
Beethoven is an audio processing Swift library that provides an easy-to-use interface to solve an age-old problem of pitch detection of musical signals. You can read more about this subject on Wikipedia.
ということで今回やりたいことに一致しているようにみえます。やったぜ。
ハマる
readmeを読み始めたあたりでなんかシグナルトラッキングとかEstimationとか、よく分からん単語が乱立しており、これは大変な沼にハマってしまったなぁという感想。
しかし作者の方が大変気が利くようでして、Exampleを用意してくれていました。ありがとう、マジありがとう。CocoaPodsとかなんか良く分からんswift環境周りのアレに翻弄されながらもなんとかビルドしコードを読む。ふむ。
キモ
ViewController.swiftの中、メンバ変数pitchEngineの生成箇所と、その使用箇所がキモのようです。
lazy var pitchEngine: PitchEngine = { [weak self] in
let config = Config(estimationStrategy: .yin)
let pitchEngine = PitchEngine(config: config, delegate: self)
pitchEngine.levelThreshold = -30.0
return pitchEngine
}()
コード見りゃ分かるんですが、Configにバッファサイズと評価方式(多分解析精度に絡むやつ)を渡します。もうここを突っ込んでいくと窓関数とかフーリエ変換とか、大学の時にもっとちゃんと勉強しておくべきだったことがいっぱい出てきます。あれ、大事だったんだなぁって。。。留年、してる場合じゃなかったなぁって。
func pitchEngine(_ pitchEngine: PitchEngine, didReceivePitch pitch: Pitch) {
noteLabel.text = pitch.note.string
let offsetPercentage = pitch.closestOffset.percentage
let absOffsetPercentage = abs(offsetPercentage)
print("pitch : \(pitch.note.string) - percentage : \(offsetPercentage)")
guard absOffsetPercentage > 1.0 else {
return
}
let prefix = offsetPercentage > 0 ? "+" : "-"
let color = offsetColor(offsetPercentage)
offsetLabel.text = "\(prefix)" + String(format:"%.2f", absOffsetPercentage) + "%"
offsetLabel.textColor = color
offsetLabel.isHidden = false
}
白状しますとDelegateパターンをよく理解していないのでこの関数がどういう経緯で動くのかがぼんやりしているのですが、ここでpitchEngineで評価した結果をいじいじして使っています。引数pitchには評価結果が入ってきます。
後はこの結果を元にいい感じに画面表示を行えば難しくない。
という訳でいい感じの採譜ツールができました。
、、、の、はず。だったのですが。。。
倍音問題
どーーーーも良くわからないのですが、高音を鳴らすと一オクターブ下の音を誤検出してしまいがちなんですよね〜〜〜〜うーーーーん。。。
ウェッブで調べたところによると、自己相関関数とかいう的な何かを使えば良いかもしれないと思われるのですが全く分からずです、はい。
という訳でなんか別のやり方を勉強しなきゃな〜と感じています。難しぃ。