This sound reminds me of the effect of dragging a needle across a vinal record.
(defun ring (dur pch scl) (let ((modstep1 (hz-to-step (* (step-to-hz pch) (sqrt 2.0)))) (modstep2 (hz-to-step (* (step-to-hz pch) (sqrt 11.0))))) (stretch dur (mult (env 0.05 0.1 0.2 1 0.6 0.24 1) (fmosc pch (mult (pwl 0.07 1800 0.15 1000 0.4 680 0.8 240 1 100 1) scl (osc modstep1) (osc modstep2) ))) )))
The following plays an example sound from this function:
(play (ring 7.1 (hz-to-step 1) 1.2))
Here is a brief description of how this function works: The sound is created by an FM
oscillator. The modulation comes from two sinusoids operating at low frequencies
multiplied together. The sinusoids are not harmonically related, so an irregular pulse is
generated by their product. This is scaled further by a piece-wise linear envelope that
adds more variation. To make the sinusoids inharmonically related, their frequencies are
scaled by the square root of 2 and the square root of 11. The variables modstep1
and modstep2
are initialized to these computed frequencies.
The following example combines several instances of ring
with different
parameters:
(play (sim (scale 0.15 (at 2.9 (ring 7.1 (hz-to-step 1) 1.2))) (scale 0.175 (at 4.9 (ring 5.1 (hz-to-step 2) 1.414))) (scale 0.2 (at 6.9 (ring 3.1 (hz-to-step 4) 1.8)))))
The same ring
function can be used to achieve other sounds. Listen to
these examples:
(play (sim (scale 0.35 (at 1.5 (ring 4 1 1))) (scale 0.325 (at 4 (ring 4 4 2))) (scale 0.3 (at 7.5 (ring 4 10 4))) ))
These instances use a higher pitch parameter than the previous ones.
The following creates a sound using FM and a wave table derived from a vocal sound.
(defun vocrap (&optional (pch 16) (dur 1)) (if (not (boundp '*voc-table1*)) (mk-voc1-table)) (fmosc pch (stretch dur (pwl 0 3 0.1 -20 0.2 20 0.3 30 0.4 -10 0.5 15 0.6 0 0.8 -30 1 60 1)) *voc-table1*))
This function uses a special test to make sure that *voc-table1*
is
initialized. If it is not, it would be an error to read or test it, but you can query to
find out if the variable is bound or unbound. (Global variables become bound when you
assign a value to them.) The boundp
function takes an atom (note the use of
the single quote to denote an atom, the name of the variable, rather then the variable's
value) and returns true if the variable is bound.
Here is the definition for mk-voc1-table
. You might have to replace the
filename depending upon how your system is configured.:
(defun mk-voc1-table () (if (not (boundp 'voc-snd1)) (setf voc-snd1 (s-read "./test/voc1.snd"))) (setf *voc-table1* (list voc-snd1 16 T)))
The following shows one way to invoke vocrap
:
(play (seqrep (i 4) (vocrap)))