POV-Ray Pluck a string Ingo 2021-04-09
This is a short one. Fill a buffer with white noise and go from there. But first,
A word of warning
MIND YOUR EARS!
Experiments with sound synthesis can create extremely loud and nasty sounds.
Don't use headphones! Turn your amps down! Build attenuators into your scripts!
Check the resulting waveform in an audio editor before listening. Audacity or Ocenaudio for example. Both support multiple platforms.
A buffer with noise
Take an array, set it to a certain length, fill it with white noise. Put all that inside a macro.
#macro FillRnd(Len) #local Buff = array[Len]; #for(i, 0, Len-1) #local Buff[i] = SRand(Stream); #end Buff #end
The question is what length to use for this macro, how big an array. Lets use a length with a relation to a frequency,
int(sample_rate / frequency).
Loop through the buffer. Use the value in the current position and the one in the previous position. Use them in a simple low pass filter,
decay * (last + current)/2. The result is a plucked string sound like the nylon string on a guitar. This is the Karplus Strong algorithm. There is a wealth on information on the web to modify it in all kind of ways. I've kept it here in its simple state.
#macro KS(Freq, Decay, StateArr, Tick, SRate) #local Len = int(SRate/Freq); #if(Tick=0) #declare StateArr = FillRnd(Len); #end #local i = mod(Tick, Len); #if(i != 0) #local Last = StateArr[i - 1]; #else #local Last = StateArr[Len - 1]; #end #local Current = StateArr[i]; #declare StateArr[i] = Decay * (Last + Current)/2; StateArr[i] #end
An array to keep the buffer in has to be declared before use,
A. When the decay is set at
1, there is none.
0.995 is a good value to start with. To create an audio buffer to write to file later on:
#declare A = array; #declare AudioBuff = array[Samples]; #for(Tick, 0, Samples-1) #declare AudioBuff[Tick] = ( KS(Freq,0.995,A,Tick,SRate) ); #end
The full source is added to POVSound.zip.
How does it look
At a certain moment I wondered what happened in the buffer. Would there be patterns? So I modified the write macro to omit the wave header and write only the 16 bit data. This raw audio file I opened with IrfanView and rotated it. The first left side column of the image is the noise filled buffer. Each column is a next complete cycle of the buffer. For a 100Hz tone the buffer is 441 samples long, the heighth of the image.
The first image is with signed 16 bit data, the second with unsigned 16 bit data. Irfanview seems to clip these. So I did one in POV-Ray. The red colour represents the negative values, the green the positive. Just lots of little spheres.