Common Lispの勉強をしていて、簡単なプログラムを再実装しています。数年前にJuliaで書いた「周波数を与えると音名・セント値が返ってくる関数」をLispに移植してみました。Julia版は以下の記事に書いてあります。
やっていることはJulia版と同じですし、あまり難しいことはしていないのでコードだけ張り付けておきます。(アルゴリズムの説明はJulia版の記事を読んでください)
(defun freq-to-midicent (frequency &optional (concert-pitch 440)) "Convert frequency (Hz) to MIDI cent value (MIDI note number times 100 for representing partial pitch). `(floor (/ (freq-to-midicent 262) 100))` can be used to get MIDI note number and cent value separately." (+ 6900 (* 1200 (log (/ frequency concert-pitch) 2)))) (defun freq-to-notename (freq &optional (concert-pitch 440) (flat nil)) "Convert frequency (Hz) to note name with standard octave number (center C = 4). The boundary between octaves lies between the notes B and C." (let* ((notenames-flat '("C" "Db" "D" "Eb" "E" "F" "Gb" "G" "Ab" "A" "Bb" "B")) (notenames-sharp '("C" "C#" "D" "D#" "E" "F" "F#" "G" "G#" "A" "A#" "B")) (mc (freq-to-midicent freq concert-pitch)) (notenum (round (/ mc 100))) (notecent (round (* (- (/ mc 100) notenum) 100))) (noteoct (floor (1- (/ notenum 12))))) (format nil "~A~A~@D" (nth (mod notenum 12) (if flat notenames-flat notenames-sharp)) noteoct notecent)))
下のように使います。ピアノ鍵盤の中央のC音のオクターブ番号を4としています(アメリカ音響学会などのピッチ表記に合わせています)。また、デフォルトのコンサートピッチは440 Hzで、シャープ記号を使った音名表示にしています。
CL-USER> (freq-to-notename 1000) "B5+21" ;; 1000 Hzの音名はB、オクターブ番号は5、ちょうどピッタリから21セント上 CL-USER> (freq-to-notename 270) "C#4-45" ;; 270 Hzの音名はC#、オクターブ番号は4、ちょうどピッタリから45セント下 CL-USER> (freq-to-notename 270 442) "C4+47" ;; コンサートピッチを442 Hzにしたとき CL-USER> (freq-to-notename 270 440 t) "Db4-45" ;; コンサートピッチを440 Hzにして、シャープではなくフラット表示にしたとき