|
- ; Rhythmicon.csd
- ; Written by Iain McCurdy, 2013.
-
- ; Recreation of Henry Cowell and Leon Theremin's Rhythmicon instrument (http://en.wikipedia.org/wiki/Rhythmicon)
-
- ; CONTROLS
- ; --------
- ; BASE -- note number of the fundemental (lowest note)
- ; RATE -- base rate (same as rate for fundemental)
- ; LEVEL -- output level
-
- ; DESCRIPTION
- ; -----------
- ; Each note above the fundemental (C3) divides the base rate increasingly according to the arithmetic progression: 2,3,4,5...
- ; Therefore if C3 plays crotchets (quarter notes), C#3 plays quavers (eighth notes), D3 triplets and so on.
- ; The pitches of each note (in cycles per second) follow a simlar progression.
- ; If C3 plays a 200Hz tone, C#3 plays 400Hz, D 600Hz and so on.
-
- ; The 17th note (E4) does not play a note but instead engages a syncopation effect.
- ; I have been unable to find a clear technical specification of how this was implemented but have nonetheless made my 'best guess'.
-
- <Cabbage>
- form caption("...") size(159, 180), pluginID("basl")
-
- label bounds( 5, 3, 22, 22), text("R"), fontcolour(red)
- label bounds( 20, 5, 22, 22), text("H"), fontcolour(yellow)
- label bounds( 35, 2, 22, 22), text("Y"), fontcolour(orchid)
- label bounds( 50, 4, 22, 22), text("T"), fontcolour(LightGreen)
- label bounds( 65, 2, 22, 22), text("H"), fontcolour(OrangeRed)
- label bounds( 80, 6, 22, 22), text("M"), fontcolour(orange)
- label bounds( 99, 1, 22, 22), text("I"), fontcolour(SkyBlue)
- label bounds(110, 4, 22, 22), text("C"), fontcolour(Tomato)
- label bounds(125, 1, 22, 22), text("O"), fontcolour(LightGreen)
- label bounds(140, 3, 22, 22), text("N"), fontcolour(violet)
-
- label bounds( 81, 24, 100, 8), text("Iain McCurdy [2013]"), FontColour("white")
-
- rslider bounds( 3, 45, 55, 55), channel("base"), textBox(1), range(0, 127,36, 1,1),fontcolour(138, 54, 15),colour(orange), trackercolour(orange)
- label bounds( 19, 34, 30, 10), text("BASE"), fontcolour(white)
- rslider bounds( 52, 45, 55, 55), channel("rate"), textBox(1), range(0.1, 5.00, 0.5, 0.5, 0.01),fontcolour(138, 54, 15),colour(orange), trackercolour(orange)
- label bounds( 68, 34, 30, 10), text("RATE"), fontcolour(white)
- rslider bounds(102, 45, 55, 54), channel("level"), textBox(1), range(0, 1.00, 0.5, 0.5, 0.01),fontcolour(138, 54, 15),colour(orange), trackercolour(orange)
- label bounds(115, 34, 30, 10), text("LEVEL"), fontcolour(white)
-
-
- checkbox bounds( 0, 101, 9, 10), channel("k1") value(0) shape(square) colour(yellow)
- checkbox bounds( 9, 101, 10, 10), channel("k2") value(0) shape(square) colour(yellow)
- checkbox bounds( 19, 101, 9, 10), channel("k3") value(0) shape(square) colour(yellow)
- checkbox bounds( 28, 101, 10, 10), channel("k4") value(0) shape(square) colour(yellow)
- checkbox bounds( 38, 101, 10, 10), channel("k5") value(0) shape(square) colour(yellow)
- checkbox bounds( 48, 101, 8, 10), channel("k6") value(0) shape(square) colour(yellow)
- checkbox bounds( 56, 101, 10, 10), channel("k7") value(0) shape(square) colour(yellow)
- checkbox bounds( 66, 101, 8, 10), channel("k8") value(0) shape(square) colour(yellow)
- checkbox bounds( 74, 101, 10, 10), channel("k9") value(0) shape(square) colour(yellow)
- checkbox bounds( 84, 101, 9, 10), channel("k10") value(0) shape(square) colour(yellow)
- checkbox bounds( 93, 101, 10, 10), channel("k11") value(0) shape(square) colour(yellow)
- checkbox bounds(103, 101, 9, 10), channel("k12") value(0) shape(square) colour(yellow)
- checkbox bounds(112, 101, 9, 10), channel("k13") value(0) shape(square) colour(yellow)
- checkbox bounds(121, 101, 10, 10), channel("k14") value(0) shape(square) colour(yellow)
- checkbox bounds(131, 101, 9, 10), channel("k15") value(0) shape(square) colour(yellow)
- checkbox bounds(140, 101, 10, 10), channel("k16") value(0) shape(square) colour(yellow)
- checkbox bounds(150, 101, 10, 10), channel("k17") value(0) shape(square) colour(red)
-
- keyboard bounds(-13, 110, 450, 70)
- </Cabbage>
-
- <CsoundSynthesizer>
-
- <CsOptions>
- -dm0 -n -+rtmidi=null -M0
- </CsOptions>
-
- <CsInstruments>
- sr = 44100
- ksmps = 64
- nchnls = 2
- 0dbfs = 1
- massign 0,1
-
- ; Author: Iain McCurdy (2013)
-
- giAmpScl ftgen 0,0,-20000,-16, 1,100,0,1, 20000-100,-100,0.2
-
- opcode SwitchPort, k, kkk
- kin,kUpPort,kDnPort xin
- kold init 0
- kporttime = (kin<kold?kDnPort:kUpPort)
- kout portk kin, kporttime
- kold = kout
- xout kout
- endop
-
- instr 1 ; Listen for midi note changes. Turn lights on or off. Start the rhymicon of at least 1 note is held.
- inum notnum ; read in midi note number
-
- #define LightToggle(N) # ; define a macro to reduce code repetition
- if inum=(59+$N) then ; if note number played on the keyboard corresponds to 'this' toggle light... (note that first note will be C3 (59 + 1)
- ik$N chnget "k$N" ; read current value for 'this' toggle light (at i-time)
- chnset 1-ik$N,"k$N" ; write the inverse to it (i.e. toggle it)
- endif#
- $LightToggle(1) ; expand macro for all 16 layers
- $LightToggle(2)
- $LightToggle(3)
- $LightToggle(4)
- $LightToggle(5)
- $LightToggle(6)
- $LightToggle(7)
- $LightToggle(8)
- $LightToggle(9)
- $LightToggle(10)
- $LightToggle(11)
- $LightToggle(12)
- $LightToggle(13)
- $LightToggle(14)
- $LightToggle(15)
- $LightToggle(16)
- $LightToggle(17)
-
- kk1 chnget "k1"
- kk2 chnget "k2"
- kk3 chnget "k3"
- kk4 chnget "k4"
- kk5 chnget "k5"
- kk6 chnget "k6"
- kk7 chnget "k7"
- kk8 chnget "k8"
- kk9 chnget "k9"
- kk10 chnget "k10"
- kk11 chnget "k11"
- kk12 chnget "k12"
- kk13 chnget "k13"
- kk14 chnget "k14"
- kk15 chnget "k15"
- kk16 chnget "k16"
-
- ksum = kk1 + kk2 + kk3 + kk4 + kk5 + kk6 + kk7 + kk8 + kk9 + kk10 + kk11 + kk12 + kk13 + kk14 + kk15 + kk16
- if ksum>0 then
- schedkwhen 1,0,1,2,0,-1
- else
- turnoff2 2,0,1
- endif
- endin
-
- instr 2
- kporttime linseg 0,0.001,0.05
- kbase chnget "base" ; base pitch as a note number
- krate chnget "rate" ; rate of pulsation of fundemental
- krate portk krate, kporttime
- klevel chnget "level" ; output amplitude level
- ksync chnget "k17" ; syncopation mode
- kBaseFrq = cpsmidinn(kbase)
- kBaseFrq portk kBaseFrq,kporttime
- iamp = 0.6
- amix = 0
-
- #define LAYER(N)# ; use a macro to reduce code repetition
- kk$N chnget "k$N"
- kk$N SwitchPort kk$N,kporttime*0.01,kporttime*0.5
- ktrig metro krate * $N
- kn = $N ; layer number as a variable
- if ksync=1&&kn>1 then ; if syncopation is on and this isn't the first layer (syncopation irrelevant for first layer)
- ktrig vdelayk ktrig, (1/(krate*$N))/$N , 1/0.1 ; add a syncopation delay for the metronome trigger for this layer
- endif
- kenv loopseg $N/60, ktrig, 0, 0,0.025, 1,0.84/krate, 0,60, 0 ; retriggering envelope
- aenv interp kenv*kk$N ; interpolate to a-rate (for better smoothness)
- kcps = kBaseFrq*$N ; pitch for this layer (in cycles per second)
- kscl table kcps,giAmpScl ; amp scaling value (to quieten higher sounds)
- kamp = iamp*kscl ; apply on/off switch for this layer to its amplitude
- asig vco2 kamp,kcps,2,0.1 ; generate a tone (pulse wave)
- kcf limit cpsoct(octcps(kcps*3)*kenv),1,10000 ; filter envelope
- asig clfilt asig,kcf,0,2 ; butterworth lowpass filter the sound
- asig = asig*aenv ; apply amplitude envelope
- amix = amix + asig# ; add to 'mix' signal with the other layers
-
- $LAYER(1) ; expand macro multiple times. Once for each layer
- $LAYER(2)
- $LAYER(3)
- $LAYER(4)
- $LAYER(5)
- $LAYER(6)
- $LAYER(7)
- $LAYER(8)
- $LAYER(9)
- $LAYER(10)
- $LAYER(11)
- $LAYER(12)
- $LAYER(13)
- $LAYER(14)
- $LAYER(15)
- $LAYER(16)
- xtratim 0.5
- outs amix*klevel, amix*klevel
- endin
-
-
- </CsInstruments>
-
- <CsScore>
- i 1 0 [3600*24*7] ;read widgets
- ;i 2 0 [3600*24*7] ;read widgets
- </CsScore>
-
- </CsoundSynthesizer>
|