// Feedback matrix - the class definition // // A network of effects processors feeding back to each other. // Thanks to David Lee Myers for his feedback music // and to Charles Cohen for telling me about it // // - Mike Ciul 2006 // No copyright unless this file comes with a GPL or Creative Commons license. // *************************************************************** // SynthArray // *************************************************************** SynthArray { var node, synths, debug; // constructor // // synthNames should be an array of synthdef names // It will clip if shorter than the synthData array // synthData should be a two dimensional array: // [ // controlName, [ value, nil, value .. ], // controlName, [ nil, value, nil .. ] // ] // controlName.. are names of synth controls, // and value/nil are values of the control settings // (or nil if that synth doesn't use that value) // // inBuses and outBuses should be arrays of bus objects // inBuses should always be the size of the channel array // // node should be a group to add all the synths to *new{ arg synthNames, synthData, inBuses, outBuses, myNode, debug=false; ^super.new.init( synthNames, synthData, inBuses, outBuses, myNode, debug ); } init{ arg synthNames, synthData, inBuses, outBuses, myNode, myDebug; var synthTable = synthData.flop; node = myNode; debug = myDebug; synths = [ ]; inBuses.do( { |inBus, i| debug.if { ( "SynthArray.init: inBus=" ++ inBus.asString ++ " i=" ++ i.asString).postln; }; this.addSynth( synthNames.clipAt(i), synthTable.wrapAt(i), inBus, outBuses[i] ); } ); ^this; } addSynth{ arg synthName, controls, inBus, outBus; var newSynth; controls = controls.addAll( [ \in, inBus.index, \out, outBus.index ] ); debug.if { ( "SynthArray.addSynth: synthName=" ++ synthName.asString ++ " controls=" ++ controls.asString ).postln }; newSynth = synthName.notNil.if( { Synth( synthName, controls, node ) }, { nil } ); debug.if { ( "SynthArray.addSynth: new synth=" ++ newSynth.asString ).postln }; synths = synths.add( newSynth ); ^this; } set{ arg mixData; var flopped = mixData.flop; synths.do { |synth, i| var control, setting; # control, setting = flopped.wrapAt(i); synth.set( control, setting ); debug.if { ( "Set synth " ++ synth.asString ++ " control " ++ control.asString ++ " to " ++ setting ).postln; }; } } setAt{ arg i, control, value; debug.if { ( "SynthArray:SetAt: i=" ++ i.asString ++ " controls=" ++ control.asString ++ "->" ++ value.asString ++ " synth=" ++ synths[i].asString ).postln }; synths[i].set( control, value ); } free{ synths.do( _.free ); synths = [ ]; ^this; } } // *************************************************************** // FeedbackMatrix // *************************************************************** // // requires the effectSend and mainOut synths to be defined on the server // Where's the best place to do that? FeedbackMatrix { var 0, 0 -> 1, .. ], // [ 1 -> 0 .. ], // .. // ] mixData.collect( { |row, i| row.collect( { |level, j| debug.if { ("setFBSends: i=" ++ i.asString ++ " j=" ++ j.asString ++ " level=" ++ level.asString ).postln; }; this.setFBSendAt( i, j, level ); } ); } ); ^this; } setSourceSends { arg mixData; mixData.collect( { |row, i| row.collect( { |level, j| debug.if { ("setSourceSends: i=" ++ i.asString ++ " j=" ++ j.asString ++ " level=" ++ level.asString ).postln; }; this.setSourceSendAt( i, j, level ); } ); } ); ^this; } setFBSendAt { arg i, j, level; fbSendSynth[i].setAt( j, \level, level ); } setSourceSendAt { arg i, j, level; sourceSendSynth[i].setAt( j, \level, level ); } setSourceChannels { arg sourceSynthNames, sourceSynthControls; // TODO - reduce duplication with setFeedbackChannels? // clear old source channels - TODO - keep what hasn't changed? sourceSynth.free; sourceChannels = this.guessNumChannels( [ sourceSynthNames ], [ sourceSynthControls ] ); // create source channels sourceBus = ( { Bus.audio(s, 1) } ).dup( sourceChannels ); // create source synths // I think we need the synthArray object to reduce duplication with fbChannels sourceSynth = SynthArray( sourceSynthNames, sourceSynthControls, sourceBus, sourceBus, sourceGroup, debug ); // create source sends and set them to a low level (?) sourceSendSynth = sourceBus.collect( { |out| SynthArray( ["FeedbackMatrix/effectSend"], [ \level, 0.001], out.dup(fbChannels), inputBus, sendGroup, debug ); } ); // we don't send source channels to output, though maybe we should provide the option. ^this; } }