2015/01/14

ピッチ計測 セント表示 Nyquist

Audacityにはチューナのような手軽に音程を計測するツールがなく、周波数スペクトルで計測することになる。ピークの周波数と音程の確認ができるので悪くないのだが、音程のズレは計算する必要が出てしまう。 そこで手軽に音程を計測するチューナーのようなものをNyquistで作ってみた。知りたいのは音程のズレなので、セント表示もできるようにした。精度はそれほど高くはないが、使えなくもないという感じ。 プログラムは0から作るとなるとNyquistとLispの復習が必要なので、手っ取り早く公式の Pitch Detect を改造してみた。久しぶりにやるとLispの括弧地獄はやはり馴染めない。

使い方

計測したい箇所を選択し、AudacityのAnalyzeメニューから Namagi:Pitch を選択。

そうすると以下のようなウィンドウが表示され、そこに計測結果が表示される。
ノートナンバーと周波数。それとセント表示で、どれぐらいのズレがあるかを確認できるようにした。


ピッチ測定プログラム ソース Nyquist

;nyquist plug-in
;version 1
;type analyze
;name "Namagi:Pitch..."
;action "Namagi:Pitch..."
;info ""

(setq range (psetq min-hz 30 max-hz 2000))
(psetq minstep (hz-to-step min-hz)maxstep
(hz-to-step max-hz))
(setq calib 440)
(setq dur 0.5)
(setq err "")
(setq f0 nil)
(setq confidence 1)

;;;;;; Error check ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(when (< (get-duration 1) 0.1)
(setf err "Selection too short."))

;;;;;; note name ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun notename (step)
   (let ((notenames 
   (list "C" "C sharp" "D" "D sharp" "E" "F"
   "F sharp" "G" "G sharp" "A" "B flat" "B"))
   (step (round step)))
   (format nil "~a ~a"
   (nth (rem step 12) notenames)
   (truncate (/ (- step 12) 12)))))

;;;;;; format ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun prettyfrequency (val)
    (setq val
    (cond
    ((<= range 1) (round val))
    ((< val 10000)
    (setq *float-format* "%1.2f")(/ val 1000.0))
    (T (setq *float-format* "%1.1f") (/ val 1000.0))))
    (format nil "~a Hz" val ))

;;;;;; DUR seconds ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun getyin (sig dur)
    (let ((srate (min *sound-srate* (* 8 max-hz))))
    (if (< srate *sound-srate*)
    (progn
    (setf sig
    (if (arrayp sig)
    (sum
    (extract-abs 0 dur (force-srate srate (aref sig 0)))
    (extract-abs 0 dur (force-srate srate (aref sig 1))))
    (extract-abs 0 dur (force-srate srate sig))))
    (setq srate (snd-srate sig)))
    (setf sig
    (if (arrayp sig)
    (sum
    (extract-abs 0 dur (aref sig 0))
    (extract-abs 0 dur (aref sig 1)))
    (extract-abs 0 dur sig))))
    (let ((stepsize (truncate (/ (* 4 srate) min-hz))))
    (yin sig minstep maxstep stepsize))))

;;;;;; frequency ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun bestguess (yin-out)
    (do ((step (snd-fetch (aref yin-out 0))
    (snd-fetch (aref yin-out 0)))
    (conf (snd-fetch (aref yin-out 1))
    (snd-fetch (aref yin-out 1))))
    ((not step))
    (when (and (= conf conf)
    (< conf confidence))
    (setq confidence conf)
    (setq f0 step)))f0)

;;;;;; print ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(if (> (length err) 0)
    (format nil "Error.~%~a" err)
    (let ((f0 (bestguess (getyin s dur))))
    (if f0
    (format nil 
    "Note: ~a~%~
    Frequency: ~aHz~%~
    cent: ~a~%"
    (notename f0)
    (step-to-hz f0)
    (write-float ;write-float,write-int
    (*
    (-
    (round(* (/ (log (/ (step-to-hz f0) calib))
    (log 2.0)) 12.0))
    (* (/ (log (/ (step-to-hz f0) calib))
    (log 2.0)) 12.0)) -100)))
    "Frequency cannot be detected.")))