The proportional relationship between any two adjacent pitches in a normal scale (12 tone equal temperament) is the 12th root of 2.
There’s various ways that this may be calculated in Nyquist, but one easy method is:
(expt 2 (/ 12.0))
(note that we need 12.0 as a float so as to avoid division by zero error)
So if we have a frequency of 440 Hz (A4) and we want to calculate the frequency of the note that is one semi-tone higher (A#4)
(* 440 (expt 2 (/ 12.0)))
which is approximately 466.16
To calculate the frequency 2 semi-tones above 440 we need to calculate ((semi-tone)^2) and multiply that by our base frequency of 440
so this gives us:
440 * [{(2 ^ (1/12)} 2]
which in Nyquist we can write as:
(* 440 (expt (expt 2 (/ 12.0)) 2.0))
so the general formula for ‘n’ semitones above a base frequency ‘f0’ can be written as a function:
(defun fcalc (f0 n)
(* f0 (expt (expt 2 (/ 12.0)) n)))
There’s a table here that can help to check that the results are correct http://www.phy.mtu.edu/~suits/notefreqs.html
However, Nyquist has been written specifically with music in mind, so for many applications there is an even easier way.
Nyquist provides two functions:
(hz-to-step) and (step-to-hz)
As a convention that is used in the MIDI 1.0 specification, the note A4 (which is the standard pitch that orchestras tune to and almost everything else uses as the tuning reference) is assigned the number 69 and corresponds to the frequency 440 Hz.
(step-to-hz 69) ; returns 440.0
(hz-to-step 440) ; returns 69
so to calculate the frequency 2 semitones above 440 Hz we can use:
(step-to-hz (+ 2 (hz-to-step 440)))
To write this as a general function for ‘n’ semitones above a base frequency ‘f0’
(defun fcalc2 (f0 n)
(step-to-hz (+ n (hz-to-step f0))))
Either of these (fcalc) or (fcalc2) functions can be useful where regular pitch spacing is required, for example, to calculate frequencies in the range 20 Hz to (over) 20 kHz that are (approximately) evenly spaced in 1/3 octave intervals:
1/3 octave is 4 semi-tones (12 semi-tone steps to an octave) so we can iterate through a loop:
(defun fcalc (f0 n)
(step-to-hz (+ n (hz-to-step f0))))
(setf frequency-list
(do* ((count 0 (setq count (1+ count)))(freq 20)(flist (list freq)))
((> freq 20000)(reverse flist))
(setq freq (round (fcalc freq 4)))
(setf flist (cons freq flist))))
(format NIL "~a" frequency-list)