Extra "ports" of juce-based plugins using the distrho build system
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
8.3KB

  1. Physical model of a plucked string with a pickup point. Model is created from first principles in order to implement some improvements over the existing Csound opcodes for plucked strings.
  2. A bandpass filter is employed within the delay buffer used to implement the pluck which facilitates filtering to specific harmonics. Conventional damping effects are still possible when cutoff frequency ratio = 1.
  3. <Cabbage>
  4. form caption("Bass Guitar"), size(550, 250), pluginID("basg")
  5. image bounds( 0, 0,550,220), colour("DarkGreen"), shape("rounded"), outline("white"), line(4)
  6. groupbox bounds(5, 5, 540,120), colour( 150,255,150,10){
  7. rslider bounds( 10, 25,60,60), text("Sustain"), colour("Olive"), FontColour("LightGreen"), channel("feedback"), range(0.9,1, 0.999, 2, 0.001)
  8. rslider bounds( 70, 25,60,60), text("Filt. Ratio"), colour("Olive"), FontColour("LightGreen"), channel("FiltRatio"), range(0.5, 32, 1, 0.5)
  9. rslider bounds(130, 25,60,60), text("B.width"), colour("Olive"), FontColour("LightGreen"), channel("bw"), range(1, 32, 16)
  10. rslider bounds(190, 25,60,60), text("Att"), colour("Olive"), FontColour("LightGreen"), channel("att"), range(0, 3, 1,0.5)
  11. checkbox bounds(260, 35, 30, 30), text("Legato") channel("legato"),FontColour("LightGreen"), colour("yellow") value(1)
  12. label bounds(255, 72, 40, 12), text("Legato"), FontColour("LightGreen")
  13. rslider bounds(300, 25,60,60), text("Leg.Speed"), colour("Olive"), FontColour("LightGreen"), channel("LegSpeed"), range(0.01,1,0.05,0.5)
  14. rslider bounds(360, 25,60,60), text("Vib.Depth"), colour("Olive"), FontColour("LightGreen"), channel("VibDep"), range(0, 1, 0.25, 0.75, 0.001)
  15. rslider bounds(420, 25,60,60), text("Vib.Rate"), colour("Olive"), FontColour("LightGreen"), channel("VibRte"), range(0.5, 20, 3, 0.5)
  16. rslider bounds(480, 25,60,60), text("Level"), colour("Olive"), FontColour("LightGreen"), channel("level"), range(0, 1, 0.7)
  17. hslider bounds(15,85,525,40), text("Pickup Position"), colour("Olive"), FontColour("LightGreen"), channel("PickupPos"), range(0.01, 0.99, 0.1)
  18. }
  19. keyboard bounds(10, 130, 530,80)
  20. image bounds(5, 225, 420, 20), colour(75, 85, 90, 50), plant("credit"){
  21. label bounds(0.03, 0.1, .6, .7), text("Author: Iain McCurdy |2012|"), colour("white"), FontColour("LightGreen")
  22. }
  23. </Cabbage>
  24. <CsoundSynthesizer>
  25. <CsOptions>
  26. -dm0 -n -+rtmidi=null -M0
  27. </CsOptions>
  28. <CsInstruments>
  29. sr = 44100
  30. ksmps = 64
  31. nchnls = 2
  32. 0dbfs = 1 ;MAXIMUM AMPLITUDE
  33. massign 0,2
  34. gkNoteTrig init 0
  35. giwave ftgen 0,0,4097,11,20,1,0.5 ;waveform used by excitation (pluck) signal
  36. gisine ftgen 0,0,4097,10,1 ;sine wave (used by lfos)
  37. gkactive init 0 ; Will contain number of active instances of instr 3 when legato mode is chosen. NB. notes in release stage will not be regarded as active.
  38. ;UDOs
  39. ;UDO for plucked electric string - using a UDO facilitates the use of ksmps=1 to improve sound quality
  40. opcode PluckedElectricString,a,aakkkak
  41. asig,acps,kcutoff,kbw,kfeedback,aPickupPos,kporttime xin
  42. setksmps 1
  43. ;smooth krate variables according to the local ksmps and kr
  44. kcutoff portk kcutoff,kporttime
  45. kbw portk kbw,kporttime
  46. acutoff interp kcutoff
  47. kcutoff downsamp acutoff
  48. abw interp kbw
  49. kbw downsamp abw
  50. kbw limit kcutoff*kbw,0.001,10000 ;limit bandwidth values to prevent explosion
  51. aDelTim limit 1/acps,0,1 ;derive required delay time from cycles per second value (reciprocal) and limit range
  52. afb init 0 ;audio feedback signal used by delay buffer
  53. atap1 vdelay asig+afb,aDelTim*aPickupPos*1000,1000 ;tap 1. Nut
  54. atap2 vdelay -atap1,aDelTim*(1-aPickupPos)*1000,1000 ;tap 2, Tailpiece
  55. atap2 butbp atap2,kcutoff,kbw ;bandpass filter (nb. within delay buffer)
  56. afb = atap2*-kfeedback ;create feedback signal to add to input for next iteration
  57. xout atap1+atap2 ;return audio to caller instrument. NB. audio at pickup is a mixture (with positive and negative interference) of wave reflected from the bridge and the nut (the two points of fixture of the string)
  58. endop
  59. ;UDO for lowpass filter attack enveloping - using a UDO permits setting ksmps=1 in order to improve sound quality
  60. opcode butlpsr,a,aii
  61. setksmps 1
  62. asig,icps,idur xin
  63. kcfenv expseg icps,idur,15000,1,15000
  64. asig butlp asig,kcfenv
  65. xout asig
  66. endop
  67. instr 1 ;read in widgets - this instrument runs constantly during performance
  68. gkfeedback chnget "feedback"
  69. gkFiltRatio chnget "FiltRatio"
  70. gkbw chnget "bw"
  71. gkatt chnget "att"
  72. gklegato chnget "legato"
  73. gkLegSpeed chnget "LegSpeed"
  74. gkVibDep chnget "VibDep"
  75. gkVibRte chnget "VibRte"
  76. gklevel chnget "level"
  77. gkPickupPos chnget "PickupPos"
  78. endin
  79. instr 2 ;triggered via MIDI
  80. gkNoteTrig init 1 ;at the beginning of a new note set note trigger flag to '1'
  81. icps cpsmidi ;read in midi note pitch in cycles per second
  82. givel veloc 0,1 ;read in midi note velocity
  83. gkcps = icps ;update a global krate variable for note pitch
  84. if i(gklegato)==0 then ;if we are *not* in legato mode...
  85. inum notnum ; read midi note number (0 - 127)
  86. event_i "i",p1+1+(inum*0.001),0,-1,icps ; call sound producing instr
  87. krel release ; release flag (1 when note is released, 0 otherwise)
  88. if krel==1 then ; when note is released...
  89. turnoff2 p1+1+(inum*0.001),4,1 ; turn off the called instrument
  90. endif ; end of conditional
  91. else ;otherwise... (i.e. legato mode)
  92. iactive = i(gkactive) ;number of active notes of instr 3 (note in release are disregarded)
  93. if iactive==0 then ;...if no notes are active
  94. event_i "i",p1+1,0,-1 ;...start a new held note
  95. endif
  96. endif
  97. endin
  98. instr 3
  99. kporttime linseg 0,0.001,1 ;portamento time function rises quickly from zero to a held value
  100. kporttime = kporttime*gkLegSpeed ;scale portamento time function with value from GUI knob widget
  101. if i(gklegato)==1 then ;if we are in legato mode...
  102. krel release ;sense when note has been released
  103. gkactive = 1-krel ;if note is in release, gkactive=0, otherwise =1
  104. kcps portk gkcps,kporttime ;apply portamento smooth to changes in note pitch (this will only have an effect in 'legato' mode)
  105. acps interp kcps ;create a a-rate version of pitch (cycles per second)
  106. kactive active p1-1 ;...check number of active midi notes (previous instrument)
  107. if kactive==0 then ;if no midi notes are active...
  108. turnoff ;... turn this instrument off
  109. endif
  110. else ;otherwise... (polyphonic / non-legato mode)
  111. acps = p4 ;pitch equal to the original note pitch
  112. endif
  113. aptr line 0,1/i(gkcps),1 ;pointer that will be used to read excitation signal waveform function table
  114. asig tablei aptr,giwave,1,0,0 ;create excitation (pluck) signal
  115. asig butlp asig,cpsoct(4+(givel*8)) ;lowpass filter excitation signal according to midi note velocity of this note
  116. asig buthp asig,i(gkcps) ;highpass filter excitation signal (this could possibly be made adjustable using a GUI widget)
  117. kcutoff limit gkcps*gkFiltRatio,20,20000 ;cutoff of frequency of the bandpass filter will be relative to the pitch of the note. Limit it to prevent out of range values that would cause filter expolosion.
  118. ;In legato mode modulations are reinitialised
  119. if gkNoteTrig==1&&gklegato==1 then
  120. reinit RESTART_ENVELOPE
  121. endif
  122. RESTART_ENVELOPE:
  123. krise linseg 0,0.3,0,1.5,1 ;build-up envelope - modulations do not begin immediately
  124. rireturn
  125. arise interp krise ;interpolation prevents discontinuities (clicks) when oscili lfos are reinitialised
  126. avib oscili 0.8*arise*gkVibDep,gkVibRte,gisine ;vibrato
  127. acps = acps*semitone(avib)
  128. atrm oscili 0.8*arise*gkVibDep,gkVibRte,gisine,0 ;tremolo
  129. gkPickupPos portk gkPickupPos,kporttime ;smooth changes made to pickup position slider
  130. aPickupPos interp gkPickupPos ;interpolate k-rate pickup position variable to create an a-rate version
  131. ares PluckedElectricString asig, acps, kcutoff, gkbw, gkfeedback, aPickupPos,kporttime ;call UDO - using a UDO facilitates the use of a different ksmps value (ksmps=1 and kr=sr) to optimise sound quality
  132. aenv linsegr 0.7,0.05,0 ;amplitude envelope
  133. if i(gkatt)>0 then ;if attack time is anything greater than zero call the lowpass filter envelope
  134. ares butlpsr ares,i(gkcps),i(gkatt) ;a UDO is used again to allow the use of ksmps=1
  135. endif
  136. ares = ares*aenv*(1+atrm)*gklevel ;scale amplitude of audio signal with envelope, tremolo and level knob widget
  137. outs ares,ares
  138. gkNoteTrig = 0 ;reset new-note trigger (in case it was '1')
  139. endin
  140. </CsInstruments>
  141. <CsScore>
  142. i 1 0 [60*60*24*7] ;instrument that reads in widget data
  143. </CsScore>
  144. </CsoundSynthesizer>