; En Garde! (Drawing a sword: precedural audio)
; Iain McCurdy, 2017
; Drawing Sword (groupbox)
; ------------------------
; Density - roughness of the texture of the sword
; Draw duration - time taken to draw the sword from the scabbard
; Freq.1 [start]/Freq.1 [end]
; Freq.2 [start]/Freq.2 [end]
; - start and end frequencies for the plate modelling for the drawing of the sword sound
; Feedback - basically the inverse of the damping of the sword while it is begin drawn
; Draw Gain - amplitude gain of the sword being drawn part of the sound
; Drawing Sword (groupbox)
; ------------------------
; Freq. Base - lowest partial frequency
; Freq. Range - possible extent of frequencies (frequencies are generated randomly)
; Resonance - ring time for when the sword is free of the scabbard
; Seed - defines the particular set of random values that will be generated. A seed value of zero will produce a different sword sound each time it is drawn.
; N.Partials - number of partials of the resonance of the sword
; Ring Offset - amount of random deviation from resonance value defined by 'Resonance' for each partial
; Ring Gain - amplitude gain for the ringing resonance part of the sound
form caption("En garde!") size(600, 310), colour(58, 110, 182), pluginID("EnGa")
button bounds(5,5,590,30) channel("PlaySound") text("Draw Sword") latched(0)
groupbox bounds(5,40,590,130) outlinethickness(1) outlinecolour(200,200,200) colour(0,0,0,100) plant("Drawing") text("Drawing Sword")
{
rslider bounds(5,25,70,90) channel("TexturalDensity") text("Density") valuetextbox(1) range(100,10000,1000,0.5,1)
rslider bounds(75,25,70,90) channel("DrawDuration") text("Duration") valuetextbox(1) range(0.01,2,0.7,0.5,0.001)
image bounds(145,30,295,90) outlinethickness(1) outlinecolour(200,200,200) colour(0,0,0,50) shape("rounded")
hslider bounds(145,35,300,20) channel("Freq1a") text("Freq. 1 [Start]") valuetextbox(1) range(100,3000,300,0.5,0.01)
hslider bounds(145,55,300,20) channel("Freq1b") text("Freq. 1 [End]") valuetextbox(1) range(100,3000,811,0.5,0.01)
hslider bounds(145,75,300,20) channel("Freq2a") text("Freq. 2 [Start]") valuetextbox(1) range(100,3000,717,0.5,0.01)
hslider bounds(145,95,300,20) channel("Freq2b") text("Freq. 2 [End]") valuetextbox(1) range(100,3000,933,0.5,0.01)
rslider bounds(440,25,70,90) channel("Feedback") text("Feedback") valuetextbox(1) range(0.1,0.249,0.17.0)
rslider bounds(510,25,70,90) channel("DrawGain") text("Draw Gain") valuetextbox(1) range(0,2,1,0.5,0.001)
}
groupbox bounds(5,175,590,130) outlinethickness(1) outlinecolour(200,200,200) colour(0,0,0,100) plant("Ringing") text("Ringing")
{
rslider bounds(15,25,70,90) channel("RingFreqBase") text("Freq. Base") valuetextbox(1) range(500,6000,2300,0.5,1)
rslider bounds(95,25,70,90) channel("RingFreqRange") text("Freq. Range") valuetextbox(1) range(500,12000,5000,0.5,1)
rslider bounds(175,25,70,90) channel("Resonance") text("Resonance") valuetextbox(1) range(100,8000,1500,0.5,1)
rslider bounds(255,25,70,90) channel("Seed") text("Seed") valuetextbox(1) range(0,1000,100,1,1)
rslider bounds(335,25,70,90) channel("NPartials") text("N.Partials") valuetextbox(1) range(1,50,10,1,1)
rslider bounds(415,25,70,90) channel("ResOffset") text("Res. Offset") valuetextbox(1) range(0,4,1,0.5,0.01)
rslider bounds(495,25,70,90) channel("RingGain") text("Ring Gain") valuetextbox(1) range(0,2,1,0.5,0.001)
}
-n -d -+rtmidi=NULL -M0 -m0d
; Initialize the global variables.
sr = 44100
ksmps = 32
nchnls = 2
0dbfs = 1
instr 1 ; read button an trigger a note event accordingly
gkPlaySound chnget "PlaySound"
if trigger:k(gkPlaySound,0.5,0)==1 then
event "i",2,0,-1
endif
endin
; UDO for a single resonance partial
opcode PARTIAL,a,aaiiiip
aInSig,aQ,iResFreqBase,iResFreqRange,iResOffset,iNPartials,iCount xin
aPartial mode aInSig, limit:i (exprand(iResFreqRange) + iResFreqBase, 20, sr/$M_PI), aQ * (2 ^ random(-iResOffset,iResOffset))
aMix = 0
if iCount<=iNPartials then
aMix PARTIAL aInSig,aQ,iResFreqBase,iResFreqRange,iResOffset,iNPartials,iCount+1
endif
xout aPartial + aMix
endop
instr 2 ; 'drawing a sword' sound effect
; drawing of the sword part of the sound
iDrawDur chnget "DrawDuration"
iRoughness chnget "TexturalDensity"
kEnv expseg 0.1, 0.3 * (iDrawDur/0.7), 1, iDrawDur-0.4, 1, 0.1 * (iDrawDur/0.7), 0.1,1,0.1
aDraw dust2 0.1*(kEnv-0.1), iRoughness
iFB chnget "Feedback"
aFreq1 expseg chnget:i("Freq1a"),(0.3*(iDrawDur/0.7)) + (iDrawDur-0.4),chnget:i("Freq1b"),1,chnget:i("Freq1b")
aFreq2 expseg chnget:i("Freq2a"),(0.3*(iDrawDur/0.7)) + (iDrawDur-0.4),chnget:i("Freq2b"),1,chnget:i("Freq2b")
aDraw wguide2 aDraw,aFreq1,aFreq2,10000,10000,iFB,iFB
aDraw wguide2 aDraw,aFreq1,aFreq2,10000,10000,iFB,iFB
aDraw dcblock2 aDraw
outs aDraw * chnget:i("DrawGain"), aDraw * chnget:i("DrawGain")
; ringing
seed chnget:i("Seed")
aQ linseg 1, (0.3*(iDrawDur/0.7)) + (iDrawDur-0.4), 1, 0.05, chnget:i("Resonance")
iResFreqBase = chnget:i("RingFreqBase")
iResFreqRange = chnget:i("RingFreqRange") / 5
iNPartials = 10
aRing PARTIAL aDraw,aQ,iResFreqBase,iResFreqRange,chnget:i("ResOffset"),chnget:i("NPartials")
aRing *= chnget:i("RingGain")
outs aRing, aRing
; wait until resonance has died away before turning off instrument
if rms:k(aRing)<0dbfs*0.00001 && timeinsts()>(iDrawDur+1) then
turnoff
endif
endin
i 1 0 z