Saturday, January 15, 2011

Shepherd tones

I took a crack at making some Shepherd tones today, for a tune I'm working on. (He's trying to do trance! Run! Hide!) Shepherd tones are a form of audio illusion; they are supposed to give the impression of a tone that rises or falls forever without ever moving out of the audio range. This is often referred to as a "barber pole" effect; Shepherd tones are one mechnism for creating it. I had hunted around for some Shepherd tone samples on the Internet, and until today I had not had much luck; in most of the examples I found, either the "cycling" was obvious (it sounded like they rose/fell to a certain point and then obviously started over), or there was no sensation of moving pitch at all. I tried copying and running the example given in the Csound manual, which employs frequency shifting, but all I got out of it was phase cancellation (sounding like pulse width modulation of a square wave).

So I decided to code up my own algorithm in Csound. I chose to build the tone out of six sine waves, at intervals of an octave. Each time rises six octaves before it is faded out. I wrote the code to gradually increase the frequency exponentially, so that it is constant-time with respect to octaves (in other words, it takes the same amount of time to go from one octave to the next at low and high frequencies). Below is my code -- first, the orchestra code:

sr = 44100
kr = 4410
ksmps = 10
nchnls = 1

1nstr 1

ifreq = 200 ; base freq * 2
idur = p3
iatk = p3 / 5
irel = p3 / 5
ireps = p4 - 1

kruntime init 0
; At the octave break point, start the next one
if kruntime < 1 kgoto keepgoing
schedwhen 1, 1, 0, idur, ireps

; If repeat count has decremented to 0, do nothing
if p4 > 0 kgoto dontquit

; Compute the exponentially rising frequency
; (necessary to make it linear with respect to half-steps per second)
ktime line 0, idur, idur
kruntime line 0, (idur/6), 1
kexp = ktime/(idur/6)-1
kpower = powoftwo(kexp)
kfreq = ifreq * kpower

;Envelope and Oscillator
kenv linen 1, iatk, idur, irel
aout oscil3 6000*kenv, kfreq, 1

; Output it
out aout


And now the score file:

; Sine
f 1 0 16385 9 1 1 0

t 0 60

; inst start duration reps
i 1 0 30 20

Most of this is pretty straightforward to someone with just a bit of experience with Csound. The "powoftwo()" function is a bit weird since it only takes arguments in the range -5 to +5, so a bit of finagling was needed there. The tricky bit is that the score file only plays the first tone. After it has increased in frequency one octave, it uses the "schedwhen" to create a dynamic score event that starts the next tone. The line opcode and the kruntime variable do the timing for when to kick off the next tone. There is a repetition count given in the original score event that is decremented every time a new tone kicks off, and when it decrements to zero, the code quits generating new tones, which eventually brings the whole thing to an orderly end. I originally had the test of kruntime at the end of the code block, and I found that I had timing problems -- with the arguments given, the next tone kicked off a few milliseconds either early or late, depending on what value I used for the kr rate. That created noticable beating between the tones because the intervals between them weren't exact octaves. Once I moved the kruntime test to the start of the block, the timing was dead on after that.

I had Csound render this to a file, which created two minutes' worth of audio. I then loaded it up into two channels in Metro and panned the two hard left and right. I offset the start time of the right channel. Then I ran both through the Expert Sleepers phase shifter plug-in. Then, to give them more presence, I ran them through an ambient (small room reverb) algorithm on my Lexicon MPX500 and re-recorded the result to a stereo channel. Here is a brief sample of the result.

I think the results are pretty decent. The cycling isn't too terribly obvious, once all six tones get kicked off and running. I'm going to experiment with it more Based on some Youtube videos I watched today, I'm not sure there is anything special about the octave interval (contrary to theory); I'm thinking many closely spaced tones would produce a better effect with less noticable cycling. But I'm going to use what I've got for the tune I'm working on.

No comments: