The Csound Blog by Jacob Joaquin email jacobjoaquin@gmail.com web www.thumbuki.com/csound/blog (C)2007 Jacob Joaquin Licensed under Creative Commons (see below) 2007.07.02 Modular Instruments Part II In the previous blog, "Modular Instruments"[1], I presented an instrument design model that takes advantage of Csound's modular nature by breaking the common instrument structure apart into three elements: Synth Engine, Memory and Interface. (SEMI) In todays blog, I create a new synth named MonoSynth based on the original SEMI Simple synth by replacing the zak memory with a memory core based on the chn opcodes, extending functionality of the engine, introducing modulation parameters, and by incorporating a method that links instances of instruments into an audio chain from within the score. The chn Software Bus Though the zak opcodes work very well with the SEMI system, it does have one significant draw back. Every zak channel has to be explicitly declared by hand. If I want to use multiple Simple synth engines, each with their own distinct set of parameters, I have to manually declare and name every memory for every parameter for each independent voice. I could get around some of the labor by writing a Perl or Python script that automatically generates long lists of macro definitions. However, there exists in Csound a solution that allows us to create individual memory structures dynamically from within the score by using the chn opcodes. According to the Csound 5 manual, the chn software bus system was authored by Istvan Varga in 2005.[2] I discovered these opcodes while reading Steven Yi's CSound Journal article "Creating Encapsulated Instruments in Csound5."[3] From my understanding, the chn opcodes were designed for external applications to talk bidirectionally with Csound. Though they can be used within a solely Csound environment. There are a couple of features which chn offers that make them highly useful. First, memory can be created from within an instrument. Second, chn supports strings. Memory Objects The chn opcodes can be used to create memory structures that loosely resemble the syntax of object-oriented programming languages.[4] A memory structure starts as a class with a list of members. When an object is created from the class, a new chn bus is created for each member of that class. The name of each new memory is a combination of the user-specified object name and the name of the member, separated by a period. For example, the Mixer class in todays example has six parameter: SaAudioIn, kAmp, kAmpMod, kPan, kPanMod and aAudioOut. When a Mixer object is created with the name "spoon", the following memory structure is generated. spoon.SaAudioIn spoon.kAmp spoon.kAmpMod spoon.kPan spoon.kPanMod spoon.aAudioOut Figure 1. A memory object created from the Mixer class. This is really where the parallels between this memory structure and OOP end. There is no encapsulation, as these memory structures can be accessed globally. There is no methods associated with the the object, as external instrument interfaces are created separately to access the object's members. Technically speaking, "there is no spoon"[5], just a group of memories with a useful naming scheme. Some of you are probably thinking that these memory objects more closely resemble C structs[6] than OOP objects. You are 100% correct. The reason I've chosen the OOP metaphor is because I'm still in the early experimentation phase, and I plan on adding more OOP type functionality to this line of work later. To aid in the creation, reading and writing of memory objects, I've made a handful of user-defined opcodes: objnew_x, objget_x and obset_x. There is much string work required to make these faux objects to behave like OOP objects, and these UDO's handle much of it. Score Signal Routing I'm always looking for ways to push more orchestra-like capabilities into the score. The chn opcodes have proven to be a great asset in doing this. Memory objects and their associated synth engines can be designed so that they can stream audio and control data to each other, with the patching being done from within the score. Taken to the extreme, it is entirely possible to build score based instruments with a large pool of compatible SEMI instruments. Here is a quick run down of how this works. Instead of having a synth engine send the audio directly to the DAC or soundfile, the engine writes the data to an a-rate chn member. For example, the instrs MonoSynth, RingMod and Reverb write audio to their local member "aAudioOut". In order for another object to tap the "aAudioOut" stream of another instrument, a special string member "SaAudioIn" is used to reference an instance of "aAudioOut" by name, such as "spoon.aAudioOut". In essence, this string member acts like a C pointer.[7] The instrs RingMod, Reverb and Mixer tap into audio streams by referring to them by the names stored in their members "SaAudionIn". In order to connect objects together, I've created the Attach instr. It accepts two arguments: The input and the output. Since Csound only currently supports a single string per i-event at this time, these two arguments have been consolidated into a single p-field and separated by a single colon. i $Attach 0 1 "cereal.SaAudioIn:spoon.aAudioOut" Figure 2. This connects the audio output from spoon to the audio input of cereal. In the score at the bottom, I create two MonoSynth objects named "lead" and "perc". The output of "perc" is read by the Mixer object "percOut", which then sends the audio to the DAC or soundfile. The other voice, "lead", is read by "leadRing", which is read by "leadReverb" which is read by "leadOut", which is then sent to the DAC or soundfile. ; "perc" -> "percOut" i $Attach 0 1 "percOut.SaAudioIn:perc.aAudioOut" ; "lead" -> "leadRing" -> "leadReverb" -> "leadOut" i $Attach 0 1 "leadRing.SaAudioIn:lead.aAudioOut" i $Attach 0 1 "leadVerb.SaAudioIn:ring.aAudioOut" i $Attach 0 1 "leadOutput.SaAudioIn:leadVerb.aAudioOut" Figure 3. Two examples of audio chains from the score. Modulation Instruments When I was converting Simple into MonoSynth, I made some fundamental changes to the way the synth engine worked in relation to the way the external control instruments fed data to it. I duplicated members I wanted to improve upon and appended "Mod", as in modulation, to their their names. I then created/converted a series of modulation instruments for controlling "Mod" parameters. This newer design allows modulation instruments to be stacked and overlapped. This was not possible with Simple. i $MonoSynth_note 0 16 "foo" 7.00 i $mLFO 0 12 "foo.kPitchMod" 1 3 0 12 0 i $mLFO 4 12 "foo.kPitchMod" 2 3 3 7 0 i $mPattern 0 16 "foo.kPitchMod" 4 22 Figure 4. Modulation instruments can be stacked and overlapped. I should warn you that these modulation instruments are designed to be used with "Mod" members only, as they will most likely break anything else they tamper with. What's Next I plan on continuing work on this synth, though it may be awhile before the next version surfaces publicly. I have an idea for implementing envelopes better than they are now. Basically, I want to keep the envelope engine(s) separate from the synth engine, and build in an envelope input member for each parameter I want envelope controllable. I think it'll work. Though how cluttery it'll make things is still a big unknown at this time. Until next time, Jake Permalink http://www.thumbuki.com/20070702/modular-instruments-part-ii.html References [1] The Csound Blog - Modular Instruments http://www.thumbuki.com/csound/files/thumbuki20070620.csd [2] Csound 5 Manual - chn http://www.csounds.com/manual/html/chn.html [3] Creating Encapsulated Instruments in Csound5 by Steven Yi http://www.csounds.com/journal/2006winter/encapsulatedInstruments.html [4] Object-oriented programming http://en.wikipedia.org/wiki/Object_oriented_programming [5] Quote from The Matrix http://en.wikipedia.org/wiki/The_matrix [6] Composite Type - struct http://en.wikipedia.org/wiki/Composite_type [7] Pointer http://en.wikipedia.org/wiki/Pointer License (cc) Creative Commons Attribution-ShareAlike 2.5 You are free: * to Share -- to copy, distribute, display, and perform the work * to Remix -- to make derivative works Under the following conditions: * Attribution. You must attribute the work in the manner specified by the author or licensor. * Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one. * For any reuse or distribution, you must make clear to others the license terms of this work. * Any of these conditions can be waived if you get permission from the copyright holder. http://creativecommons.org/licenses/by-sa/2.5/ sr = 44100 kr = 11025 ksmps = 4 nchnls = 2 ; ---- Create new Object.Member ---- opcode objnew_i, 0, SS Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember chn_k Sname, 3 endop opcode objnew_k, 0, SS Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember chn_k Sname, 3 endop opcode objnew_a, 0, SS Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember chn_a Sname, 3 endop opcode objnew_S, 0, SS Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember chn_S Sname, 3 endop ; ---- Set value of Object.Member ---- opcode objset_i, 0, iSS ival, Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember chnset ival, Sname endop opcode objset_k, 0, kSS kval, Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember chnset kval, Sname endop opcode objset_a, 0, aSS aval, Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember chnset aval, Sname endop opcode objset_S, 0, SSS Sval, Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember chnset Sval, Sname endop ; ---- Get value from Object.Member ---- opcode objget_i, i, SS Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember iout chnget Sname xout iout endop opcode objget_k, k, SS Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember kout chnget Sname xout kout endop opcode objget_a, a, SS Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember aout chnget Sname xout aout endop opcode objget_S, S, SS Sobject, Smember xin Sname sprintf "%s.%s", Sobject, Smember Sout chnget Sname xout Sout endop ; ---- Instrument Definitions ---- # define MonoSynth_new # 1 # # define RingMod_new # 2 # # define Reverb_new # 3 # # define Mixer_new # 4 # # define Attach # 5 # # define Parameter # 6 # # define Fader # 7 # # define mEnvelope # 8 # # define mLFO # 9 # # define mSampleAndHold # 10 # # define mPattern # 11 # # define MonoSynth_note # 12 # # define MonoSynth # 13 # # define RingMod # 14 # # define Reverb # 15 # # define Mixer # 16 # ; ---- Tempo ---- # define tempo # 135 # # define duration # 77 # instr $MonoSynth_new Sobject strget p4 ; Create members of Sobject objnew_k Sobject, "kPitch" objnew_k Sobject, "kPitchMod" objnew_k Sobject, "kOsc1Transpose" objnew_k Sobject, "kOsc1TransposeMod" objnew_k Sobject, "kOsc1Waveform" objnew_k Sobject, "kOsc1Amplitude" objnew_k Sobject, "kOsc1AmplitudeMod" objnew_k Sobject, "kOsc2Transpose" objnew_k Sobject, "kOsc2TransposeMod" objnew_k Sobject, "kOsc2Waveform" objnew_k Sobject, "kOsc2Amplitude" objnew_k Sobject, "kOsc2AmplitudeMod" objnew_k Sobject, "kFilterMode" objnew_k Sobject, "kFilterModeMod" objnew_k Sobject, "kFilterFreq" objnew_k Sobject, "kFilterFreqMod" objnew_k Sobject, "kFilterRes" objnew_k Sobject, "kFilterResMod" objnew_k Sobject, "kAmplitude" objnew_k Sobject, "kAmplitudeMod" objnew_k Sobject, "kAmpAttack" objnew_k Sobject, "kAmpRelease" objnew_k Sobject, "kAmpEnv" objnew_k Sobject, "kAmpEnvCurve" objnew_a Sobject, "aAudioOut" ; Set default values for members objset_i 0, Sobject, "kPitch" objset_i 0, Sobject, "kPitchMod" objset_i 0, Sobject, "kOsc1Transpose" objset_i 0, Sobject, "kOsc1TransposeMod" objset_i 1, Sobject, "kOsc1Waveform" objset_i 1, Sobject, "kOsc1Amplitude" objset_i 1, Sobject, "kOsc1AmplitudeMod" objset_i 0, Sobject, "kOsc2Transpose" objset_i 0, Sobject, "kOsc2TransposeMod" objset_i 1, Sobject, "kOsc2Waveform" objset_i 1, Sobject, "kOsc2Amplitude" objset_i 1, Sobject, "kOsc2AmplitudeMod" objset_i 0, Sobject, "kFilterMode" objset_i 0, Sobject, "kFilterModeMod" objset_i 22050, Sobject, "kFilterFreq" objset_i 0, Sobject, "kFilterFreqMod" objset_i 0.0, Sobject, "kFilterRes" objset_i 0.0, Sobject, "kFilterResMod" objset_i 0.0, Sobject, "kAmplitude" objset_i 1.0, Sobject, "kAmplitudeMod" objset_i 2.0, Sobject, "kAmpAttack" objset_i 6.0, Sobject, "kAmpRelease" objset_i 0, Sobject, "kAmpEnv" objset_i 2, Sobject, "kAmpEnvCurve" endin instr $RingMod_new Sobject strget p4 ; Create members of Sobject objnew_S Sobject, "SaAudioIn" objnew_k Sobject, "kFreq" objnew_k Sobject, "kFreqMod" objnew_k Sobject, "kTable" objnew_k Sobject, "kMix" objnew_k Sobject, "kMixMod" objnew_a Sobject, "aAudioOut" ; Set Default Internal Parameters objset_i 440, Sobject, "kFreq" objset_i 0, Sobject, "kFreqMod" objset_i 1, Sobject, "kTable" objset_i 0.5, Sobject, "kMix" objset_i 0, Sobject, "kMixMod" endin instr $Reverb_new Sobject strget p4 ; Create members of Sobject objnew_S Sobject, "SaAudioIn" objnew_k Sobject, "kTime" objnew_k Sobject, "kTimeMod" objnew_k Sobject, "kDiffuse" objnew_k Sobject, "kDiffuseMod" objnew_k Sobject, "kMix" objnew_k Sobject, "kMixMod" objnew_a Sobject, "aAudioOut" ; Set Default Internal Parameters objset_i 1, Sobject, "kTime" objset_i 0, Sobject, "kTimeMod" objset_i 0, Sobject, "kDiffuse" objset_i 0, Sobject, "kDiffuseMod" objset_i 0.5, Sobject, "kMix" objset_i 0, Sobject, "kMixMod" endin instr $Mixer_new Sobject strget p4 ; Create members of Sobject objnew_S Sobject, "SaAudioIn" objnew_k Sobject, "kAmp" objnew_k Sobject, "kAmpMod" objnew_k Sobject, "kPan" objnew_k Sobject, "kPanMod" objnew_a Sobject, "aAudioOut" ; Set Default Internal Parameters objset_i 1, Sobject, "kAmp" objset_i 0, Sobject, "kAmpMod" objset_i 0.5, Sobject, "kPan" objset_i 0, Sobject, "kPanMod" endin instr $Attach Smember strget p4 ; Parse Smember istrlen strlen Smember idelimiter strindex Smember, ":" Sobject strsub Smember, 0, idelimiter SmodSource strsub Smember, idelimiter + 1, istrlen chnset SmodSource, Sobject endin instr $Parameter Smember strget p4 ivalue = p5 chnset ivalue, Smember endin instr $Fader idur = p3 Smember strget p4 ivalue = p5 isteepness = p6 ioldvalue chnget Smember if ( isteepness == 1.0 ) kgoto line kphasor phasor 1 / idur kline expcurve kphasor, isteepness kgoto end line: kline line 0, idur, 1 end: kline = kline * ( ivalue - ioldvalue ) + ioldvalue chnset kline, Smember endin instr $mEnvelope idur = p3 Smember strget p4 ivalue1 = p5 ivalue2 = p6 isteepness = p7 kget chnget Smember if ( isteepness == 1.0 ) kgoto line kphasor phasor 1 / idur kline expcurve kphasor, isteepness kgoto end line: kline line 0, idur, 1 end: kline = kline * ( ivalue2 - ivalue1 ) + ivalue1 chnset kline + kget, Smember endin instr $mLFO idur = p3 Smember strget p4 ifreq = p5 ; In Beats ishape = p6 imin = p7 imax = p8 iphase = p9 kget chnget Smember koscil oscil 0.5, ifreq * $tempo / 60, ishape, iphase koscil = ( koscil + 0.5 ) * ( imax - imin ) + imin chnset koscil + kget, Smember endin instr $mSampleAndHold idur = p3 Smember strget p4 ifreq = p5 imin = p6 imax = p7 idistribution = p8 kget chnget Smember krnd randh 0.5, ifreq * $tempo / 60 krnd = ( krnd + 0.5 ) if ( idistribution <= 1.0 ) kgoto skip krnd expcurve krnd, idistribution skip: krnd = krnd * ( imax - imin ) + imin chnset krnd + kget, Smember endin instr $mPattern idur = p3 Smember strget p4 ifreq = p5 itable = p6 kget chnget Smember kclock phasor ifreq * $tempo / 60 / tableng( itable ) kpattern table kclock, itable, -1 chnset kpattern + kget, Smember endin instr $MonoSynth_note idur = p3 Smember strget p4 ipch = cpspch( p5 ) kattack objget_k Smember, "kAmpAttack" krelease objget_k Smember, "kAmpRelease" kampEnv objget_k Smember, "kAmpEnv" kampEnv = kampEnv + 1 / kattack / kr + 1 / krelease / kr kampEnv limit kampEnv, 0, 1 objset_i ipch, Smember, "kPitch" objset_k kampEnv, Smember, "kAmpEnv" endin instr $MonoSynth idur = p3 Sobject strget p4 kpitch objget_k Sobject, "kPitch" kpitchMod objget_k Sobject, "kPitchMod" ktranspose1 objget_k Sobject, "kOsc1Transpose" ktransposeMod1 objget_k Sobject, "kOsc1TransposeMod" kwaveform1 objget_k Sobject, "kOsc1Waveform" kosc1Amp objget_k Sobject, "kOsc1Amplitude" kosc1AmpMod objget_k Sobject, "kOsc1AmplitudeMod" ktranspose2 objget_k Sobject, "kOsc2Transpose" ktransposeMod2 objget_k Sobject, "kOsc2TransposeMod" kwaveform2 objget_k Sobject, "kOsc2Waveform" kosc2Amp objget_k Sobject, "kOsc2Amplitude" kosc2AmpMod objget_k Sobject, "kOsc2AmplitudeMod" kfilterMode objget_k Sobject, "kFilterMode" kfilterModeMod objget_k Sobject, "kFilterModeMod" kfilterFreq objget_k Sobject, "kFilterFreq" kfilterFreqMod objget_k Sobject, "kFilterFreqMod" kfilterRes objget_k Sobject, "kFilterRes" kfilterResMod objget_k Sobject, "kFilterResMod" kamplitude objget_k Sobject, "kAmplitude" kamplitudeMod objget_k Sobject, "kAmplitudeMod" kampRelease objget_k Sobject, "kAmpRelease" kampEnv objget_k Sobject, "kAmpEnv" kampEnvCurve objget_k Sobject, "kAmpEnvCurve" ; Oscillator aosc1 oscilikt 1, (kpitch)*2^((ktranspose1+ktransposeMod1+kpitchMod)/12), kwaveform1, -1 aosc2 oscilikt 1, (kpitch)*2^((ktranspose2+ktransposeMod2+kpitchMod)/12), kwaveform2, -1 aosc = ( aosc1 * kosc1Amp * kosc1AmpMod + aosc2 * kosc2Amp * kosc2AmpMod ) * 0.5 ; Filter alp moogladder aosc, kfilterFreq + kfilterFreqMod, kfilterRes + kfilterResMod, 0 ahp buthp aosc, kfilterFreq + kfilterFreqMod afilter = alp * ( 1 - ( kfilterMode + kfilterModeMod ) ) + ahp * ( kfilterMode + kfilterModeMod ) ; Amplifier kampEnvFunction expcurve kampEnv, kampEnvCurve avca = afilter * ( kamplitude * kamplitudeMod ) * kampEnvFunction ; Output objset_a avca, Sobject, "aAudioOut" ; Setup for next pass objset_k 0, Sobject, "kPitchMod" objset_k 0, Sobject, "kOsc1TransposeMod" objset_k 0, Sobject, "kOsc2TransposeMod" objset_k 1, Sobject, "kOsc1AmplitudeMod" objset_k 1, Sobject, "kOsc2AmplitudeMod" objset_k 0, Sobject, "kFilterModeMod" objset_k 0, Sobject, "kFilterFreqMod" objset_k 0, Sobject, "kFilterResMod" objset_k 1, Sobject, "kAmplitudeMod" kampEnv = kampEnv - 1 / kampRelease / kr kampEnv limit kampEnv, 0, 1 objset_k kampEnv, Sobject, "kAmpEnv" endin instr $RingMod Sobject strget p4 SaaudioIn objget_S Sobject, "SaAudioIn" aaudioIn chnget SaaudioIn kfreq objget_k Sobject, "kFreq" kfreqMod objget_k Sobject, "kFreqMod" ktable objget_k Sobject, "kTable" kmix objget_k Sobject, "kMix" kmixMod objget_k Sobject, "kMixMod" kmix = kmix + kmixMod kmix limit kmix, 0, 1 a1 oscilikt 1, kfreq + kfreqMod, ktable a1 = aaudioIn * ( 1 - kmix ) + aaudioIn * a1 * kmix objset_k 0, Sobject, "kFreqMod" objset_k 0, Sobject, "kMixMod" objset_a a1, Sobject, "aAudioOut" endin instr $Reverb Sobject strget p4 SaaudioIn objget_S Sobject, "SaAudioIn" aaudioIn chnget SaaudioIn ktime objget_k Sobject, "kTime" ktimeMod objget_k Sobject, "kTimeMod" kdiffuse objget_k Sobject, "kDiffuse" kdiffuseMod objget_k Sobject, "kDiffuseMod" kmix objget_k Sobject, "kMix" kmixMod objget_k Sobject, "kMixMod" kdiffuse = kdiffuse + kdiffuseMod kdiffuse limit kdiffuse, 0, 1 kmix = kmix + kmixMod kmix limit kmix, 0, 1 areverb nreverb aaudioIn, ktime + ktimeMod, kdiffuse aaudioOut = aaudioIn * ( 1 - kmix ) + areverb * kmix objset_a aaudioOut, Sobject, "aAudioOut" ; Setup for next pass objset_k 0, Sobject, "kTimeMod" objset_k 0, Sobject, "kMixMod" endin instr $Mixer Sobject strget p4 SaaudioIn objget_S Sobject, "SaAudioIn" aaudioIn chnget SaaudioIn kamp objget_k Sobject, "kAmp" kampMod objget_k Sobject, "kAmpMod" kpan objget_k Sobject, "kPan" kpanMod objget_k Sobject, "kPanMod" aaudioIn = aaudioIn * ( kamp * kampMod ) * 0dbfs kpan = kpan + kpanMod kpan limit kpan, 0, 1 aleft = aaudioIn * ( 1 - kpan ) aright = aaudioIn * kpan outs aleft, aright objset_k 1, Sobject, "kAmpMod" objset_k 0, Sobject, "kPanMod" endin ; ---- Instrument Definitions ---- # define MonoSynth_new # 1 # # define RingMod_new # 2 # # define Reverb_new # 3 # # define Mixer_new # 4 # # define Attach # 5 # # define Parameter # 6 # # define Fader # 7 # # define mEnvelope # 8 # # define mLFO # 9 # # define mSampleAndHold # 10 # # define mPattern # 11 # # define MonoSynth_note # 12 # # define MonoSynth # 13 # # define RingMod # 14 # # define Reverb # 15 # # define Mixer # 16 # ; ---- Tempo ---- # define tempo # 135 # # define duration # 77 # ; ---- f-tables ---- ; Waveforms f1 0 65537 10 1 ; Sine f2 0 65537 -7 0 16384 1 32768 -1 16386 0 ; Triangle f3 0 65537 -7 1 32768 1 0 -1 32768 -1 ; Square f4 0 65537 -7 -1 65526 1 ; Saw Up f5 0 65537 21 1 ; White Noise f10 0 65537 10 1 0 [-1/11] 0 [1/19] 0 [-1/27] 0 [1/35] ; Band-limited Triangle f11 0 65537 10 1 0 [1/3] 0 [1/5] 0 [1/7] 0 [1/9] ; Band-limited Square f12 0 65537 10 1 [1/2] [1/3] [1/4] [1/5] [1/6] [1/7] [1/8] [1/9] ; Band-limited Saw ; Note Patterns f22 0 9 -2 12 9 4 0 12 9 4 11 ;f23 0 9 -2 12 7 3 -2 -2 12 7 0 ;f23 0 9 -2 12 7 7 -2 3 3 12 0 f23 0 9 -2 12 7 7 -2 3 3 -2 5 ; Windows f50 0 513 -7 1 32 -1 480 -1 ; Window for perc amp f51 0 4096 -7 1 2000 1 48 -1 2000 -1 48 1 ; Window for lead amp output gating f52 0 5 -7 440 880 262 100 ; Half second delay before starting audio s f0 0.5 s ; Tempo t 0 $tempo ; ---- Create Objects ---- i $MonoSynth_new 0 1 "perc" i $Mixer_new 0 1 "percOut" i $MonoSynth_new 0 1 "lead" i $RingMod_new 0 1 "leadRing" i $Reverb_new 0 1 "leadVerb" i $Mixer_new 0 1 "leadOutput" ; ---- Turn on Objects ---- i $MonoSynth 0 $duration "perc" i $Mixer 0 $duration "percOut" i $MonoSynth 0 $duration "lead" i $RingMod 0 $duration "leadRing" i $Reverb 0 $duration "leadVerb" i $Mixer 0 $duration "leadOutput" ; ---- Assemble Audio Chain ---- i $Attach 0 1 "percOut.SaAudioIn:perc.aAudioOut" i $Attach 0 1 "leadRing.SaAudioIn:lead.aAudioOut" i $Attach 0 1 "leadVerb.SaAudioIn:leadRing.aAudioOut" i $Attach 0 1 "leadOutput.SaAudioIn:leadVerb.aAudioOut" ; ---- Set Initial Parameter ---- ; synth i $Parameter 0 1 "lead.kOsc1Waveform" 2 i $Parameter 0 1 "lead.kOsc2Waveform" 2 i $Parameter 0 1 "lead.kOsc2Transpose" 0.1 i $Parameter 0 1 "lead.kOsc1Amplitude" 1 i $Parameter 0 1 "lead.kOsc2Amplitude" 1 i $Parameter 0 1 "lead.kAmplitude" 0.25 i $Parameter 0 1 "lead.kAmpAttack" 0.05 i $Parameter 0 1 "lead.kAmpRelease" 3 i $Parameter 0 1 "lead.kAmpEnvCurve" 10000 i $Parameter 0 1 "perc.kOsc1Waveform" 5 i $Parameter 0 1 "perc.kOsc2Waveform" 2 i $Parameter 0 1 "perc.kOsc2Transpose" 0 i $Parameter 0 1 "perc.kOsc1Amplitude" 1 i $Parameter 0 1 "perc.kOsc2Amplitude" 1.25 i $Parameter 0 1 "perc.kFilterMode" 0.9 i $Parameter 0 1 "perc.kFilterFreq" 100 i $Parameter 0 1 "perc.kAmplitude" 0.25 i $Parameter 0 1 "perc.kAmpAttack" 0.001 i $Parameter 0 1 "perc.kAmpRelease" 0.01 i $Parameter 0 1 "perc.kAmpEnvCurve" 10000 ; fx i $Parameter 0 1 "leadRing.kMix" 0 i $Parameter 0 1 "leadRing.kFreq" 440 i $Parameter 0 1 "leadVerb.kMix" 0.1 i $Parameter 0 1 "leadVerb.kTime" 1 i $Parameter 0 1 "leadVerb.kDiffuse" 0.5 ; mixers i $Parameter 0 1 "leadOutput.kAmp" 3 i $Parameter 0 1 "percOut.kAmp" 2.5 ; ---- Synth Music Demo ---- ; ---- Measures 1 - 8 ---- i $Parameter 0 1 "percOut.kPan" 0.7 i $mLFO 17 11 "perc.kAmplitudeMod" 0.5 50 -1 0 0 i $MonoSynth_note 17 10.25 "perc" 8.00 i $mLFO 28 0.5 "perc.kAmplitudeMod" 0.5 50 -1 0 0 i $MonoSynth_note 28 0.25 "perc" 8.00 i $mPattern 0 28 "lead.kPitchMod" 4 22 i $MonoSynth_note 0 1 "lead" 7.00 i $MonoSynth_note 4 . "lead" 7.07 i $MonoSynth_note 8 . "lead" 7.09 i $MonoSynth_note 12 . "lead" 7.04 i $MonoSynth_note 16 . "lead" 7.00 i $MonoSynth_note 20 . "lead" 7.07 i $MonoSynth_note 24 . "lead" 7.09 i $Parameter 28 1 "lead.kOsc1Waveform" 4 i $Parameter 28 1 "lead.kOsc2Waveform" 4 i $Parameter 28 1 "lead.kOsc1Transpose" -0.1 i $Parameter 28 1 "lead.kOsc2Transpose" 0.1 i $Parameter 28 1 "lead.kFilterMode" 0 i $Parameter 28 1 "lead.kFilterFreq" 1200 i $Parameter 28 1 "lead.kFilterRes" 0.9 i $Parameter 28 1 "lead.kAmplitude" 0.3 i $Fader 28 4 "leadVerb.kMixMod" 0.8 2 i $MonoSynth_note 28 4 "lead" 5.00 i $mLFO 30 2 "leadOutput.kPanMod" 8 1 -0.25 0.25 0 i $mEnvelope 30 2 "lead.kPitchMod" 0 48 2 ; ---- Measures 9 - 17 ---- i $mLFO 31 33 "perc.kAmplitudeMod" 0.5 50 -1 0 0 i $MonoSynth_note 31 32.5 "perc" 8.00 i $Parameter 32 1 "lead.kOsc1Waveform" 2 i $Parameter 32 1 "lead.kOsc2Waveform" 3 i $Parameter 32 1 "lead.kOsc2Transpose" 0.1 i $Parameter 32 1 "lead.kOsc1Amplitude" 1 i $Parameter 32 1 "lead.kOsc2Amplitude" .25 i $Parameter 32 1 "lead.kFilterMode" 0 i $Parameter 32 1 "lead.kFilterFreq" 22000 i $Parameter 32 1 "lead.kFilterRes" 0.0 i $Parameter 32 1 "lead.kAmplitude" 0.25 i $Parameter 32 1 "lead.kAmpAttack" 0.05 i $Parameter 32 1 "lead.kAmpRelease" 3 i $Parameter 32 1 "lead.kAmpEnvCurve" 10000 i $Parameter 32 1 "leadVerb.kMix" 0.1 i $Parameter 32 1 "leadVerb.kTime" 1 i $Fader 32 0.1 "leadVerb.kMixMod" 0.1 i $Parameter 32 1 "leadOutput.kPan" 0.4 i $mLFO 32 32 "leadOutput.kPanMod" 0.333 1 -0.15 0.15 0 i $mPattern 32 32 "lead.kPitchMod" 4 23 i $Fader 32 32 "leadRing.kFreq" 1000 2 i $mLFO 32 32 "leadRing.kFreqMod" 2 3 0 440 0 i $mPattern 32 32 "leadRing.kFreqMod" 1 52 i $MonoSynth_note 32 2.5 "lead" 7.00 i $Parameter 34.5 1 "leadRing.kMix" 1 i $mEnvelope 34 2 "leadVerb.kMixMod" 0 0.4 2 i $MonoSynth_note 36 2.5 "lead" 7.05 i $Parameter 36 1 "leadRing.kMix" 0 i $Parameter 38.5 1 "leadRing.kMix" 1 i $mEnvelope 38 2 "leadVerb.kMixMod" 0 0.4 2 i $MonoSynth_note 40 2.5 "lead" 7.00 i $Parameter 40 1 "leadRing.kMix" 0 i $Parameter 42.5 1 "leadRing.kMix" 1 i $mEnvelope 42 2 "leadVerb.kMixMod" 0 0.4 2 i $MonoSynth_note 44 2.5 "lead" 7.07 i $Parameter 44 1 "leadRing.kMix" 0 i $mEnvelope 46 2 "leadVerb.kMixMod" 0 0.4 2 i $mLFO 46 2 "leadOutput.kAmpMod" 5 51 0 1 0.0 i $mLFO 48 16 "lead.kOsc2TransposeMod" 1 3 7 12 0 i $MonoSynth_note 48 2.5 "lead" 7.00 i $mEnvelope 50 2 "leadRing.kMixMod" 0 0.7 2 i $mEnvelope 50 2 "leadVerb.kMixMod" 0 0.9 2 i $MonoSynth_note 52 2.5 "lead" 7.05 i $mEnvelope 54 2 "leadRing.kMixMod" 0 0.7 2 i $mEnvelope 54 2 "leadVerb.kMixMod" 0 0.9 2 i $MonoSynth_note 56 2.5 "lead" 7.00 i $mEnvelope 58 2 "leadRing.kMixMod" 0 0.7 2 i $mEnvelope 58 2 "leadVerb.kMixMod" 0 0.9 2 i $MonoSynth_note 60 2.5 "lead" 7.07 i $mEnvelope 62 2 "leadRing.kMixMod" 0 0.7 2 i $mEnvelope 62 2 "leadVerb.kMixMod" 0 0.9 2 i $mLFO 62 2 "leadOutput.kAmpMod" 3.3 51 0 1 0.0 i $Parameter 64 1 "lead.kOsc1Waveform" 4 i $Parameter 64 1 "lead.kOsc2Waveform" 4 i $Parameter 64 1 "lead.kOsc1Transpose" -0.1 i $Parameter 64 1 "lead.kOsc2Transpose" 0.1 i $Parameter 64 1 "lead.kOsc1Amplitude" 1 i $Parameter 64 1 "lead.kOsc2Amplitude" 1 i $Parameter 64 1 "lead.kFilterMode" 0 i $Parameter 64 1 "lead.kFilterFreq" 1200 i $Parameter 64 1 "lead.kFilterRes" 0.9 i $Parameter 64 1 "lead.kAmpRelease" 6 i $MonoSynth_note 64 4 "lead" 5.00 i $Fader 68 7 "lead.kFilterFreq" 50 100 i $Parameter 64 1 "perc.kOsc1Waveform" 5 i $Parameter 64 1 "perc.kOsc2Waveform" 5 i $Parameter 64 1 "perc.kOsc2Transpose" 0 i $Parameter 64 1 "perc.kOsc1Amplitude" 1 i $Parameter 64 1 "perc.kOsc2Amplitude" 1 i $Parameter 64 1 "perc.kFilterMode" 0 i $Parameter 64 1 "perc.kFilterFreq" 100 i $Parameter 64 1 "perc.kFilterRes" 0.9 i $Parameter 64 1 "perc.kAmplitude" 0.125 i $Parameter 64 1 "perc.kAmpAttack" 0.05 i $Parameter 64 1 "perc.kAmpRelease" 0.25 i $Parameter 64 1 "perc.kAmpEnvCurve" 2 i $Parameter 64 1 "percOut.kPan" 0 i $Fader 64 2 "perc.kAmplitude" 0.125 2 i $mSampleAndHold 64 12 "perc.kFilterFreqMod" 2 0 2000 2 i $mSampleAndHold 64 12 "percOut.kPanMod" 2 0 1 2 i $Fader 66 10 "perc.kAmplitude" 0 2 i $MonoSynth_note 64 0.1 "perc" 7.00 i $MonoSynth_note 64.5 . "perc" . i $MonoSynth_note 65 . "perc" . i $MonoSynth_note 65.5 . "perc" . i $MonoSynth_note 66 . "perc" . i $MonoSynth_note 66.5 . "perc" . i $MonoSynth_note 67 . "perc" . i $MonoSynth_note 67.5 . "perc" . i $MonoSynth_note 68 . "perc" . i $MonoSynth_note 68.5 . "perc" . i $MonoSynth_note 69 . "perc" . i $MonoSynth_note 69.5 . "perc" . i $MonoSynth_note 70 . "perc" . i $MonoSynth_note 70.5 . "perc" . i $MonoSynth_note 71 . "perc" . i $MonoSynth_note 71.5 . "perc" . i $MonoSynth_note 72 . "perc" . i $MonoSynth_note 72.5 . "perc" . i $MonoSynth_note 73 . "perc" . i $MonoSynth_note 73.5 . "perc" . i $MonoSynth_note 74 . "perc" . i $MonoSynth_note 74.5 . "perc" . i $MonoSynth_note 75 . "perc" . i $MonoSynth_note 75.5 . "perc" . i $MonoSynth_note 76 . "perc" . i $MonoSynth_note 76.5 . "perc" . e $duration