Modulation matrix opcode with optimizations for sparse matrices.
The opcode can be used to let a large number of k-rate modulator variables modulate a large number of k-rate parameter variables, with arbitrary scaling of each modulator-to-parameter connection. Csound ftables are used to hold both the input (parameter) variables, the modulator variables, and the scaling coefficients. Output variables are written to another Csound ftable.
iresfn -- ftable number for the parameter output variables
isrcmodfn -- ftable number for the modulation source variables
isrcparmfn -- ftable number for the parameter input variables
imodscale -- scaling/routing coefficient matrix. This is also a csound ftable, used as a matrix of inum_mod rows and inum_parm columns.
inum_mod -- number of modulation variables
inum_parm -- number of parmeter (input and output) variables.
The arguments inum_mod and inum_parm do not have to be set to power-of-two values.
Performance
kupdate -- flag to update the scaling coefficients. When the flag is set to a nonzero value, the scaling coefficients are read directly from the imodscale ftable. When the flag is set to zero, the scaling coefficients are scanned, and an optimized scaling matrix stored internally in the opcode.
For each modulator in isrcmodfn, scale it with the coefficient (in imodscale) determining to what degree it should influence each parameter. Then sum all modulators for each parameter and add the resulting modulator value to the input parameter value read from iscparmfn. Finally, write the output parameter values to table iresfn.
The following tables give insight into the processing performed by the modmatrix opcode, for a simplified example using 3 parameter and 2 modulators. Let’s call the parameters "cps1", "cps2", and "cutoff", and the modulators "lfo1" and "lfo2".
The input variables may at a given point in time have these values:
cps1
cps2
cutoff
isrcparmfn
400
800
3
... while the modulator variables have these values:
lfo1
lfo2
isrcmodfn
0.5
-0.2
The scaling/routing coefficients used:
imodscale
cps1
cps2
cutoff
lfo1
40
0
-2
lfo2
-50
100
3
... and the resulting output values:
cps1
cps2
cutoff
iresfn
430
780
1.4
lfo2
-50
100
3
The output value for "cps1" is calculated as 400+(0.540)+(-0.2-50), similarly for "cps2" 800+(0.50)+(-0.2100), and for cutoff: 3+(0.5-2)+(-0.23)
The imodscale ftable may be specified in the score like this:
f108-22000250300-1.5
Or more conveniently using ftgen in the orchestra:
gimodscaleftgen0,0,8,-2,200,0,2,50,300,-1.5
Obviously, the parameter and modulator variables need not be static values, and similarly, the scaling routing coefficient table may be continuously rewritten using opcodes like tablew.
Examples
Here is an example of the modmatrix opcode. It uses the file modmatrix.csd.
<CsoundSynthesizer><CsOptions>; Select audio flags here according to platform; Audio out Audio in;-odac -iadc ;;;RT audio I/O; For Non-realtime ouput leave only the line below: -o modmatrix.wav -W ;;; for file output any platform</CsOptions><CsInstruments>sr=44100kr=441ksmps=100nchnls=20dbfs=1; basic waveformsgiSineftgen0,0,65537,10,1; sine wavegiSawftgen0,0,4097,7,1,4096,-1; saw (linear)giSoftSawftgen0,0,65537,30,giSaw,1,10; soft saw (only 10 first harmonics); modmatrix tablesgiMaxNumParam=128giMaxNumMod=32giParam_Inftgen0,0,giMaxNumParam,2,0; input parameters table; output parameters table (parameter values with added modulators)giParam_Outftgen0,0,giMaxNumParam,2,0giModulatorsftgen0,0,giMaxNumMod,2,0; modulators table; modulation scaling and routing (mod matrix) table, start with empty tablegiModScaleftgen0,0,giMaxNumParam*giMaxNumMod,-2,0;********************************************; generate the modulator signals;********************************************instr1; LFO1, 1.5 Hz, normalized range (0.0 to 1.0)kLFO1oscil0.5,1.5,giSine; generate LFO signalkLFO1=kLFO1+0.5; offset; LFO2, 0.4 Hz, normalized range (0.0 to 1.0)kLFO2oscil0.5,0.4,giSine; generate LFO signalkLFO2=kLFO2+0.5; offset; write modulators to tabletablewkLFO1,0,giModulatorstablewkLFO2,1,giModulatorsendin;********************************************; set parameter values;********************************************instr2; Here we can set the parameter valuesicps1=p4icps2=p5icutoff=p6; write parameters to tabletableiwicps1,0,giParam_Intableiwicps2,1,giParam_Intableiwicutoff,2,giParam_Inendin;********************************************; mod matrix edit;********************************************instr3; Here we can write to the modmatrix table by using tablew or tableiwiLfo1ToCps1=p4iLfo1ToCps2=p5iLfo1ToCutoff=p6iLfo2ToCps1=p7iLfo2ToCps2=p8iLfo2ToCutoff=p9tableiwiLfo1ToCps1,0,giModScaletableiwiLfo1ToCps2,1,giModScaletableiwiLfo1ToCutoff,2,giModScaletableiwiLfo2ToCps1,3,giModScaletableiwiLfo2ToCps2,4,giModScaletableiwiLfo2ToCutoff,5,giModScale; and set the update flag for modulator matrix ; ***(must update to enable changes)ktriginit1chnsetktrig,"modulatorUpdateFlag"ktrig=0endin;********************************************; mod matrix;********************************************instr4; get the update flagkupdatechnget"modulatorUpdateFlag"; run the mod matrix inum_mod=2inum_parm=3modmatrixgiParam_Out,giModulators,giParam_In,\
giModScale,inum_mod,inum_parm,kupdate; and reset the update flagchnset0,"modulatorUpdateFlag"; reset the update flagendin;********************************************; audio generator to test values;********************************************instr5; basic parametersiamp=ampdbfs(-5); read modulated parameters from tablekcps1table0,giParam_Outkcps2table1,giParam_Outkcutofftable2,giParam_Out; set filter parameterskCF_freq1=kcps1*kcutoffkCF_freq2=kcps2*kcutoffkReso=0.7kDist=0.3; oscillators and filtersa1osciliiamp,kcps1,giSoftSawa1lpf18a1,kCF_freq1,kReso,kDista2osciliiamp,kcps2,giSoftSawa2lpf18a2,kCF_freq2,kReso,kDistoutsa1,a2endin</CsInstruments><CsScore>;********************************************; set initial parameters; cps1 cps2 cutoffi2014008003;********************************************; set modmatrix values; lfo1ToCps1 lfo1ToCps2 lfo1ToCut lfo2ToCps1 lfo2ToCps2 lfo2ToCuti301400-2-501003;********************************************; start "always on" instruments#defineSCORELEN# 20 #; set length of scorei10$SCORELEN; start modulatorsi40$SCORELEN; start mod matrixi50$SCORELEN; start audio oscillatore</CsScore></CsoundSynthesizer>