Browse Source

new version of SC part (WIP)

Thomas GUFFROY 6 tháng trước cách đây
mục cha
commit
0754b3ad89

+ 0 - 45
SC/2_oscillator_synthdefs.scd

@@ -1,45 +0,0 @@
-// Basic oscillator SynthDefs
-(
-// Pure sine tone
-SynthDef(\sineTone, { |out=0, freq=440, amp=0.1, pan=0, attack=0.01, release=1|
-    var sig, env;
-    env = EnvGen.kr(Env.perc(attack, release), doneAction: 2);
-    sig = SinOsc.ar(freq) * env * amp;
-    Out.ar(out, Pan2.ar(sig, pan));
-}).add;
-
-// Square wave tone
-SynthDef(\squareTone, { |out=0, freq=440, amp=0.1, pan=0, attack=0.01, release=1, width=0.5|
-    var sig, env;
-    env = EnvGen.kr(Env.perc(attack, release), doneAction: 2);
-    sig = Pulse.ar(freq, width) * env * amp;
-    Out.ar(out, Pan2.ar(sig, pan));
-}).add;
-
-// Sawtooth wave tone
-SynthDef(\sawTone, { |out=0, freq=440, amp=0.1, pan=0, attack=0.01, release=1|
-    var sig, env;
-    env = EnvGen.kr(Env.perc(attack, release), doneAction: 2);
-    sig = Saw.ar(freq) * env * amp;
-    Out.ar(out, Pan2.ar(sig, pan));
-}).add;
-
-// Triangle wave tone
-SynthDef(\triTone, { |out=0, freq=440, amp=0.1, pan=0, attack=0.01, release=1|
-    var sig, env;
-    env = EnvGen.kr(Env.perc(attack, release), doneAction: 2);
-    sig = LFTri.ar(freq) * env * amp;
-    Out.ar(out, Pan2.ar(sig, pan));
-}).add;
-
-// FM synthesis tone
-SynthDef(\fmTone, { |out=0, freq=440, amp=0.1, pan=0, attack=0.01, release=1, modRatio=2, modAmt=0.5|
-    var sig, env, mod;
-    env = EnvGen.kr(Env.perc(attack, release), doneAction: 2);
-    mod = SinOsc.ar(freq * modRatio, 0, freq * modAmt);
-    sig = SinOsc.ar(freq + mod) * env * amp;
-    Out.ar(out, Pan2.ar(sig, pan));
-}).add;
-
-"Oscillator SynthDefs loaded".postln;
-)

+ 4 - 12
SC/2b_rgb_synthdefs.scd

@@ -1,19 +1,15 @@
 (
 // RGB-controlled synthesizer with amplitude envelope
-SynthDef(\rgbSynth, { |out=0, freq=440, amp=0.5, ampAttack=0.01, ampRelease=1,
-	filterAttack=0, filterRelease=0, filterMin=200, filterMax=5000,
+SynthDef(\rgbSynth, { |out=0, freq=440, amp=1, ampAttack=0.01, ampRelease=1,
 	pitchAttack=0, pitchRelease=0, pitchRatio=2,
 	redAmt=0.5, greenAmt=0.5, blueAmt=0.5|
 
-    var env, gate, filterEnv, pitchEnv, red, green, blue, sig;
+    var env, gate, pitchEnv, red, green, blue, sig;
 
-	gate = \gate.kr(1);
+	gate = \gate.kr(0);
 
     // Amplitude envelope
-    env = EnvGen.kr(Env.adsr(ampAttack, 0, 1, ampRelease), gate, doneAction: 2);
-
-    // Filter envelope
-    filterEnv = EnvGen.kr(Env.adsr(filterAttack, 0, 1, filterRelease), gate);
+    env = EnvGen.kr(Env.adsr(ampAttack, 0, 1, ampRelease), gate);
 
     // Pitch envelope
     pitchEnv = EnvGen.kr(Env.adsr(pitchAttack, 0, 1, pitchRelease), gate);
@@ -29,15 +25,11 @@ SynthDef(\rgbSynth, { |out=0, freq=440, amp=0.5, ampAttack=0.01, ampRelease=1,
     // Mix the waveforms
     sig = (red + green + blue) / 3;
 
-    // Apply filter with envelope control
-    sig = RLPF.ar(sig, filterEnv.linexp(0, 1, filterMin, filterMax), 0.8);
-
     // Apply envelope and output
     sig = sig * env * amp;
     Out.ar(out, sig!2);
 }).add;
 
 
-
 "RGB-controlled synthesizer loaded".postln;
 )

+ 22 - 0
SC/2c_voice_allocation_setup.scd

@@ -0,0 +1,22 @@
+(
+//PUT HERE THE NUMBER OF POLYPHONY VOICES
+var nbVoices = 16;
+
+
+// Synth array for voice allocation
+~synths = Array.fill(nbVoices, { Synth(\rgbSynth) });
+
+
+// Array to keep in memory active synths (i.e. active notes)
+~activeNotes = Array.fill(nbVoices, { nil });
+
+
+// Function to modify a parameter for all synths
+~setSynthsParam = { |param, value|
+    ~synths.do { |synth|
+        synth.set(param, value);
+    };
+};
+
+"Voice allocation arrays loaded".postln
+)

+ 0 - 44
SC/3_effects_synthdefs.scd

@@ -1,44 +0,0 @@
-(
-// Simple reverb effect
-SynthDef(\reverb, { |in=0, out=0, mix=0.3, room=0.5, damp=0.5|
-    var sig, wet;
-    sig = In.ar(in, 2);
-    wet = FreeVerb.ar(sig, mix, room, damp);
-    Out.ar(out, wet);
-}).add;
-
-// Delay effect with feedback
-SynthDef(\delay, { |in=0, out=0, delaytime=0.5, feedback=0.5, mix=0.5|
-    var sig, wet, delayed;
-    sig = In.ar(in, 2);
-    delayed = CombL.ar(sig, 2.0, delaytime, feedback * 3);
-    wet = (sig * (1 - mix)) + (delayed * mix);
-    Out.ar(out, wet);
-}).add;
-
-// Low-pass filter effect
-SynthDef(\lpf, { |in=0, out=0, cutoff=1000, res=0.5|
-    var sig;
-    sig = In.ar(in, 2);
-    sig = RLPF.ar(sig, cutoff, res);
-    Out.ar(out, sig);
-}).add;
-
-// High-pass filter effect
-SynthDef(\hpf, { |in=0, out=0, cutoff=1000, res=0.5|
-    var sig;
-    sig = In.ar(in, 2);
-    sig = RHPF.ar(sig, cutoff, res);
-    Out.ar(out, sig);
-}).add;
-
-// Distortion effect
-SynthDef(\distortion, { |in=0, out=0, amount=0.5, mix=0.5|
-    var sig, dist;
-    sig = In.ar(in, 2);
-    dist = (sig * amount).tanh;
-    Out.ar(out, (sig * (1 - mix)) + (dist * mix));
-}).add;
-
-"Effects SynthDefs loaded".postln;
-)

+ 5 - 9
SC/4_modulation_synthdefs.scd

@@ -5,9 +5,9 @@ SynthDef(\lfo, { |out=0, freq=1, min=0, max=1, waveform=0|
 
     // Select waveform based on parameter
     lfo = Select.kr(waveform, [
-        SinOsc.kr(freq),        // Sine wave (waveform=0)
-        LFTri.kr(freq),         // Triangle wave (waveform=1)
-        LFSaw.kr(freq),         // Sawtooth wave (waveform=2)
+        SinOsc.kr(freq),         // Sine wave (waveform=0)
+        LFTri.kr(freq),          // Triangle wave (waveform=1)
+        LFSaw.kr(freq, 0, -1),   // Decreasing sawtooth wave (waveform=2)
         LFPulse.kr(freq, 0, 0.5) // Square wave (waveform=3)
     ]);
 
@@ -18,21 +18,17 @@ SynthDef(\lfo, { |out=0, freq=1, min=0, max=1, waveform=0|
     Out.kr(out, lfo);
 }).add;
 
+
 // ADSR envelope generator
 SynthDef(\envelope, { |out=0, gate=1, attack=0.01, decay=0.3, sustain=0.5, release=1|
     var env = EnvGen.kr(
         Env.adsr(attack, decay, sustain, release),
         gate,
-        doneAction: 2
     );
     Out.kr(out, env);
 }).add;
 
-// Random value generator with controllable rate
-SynthDef(\randomGen, { |out=0, freq=1, min=0, max=1|
-    var rand = LFNoise2.kr(freq).range(min, max);
-    Out.kr(out, rand);
-}).add;
+
 
 "Modulation SynthDefs loaded".postln;
 )

+ 0 - 22
SC/4b_lfo_effects.scd

@@ -1,22 +0,0 @@
-(
-// LFO SynthDef with multiple waveform options
-SynthDef(\lfoEffect, { |out=0, freq=1, min=0, max=1, waveform=0, target=0|
-    var lfo;
-
-    // Select waveform based on parameter
-    lfo = Select.kr(waveform, [
-        SinOsc.kr(freq),        // Sine wave (waveform=0)
-        LFTri.kr(freq),         // Triangle wave (waveform=1)
-        LFSaw.kr(freq, 0, -1),  // Decreasing sawtooth (waveform=2)
-        LFPulse.kr(freq, 0, 0.5) // Square wave (waveform=3)
-    ]);
-
-    // Scale to range
-    lfo = lfo.range(min, max);
-
-    // Output to control bus
-    Out.kr(out, lfo);
-}).add;
-
-"Enhanced LFO effects loaded".postln;
-)

+ 127 - 288
SC/5_osc_communication.scd

@@ -1,5 +1,5 @@
-// Module 5: OSC Communication Setup - FIXED FOR PROPER TOUCH MANAGEMENT
-// Save as "5_osc_communication.scd" (REPLACE THE PREVIOUS VERSION)
+// Module 5: OSC Communication Setup - MODIFIED FOR IDRAW OSC
+// Save as "5_osc_communication.scd"
 
 (
 // Clear any existing OSC definitions
@@ -10,278 +10,111 @@ OSCdef.freeAll;
 ~currentColor = (r: 0.0, g: 0.0, b: 1.0); // Default blue
 ~currentPadValues = (x: 0.0, y: 0.0, pressure: 1.0); //Default pad values
 
-// Touch state management
-~touchState = (
-    isActive: false,
-    currentSynth: nil,
-    lastTriggerTime: 0,
-    minTriggerInterval: 0.1  // Minimum time between new synths (100ms)
-);
-
-~synthParams = (
-	out: 0,
-	freq: 440,
-	amp: 0.5,
-	ampAttack: 0.01,
-	ampRelease: 1,
-	filterAttack: 0,
-	filterRelease: 0,
-	filterMin: 200,
-	filterMax: 5000,
-	pitchAttack: 0,
-	pitchRelease: 0,
-	pitchRatio: 2,
-	redAmt: 0.5,
-	greenAmt: 0.5,
-	blueAmt: 0.5
-);
-
-// Track active synths to prevent memory leaks
-~activeSynths = IdentityDictionary.new;
-~synthCounter = 0;
-
-// Function to clean up old synths
-~cleanupSynths = {
-	~activeSynths.keysValuesDo({ |key, synth|
-		if(synth.isPlaying.not, {
-			~activeSynths.removeAt(key);
-		});
-	});
-	
-	// If too many synths are active, force cleanup of oldest ones
-	if(~activeSynths.size > 5, {  // Reduced from 10 to 5
-		var oldestKeys = ~activeSynths.keys.asArray.sort.copyRange(0, ~activeSynths.size - 3);
-		oldestKeys.do({ |key|
-			if(~activeSynths[key].notNil, {
-				~activeSynths[key].set(\gate, 0);
-				~activeSynths.removeAt(key);
-			});
-		});
-	});
-};
-
-// Function to create a new synth safely (only when needed)
-~createSafeSynth = { |synthType = \rgbSynth, args|
-	var synth, synthId;
-	
-	// Clean up old synths first
-	~cleanupSynths.value;
-	
-	// Create new synth
-	synthId = ~synthCounter;
-	~synthCounter = ~synthCounter + 1;
-	
-	// Add default parameters if not provided
-	args = args ++ [
-		\ampAttack, ~synthParams.ampAttack,
-		\ampRelease, ~synthParams.ampRelease,
-		\filterAttack, ~synthParams.filterAttack,
-		\filterRelease, ~synthParams.filterRelease,
-		\pitchAttack, ~synthParams.pitchAttack,
-		\pitchRelease, ~synthParams.pitchRelease,
-		\redAmt, ~synthParams.redAmt,
-		\greenAmt, ~synthParams.greenAmt,
-		\blueAmt, ~synthParams.blueAmt
-	];
-	
-	synth = Synth(synthType, args);
-	~activeSynths[synthId] = synth;
-	
-	// Schedule automatic cleanup
-	SystemClock.sched(~synthParams.ampAttack + ~synthParams.ampRelease + 1, {
-		if(~activeSynths[synthId].notNil, {
-			~activeSynths[synthId].set(\gate, 0);
-			~activeSynths.removeAt(synthId);
-		});
-		nil; // Don't reschedule
-	});
-	
-	synth;
-};
-
-// Function to handle touch begin (creates new synth)
-~handleTouchBegin = {
-    var x = ~currentPadValues.x;
-    var y = ~currentPadValues.y;
-    var pressure = ~currentPadValues.pressure;
-    var freq = x.linexp(-0.5, 0.5, 100, 2000);
-    var amp = pressure.linlin(1, 8, 0.1, 0.5);  // Reduced max amplitude
-
-    // Only create sounds for envelope-controlling pen types
-    if([\pen, \monoline, \marker].includes(~currentPenType.asSymbol), {
-        // Release previous synth if it exists
-        if(~touchState.currentSynth.notNil, {
-            ~touchState.currentSynth.set(\gate, 0);
-        });
-        
-        // Create new synth
-        ~touchState.currentSynth = ~createSafeSynth.value(\rgbSynth, [
-            \out, ~sourceBus ? 0,
-            \freq, freq,
-            \amp, amp
-        ]);
-        
-        ~touchState.isActive = true;
-        ~touchState.lastTriggerTime = SystemClock.seconds;
-        
-        ["Touch BEGIN - Sound triggered:", ~currentPenType, freq, amp].postln;
-    });
-};
-
-// Function to handle touch movement (updates existing synth)
-~handleTouchMove = {
-    var x = ~currentPadValues.x;
-    var y = ~currentPadValues.y;
-    var pressure = ~currentPadValues.pressure;
-    var freq = x.linexp(-0.5, 0.5, 100, 2000);
-    var amp = pressure.linlin(1, 8, 0.1, 0.5);
-
-    // Only update if we have an active touch for envelope-controlling pens
-    if(~touchState.isActive and: { ~touchState.currentSynth.notNil } and: { 
-        [\pen, \monoline, \marker].includes(~currentPenType.asSymbol) 
-    }, {
-        // Update the existing synth parameters
-        if(~touchState.currentSynth.isPlaying, {
-            ~touchState.currentSynth.set(\freq, freq, \amp, amp);
-            // Don't log every movement to avoid spam
-        });
-    });
-};
 
-// Function to handle touch end (releases synth)
-~handleTouchEnd = {
-    if(~touchState.currentSynth.notNil, {
-        ~touchState.currentSynth.set(\gate, 0);
-        ~touchState.currentSynth = nil;
-        ~touchState.isActive = false;
-        
-        ["Touch END - Sound released"].postln;
-    });
-};
-
-// Smart trigger function that decides what to do based on pressure changes
-~smartTriggerSound = {
-    var currentTime = SystemClock.seconds;
-    var pressure = ~currentPadValues.pressure;
-    
-    // Detect touch begin: pressure goes from low to high
-    if(pressure > 2 and: { ~touchState.isActive.not }, {
-        ~handleTouchBegin.value;
-    });
-    
-    // Detect touch movement: pressure stays high and we have active touch
-    if(pressure > 1 and: { ~touchState.isActive }, {
-        ~handleTouchMove.value;
-    });
-    
-    // Detect touch end: pressure goes to very low or zero
-    if(pressure <= 1 and: { ~touchState.isActive }, {
-        ~handleTouchEnd.value;
-    });
-};
-
-// Function to update effect parameters safely
+// Define OSC responder for iDraw touch data
 ~changeEffectParams = {
     var x = ~currentPadValues.x;
     var y = ~currentPadValues.y;
     var pressure = ~currentPadValues.pressure;
 
-    // Update synthesis parameters but DON'T log every change to avoid spam
-    switch(~currentPenType.asSymbol,
+    // Log the received data
+    ["Touch data:", x, y, pressure, ~currentPenType, ~currentColor].postln;
+
+    // Handle touch based on current pen type
+    switch(~currentPenType,
         // Pen - Controls amplitude envelope
-		\pen, {
+		"/pen", {
             var ampAttack = y.linexp(-0.5, 0.5, 0.001, 5);
             var ampRelease = x.linexp(-0.5, 0.5, 0.001, 10);
 
-			~synthParams.ampAttack = ampAttack;
-			~synthParams.ampRelease = ampRelease;
+			~setSynthsParam.(\ampAttack, ampAttack);
+			~setSynthsParam.(\ampRelease, ampRelease);
+
+            ["Amplitude envelope:", ampAttack, ampRelease].postln;
         },
 
         // Monoline - Controls filter envelope
-		\monoline, {
+		"/monoline", {
             var filterAttack = y.linexp(-0.5, 0.5, 0.001, 5);
             var filterRelease = x.linexp(-0.5, 0.5, 0.001, 10);
 
-			~synthParams.filterAttack = filterAttack;
-			~synthParams.filterRelease = filterRelease;
+			~setSynthsParam.(\filterAttack, filterAttack);
+			~setSynthsParam.(\filterRelease, filterRelease);
+
+            ["Filter envelope:", filterAttack, filterRelease].postln;
         },
 
         // Marker - Controls pitch envelope
-		\marker, {
+		"/marker", {
             var pitchAttack = y.linexp(-0.5, 0.5, 0.001, 5);
             var pitchRelease = x.linexp(-0.5, 0.5, 0.001, 10);
 
-			~synthParams.pitchAttack = pitchAttack;
-			~synthParams.pitchRelease = pitchRelease;
+			~setSynthsParam.(\pitchAttack, pitchAttack);
+			~setSynthsParam.(\pitchRelease, pitchRelease);
+
+            ["Pitch envelope:", pitchAttack, pitchRelease].postln;
         },
 
         // Pencil - Effect preset 1
-		\pencil, {
-            // Apply Preset 1 effects - with safety checks
-            if(~filterSynth.notNil and: { ~filterSynth.isPlaying }, {
-                ~filterSynth.set(
-                    \cutoff, x.linexp(-0.5, 0.5, 20, 18000),
-                    \res, y.linlin(-0.5, 0.5, 0, 1)
-                );
-            });
-
-            if(~lfoSynth.notNil and: { ~lfoSynth.isPlaying }, {
-                ~lfoSynth.set(
-                    \freq, x.linlin(-0.5, 0.5, 0, 15),
-                    \intensity, pressure.linlin(1, 8, 0, 1)
-                );
-            });
-
-            if(~reverbSynth.notNil and: { ~reverbSynth.isPlaying }, {
-                ~reverbSynth.set(
-                    \room, y.linlin(-0.5, 0.5, 0.1, 0.9)
-                );
-            });
+		"/pencil", {
+            // Apply Preset 1 effects
+            ~filterSynth.set(
+                \cutoff, x.linexp(-0.5, 0.5, 20, 18000),
+                \res, y.linlin(-0.5, 0.5, 0, 1)
+            );
+
+            ~lfoSynth.set(
+                \freq, x.linlin(-0.5, 0.5, 0, 15),
+                \intensity, pressure.linlin(1, 8, 0, 1)
+            );
+
+            ~reverbSynth.set(
+                \roomsize, y.linlin(-0.5, 0.5, 0.1, 0.9)
+            );
+
+            ["Pencil preset:", "Cutoff", x.linexp(-0.5, 0.5, 20, 18000), "LFO", x.linlin(-0.5, 0.5, 0, 15)].postln;
         },
 
         // Crayon - Effect preset 2
-		\crayon, {
-            // Apply Preset 2 effects - with safety checks
-            if(~lfoSynth.notNil and: { ~lfoSynth.isPlaying }, {
-                ~lfoSynth.set(
-                    \freq, x.linlin(-0.5, 0.5, 15, 1),
-                    \intensity, x.linlin(-0.5, 0.5, 0, 1)
-                );
-            });
-
-            if(~delaySynth.notNil and: { ~delaySynth.isPlaying }, {
-                ~delaySynth.set(
-                    \delaytime, x.linlin(-0.5, 0.5, 0.01, 1.0)
-                );
-            });
-
-            if(~filterSynth.notNil and: { ~filterSynth.isPlaying }, {
-                ~filterSynth.set(
-                    \cutoff, y.linexp(-0.5, 0.5, 20, 18000),
-                    \res, pressure.linlin(1, 5, 0, 1)
-                );
-            });
-
-            if(~reverbSynth.notNil and: { ~reverbSynth.isPlaying }, {
-                ~reverbSynth.set(
-                    \mix, y.linlin(-0.5, 0.5, 0, 1)
-                );
-            });
+		"/crayon", {
+            // Apply Preset 2 effects
+            ~lfoSynth.set(
+                \freq, x.linlin(-0.5, 0.5, 15, 1),
+                \intensity, x.linlin(-0.5, 0.5, 0, 1)
+            );
+
+            ~delaySynth.set(
+                \delaytime, x.linlin(-0.5, 0.5, 0.01, 1.0)
+            );
+
+            ~filterSynth.set(
+                \cutoff, y.linexp(-0.5, 0.5, 20, 18000),
+                \res, pressure.linlin(1, 5, 0, 1)
+            );
+
+            ~reverbSynth.set(
+                \mix, y.linlin(-0.5, 0.5, 0, 1)
+            );
+
+            ["Crayon preset:", "LFO", x.linlin(-0.5, 0.5, 15, 1), "Filter", y.linexp(-0.5, 0.5, 20, 18000)].postln;
         },
 
         // Fountain pen - Effect preset 3 (placeholder)
-		\fountainPen, {
+		"/fountainPen", {
             // Apply Preset 3 effects (TBD in documentation)
+            ["Fountain pen preset (TBD)"].postln;
         },
 
         // Water color - Effect preset 4 (placeholder)
-		\waterColor, {
+		"/waterColor", {
             // Apply Preset 4 effects (TBD in documentation)
+            ["Water color preset (TBD)"].postln;
         }
     );
 };
 
-// ----- OSC Pad Values -----
+
+// ----- OSC Pad Vaues -----
 // OSC responder for x coordinate
 OSCdef(\xOSC, { |msg, time, addr, port|
     var x = msg[1].asFloat;
@@ -289,11 +122,6 @@ OSCdef(\xOSC, { |msg, time, addr, port|
     // Update current pad value and change effects
     ~currentPadValues.x = x;
 	~changeEffectParams.value;
-	
-	// Handle touch movement if active
-	if(~touchState.isActive, {
-		~handleTouchMove.value;
-	});
 
 }, '/aspectX');
 
@@ -304,137 +132,148 @@ OSCdef(\yOSC, { |msg, time, addr, port|
     // Update current pad value and change effects
     ~currentPadValues.y = y;
 	~changeEffectParams.value;
-	
-	// Handle touch movement if active
-	if(~touchState.isActive, {
-		~handleTouchMove.value;
-	});
 
 }, '/aspectY');
 
-// OSC responder for pressure coordinate - THIS IS THE KEY ONE
+// OSC responder for pressure coordinate
 OSCdef(\pressureOSC, { |msg, time, addr, port|
     var pressure = msg[1].asFloat;
 
     // Update current pad value and change effects
     ~currentPadValues.pressure = pressure;
 	~changeEffectParams.value;
-	
-	// Use smart trigger logic instead of always creating new synths
-	~smartTriggerSound.value;
 
 }, '/pressure');
 
-// ----- OSC Pen Types ----- (unchanged)
+
+
+
+// ----- OSC Pen Types -----
+// OSC responder for pen
 OSCdef(\penOSC, { |msg, time, addr, port|
     var penType = msg[1].asFloat;
+
 	if (penType == 1.0) {
-		~currentPenType = \pen;
+		~currentPenType = msg[0].asString;
 		["Current pen type:", ~currentPenType].postln;
 	}
+
 }, '/pen');
 
+// OSC responder for monoline
 OSCdef(\monolineOSC, { |msg, time, addr, port|
     var penType = msg[1].asFloat;
+
 	if (penType == 1.0) {
-		~currentPenType = \monoline;
+		~currentPenType = msg[0].asString;
 		["Current pen type:", ~currentPenType].postln;
 	}
+
 }, '/monoline');
 
+// OSC responder for marker
 OSCdef(\markerOSC, { |msg, time, addr, port|
     var penType = msg[1].asFloat;
+
 	if (penType == 1.0) {
-		~currentPenType = \marker;
+		~currentPenType = msg[0].asString;
 		["Current pen type:", ~currentPenType].postln;
 	}
+
 }, '/marker');
 
+// OSC responder for pencil
 OSCdef(\pencilOSC, { |msg, time, addr, port|
     var penType = msg[1].asFloat;
+
 	if (penType == 1.0) {
-		~currentPenType = \pencil;
-		if(~initializePreset1.notNil, { ~initializePreset1.value; });
+		~currentPenType = msg[0].asString;
+		~initializePreset1.value;
 		["Current pen type:", ~currentPenType].postln;
 	}
+
 }, '/pencil');
 
+// OSC responder for crayon
 OSCdef(\crayonOSC, { |msg, time, addr, port|
     var penType = msg[1].asFloat;
+
 	if (penType == 1.0) {
-		~currentPenType = \crayon;
-		if(~initializePreset2.notNil, { ~initializePreset2.value; });
+		~currentPenType = msg[0].asString;
+		~initializePreset2.value;
 		["Current pen type:", ~currentPenType].postln;
 	}
+
 }, '/crayon');
 
+// OSC responder for fountainPen
 OSCdef(\fountainPenOSC, { |msg, time, addr, port|
     var penType = msg[1].asFloat;
+
 	if (penType == 1.0) {
-		~currentPenType = \fountainPen;
-		if(~initializePreset3.notNil, { ~initializePreset3.value; });
+		~currentPenType = msg[0].asString;
+		~initializePreset3.value;
 		["Current pen type:", ~currentPenType].postln;
 	}
+
 }, '/fountainPen');
 
+// OSC responder for waterColor
 OSCdef(\waterColorOSC, { |msg, time, addr, port|
     var penType = msg[1].asFloat;
+
 	if (penType == 1.0) {
-		~currentPenType = \waterColor;
-		if(~initializePreset4.notNil, { ~initializePreset4.value; });
+		~currentPenType = msg[0].asString;
+		~initializePreset4.value;
 		["Current pen type:", ~currentPenType].postln;
 	}
+
 }, '/waterColor');
 
-// ----- OSC RGB Colors ----- (unchanged)
+
+
+
+// ----- OSC RGB Colors -----
+// OSC responder for red changes
 OSCdef(\redOSC, { |msg, time, addr, port|
     var component = msg[1].asFloat;
+
+    // Update current color
     ~currentColor.r = component;
-	~synthParams.redAmt = component;
+	~setSynthsParam.(\redAmt, component);
+
     ["Color changed:", ~currentColor].postln;
 }, '/r');
 
+// OSC responder for green changes
 OSCdef(\greenOSC, { |msg, time, addr, port|
     var component = msg[1].asFloat;
+
+    // Update current color
     ~currentColor.g = component;
-	~synthParams.greenAmt = component;
+	~setSynthsParam.(\greenAmt, component);
+
     ["Color changed:", ~currentColor].postln;
 }, '/g');
 
+// OSC responder for blue changes
 OSCdef(\blueOSC, { |msg, time, addr, port|
     var component = msg[1].asFloat;
+
+    // Update current color
     ~currentColor.b = component;
-	~synthParams.blueAmt = component;
+	~setSynthsParam.(\blueAmt, component);
+
     ["Color changed:", ~currentColor].postln;
 }, '/b');
 
-// Cleanup function
-~cleanupOSCSystem = {
-	// End any active touch
-	~handleTouchEnd.value;
-	
-	// Clean up all synths
-	~activeSynths.keysValuesDo({ |key, synth|
-		synth.set(\gate, 0);
-	});
-	~activeSynths.clear;
-	
-	// Reset touch state
-	~touchState.isActive = false;
-	~touchState.currentSynth = nil;
-	
-	"OSC system cleaned up".postln;
-};
 
-// Register cleanup with CmdPeriod
-CmdPeriod.add({
-	~cleanupOSCSystem.value;
-});
+
+
 
 // Start the OSC server on port 57120 (default SuperCollider port)
 thisProcess.openUDPPort(57120);
-"OSC server ready on port 57120 - FIXED FOR TOUCH MANAGEMENT".postln;
-"Now only creates synths on touch BEGIN, updates on MOVE, releases on END".postln;
+"OSC server ready on port 57120".postln;
+"Registered OSC commands: /touch, /pen, /color".postln;
 "Ready to receive data from iDraw OSC app".postln;
-"To cleanup system, run: ~cleanupOSCSystem.value".postln;
 )

+ 0 - 163
SC/6_test_functions.scd

@@ -1,163 +0,0 @@
-(
-// Function to start effects chain
-~startEffectsChain = {
-    // Create audio buses for effects chain
-    ~sourceBus = Bus.audio(s, 2);
-    ~filterBus = Bus.audio(s, 2);
-    ~delayBus = Bus.audio(s, 2);
-    ~reverbBus = Bus.audio(s, 2);
-
-    // Create control buses for modulation
-    ~lfoControlBus = Bus.control(s, 1);
-
-    // Create effects synths in chain
-    ~lfoSynth = Synth(\lfoEffect, [
-        \out, ~lfoControlBus,
-        \freq, 1,
-        \min, 100,
-        \max, 5000,
-        \waveform, 0,
-        \target, 0
-    ]);
-
-    ~filterSynth = Synth(\lpf, [
-        \in, ~sourceBus,
-        \out, ~delayBus,
-        \cutoff, 1000,
-        \res, 0.5
-    ]);
-
-    ~delaySynth = Synth(\delay, [
-        \in, ~delayBus,
-        \out, ~reverbBus,
-        \delaytime, 0.4,
-        \feedback, 0.3,
-        \mix, 0.3
-    ], ~filterSynth, \addAfter);
-
-    ~reverbSynth = Synth(\reverb, [
-        \in, ~reverbBus,
-        \out, 0,
-        \mix, 0.2,
-        \room, 0.5,
-        \damp, 0.5
-    ], ~delaySynth, \addAfter);
-
-    // Create a mapping for the LFO to control the filter
-    s.sync;
-    ~lfoControlBus.asMap.postln;
-    ~filterSynth.map(\cutoff, ~lfoControlBus);
-
-    // Store the effects chain nodes in an array for easy access
-    ~effectsChain = [~lfoSynth, ~filterSynth, ~delaySynth, ~reverbSynth];
-
-    "Effects chain started with LFO mapping".postln;
-};
-// Function to stop effects chain
-~stopEffectsChain = {
-    if(~effectsChain.notNil, {
-        ~effectsChain.do(_.free);
-        ~effectsChain = nil;
-    });
-
-    if(~sourceBus.notNil, { ~sourceBus.free; ~sourceBus = nil; });
-    if(~reverbBus.notNil, { ~reverbBus.free; ~reverbBus = nil; });
-    if(~delayBus.notNil, { ~delayBus.free; ~delayBus = nil; });
-
-    "Effects chain stopped".postln;
-};
-
-// Function to reset the entire system
-~resetSystem = {
-    ~stopEffectsChain.value;
-    OSCdef.freeAll;
-
-    // Reload OSC definitions
-    thisProcess.interpreter.executeFile("5_osc_communication.scd");
-
-    "System reset complete".postln;
-	~touchSynths = ();  // Clear any active touch synths
-
-};
-
-// Test function for parameter changes
-~testParameters = {
-    // Start effects chain if not already running
-    if(~effectsChain.isNil, { ~startEffectsChain.value; });
-
-    // Test different oscillator types with varying parameters
-    [
-        [\sineTone, 440, 0.3, -0.5, 0.05, 0.5],
-        [\squareTone, 330, 0.2, 0, 0.01, 0.8],
-        [\sawTone, 220, 0.15, 0.5, 0.1, 1.2],
-        [\triTone, 550, 0.25, -0.2, 0.02, 0.7],
-        [\fmTone, 660, 0.2, 0.3, 0.05, 1.0]
-    ].do { |params, i|
-        var synthType, freq, amp, pan, attack, release;
-        #synthType, freq, amp, pan, attack, release = params;
-
-        // Create the synth with the specified parameters
-        Synth(synthType, [
-            \out, ~sourceBus,
-            \freq, freq,
-            \amp, amp,
-            \pan, pan,
-            \attack, attack,
-            \release, release
-        ]);
-
-        // Change effect parameters for demonstration
-        ~filterSynth.set(\cutoff, 500 + (i * 1000));
-        ~delaySynth.set(\mix, 0.2 + (i * 0.1));
-        ~reverbSynth.set(\room, 0.3 + (i * 0.1));
-
-        // Log the current sound
-        ["Testing synth:", synthType, freq, amp].postln;
-
-        // Wait between notes
-        0.8.wait;
-    };
-
-    // Clean up
-    "Parameter test complete".postln;
-};
-
-// Function to simulate Arduino touch input
-~simulateTouch = { |numTouches=10, duration=5|
-    var endTime = SystemClock.seconds + duration;
-
-    "Starting touch simulation for % seconds".format(duration).postln;
-
-    // Start the effects chain
-    ~startEffectsChain.value;
-
-    // Generate random touches until the duration expires
-    while { SystemClock.seconds < endTime } {
-        var x = 1.0.rand;
-        var y = 1.0.rand;
-        var pressure = 0.3 + 0.7.rand;
-        var color = 5.rand;  // 0-4 for different synth types
-
-        // Send the simulated touch data through our OSC handler
-        OSCdef(\touchOSC).value(['/touch', x, y, pressure, color], nil, nil, nil);
-
-        // Random wait time between touches
-        (0.1 + 0.3.rand).wait;
-    };
-
-    "Touch simulation complete".postln;
-};
-
-// Run parameter test in a Routine
-~runParameterTest = {
-    Routine(~testParameters).play;
-};
-
-// Run touch simulation in a Routine
-~runTouchSimulation = { |duration=5|
-    Routine({ ~simulateTouch.value(10, duration) }).play;
-};
-
-"Test functions loaded".postln;
-)
-

+ 0 - 327
SC/6b_effect_presets.scd

@@ -1,327 +0,0 @@
-// Module 6: Test Functions & Effect Chain Setup - FIXED FOR MEMORY MANAGEMENT
-// Save as "6_test_functions.scd"
-
-(
-// Function to start effects chain
-~startEffectsChain = {
-    // Stop existing effects first
-    ~stopEffectsChain.value;
-    
-    // Create audio buses for effects chain
-    ~sourceBus = Bus.audio(s, 2);
-    ~reverbBus = Bus.audio(s, 2);
-    ~delayBus = Bus.audio(s, 2);
-    ~filterBus = Bus.audio(s, 2);
-    
-    // Create control buses for modulation
-    ~lfoControlBus = Bus.control(s, 1);
-    
-    // Create effects synths in chain with error handling
-    try {
-        ~filterSynth = Synth(\lpf, [
-            \in, ~sourceBus, 
-            \out, ~delayBus, 
-            \cutoff, 1000, 
-            \res, 0.5
-        ]);
-        
-        ~delaySynth = Synth(\delay, [
-            \in, ~delayBus, 
-            \out, ~reverbBus, 
-            \delaytime, 0.4, 
-            \feedback, 0.3, 
-            \mix, 0.3
-        ], ~filterSynth, \addAfter);
-        
-        ~reverbSynth = Synth(\reverb, [
-            \in, ~reverbBus, 
-            \out, 0, 
-            \mix, 0.2, 
-            \room, 0.5, 
-            \damp, 0.5
-        ], ~delaySynth, \addAfter);
-        
-        // Create LFO separately
-        ~lfoSynth = Synth(\lfoEffect, [
-            \out, ~lfoControlBus, 
-            \freq, 1, 
-            \min, 100, 
-            \max, 5000,
-            \waveform, 0
-        ]);
-        
-        // Wait for server sync then map LFO
-        s.sync;
-        ~filterSynth.map(\cutoff, ~lfoControlBus);
-        
-        // Store the effects chain nodes in an array for easy access
-        ~effectsChain = [~filterSynth, ~delaySynth, ~reverbSynth, ~lfoSynth];
-        
-        "Effects chain started successfully".postln;
-        
-    } { |error|
-        "Error starting effects chain: %".format(error).postln;
-        ~stopEffectsChain.value;
-    };
-};
-
-// Function to stop effects chain
-~stopEffectsChain = {
-    if(~effectsChain.notNil, {
-        ~effectsChain.do({ |synth|
-            if(synth.notNil and: { synth.isPlaying }, {
-                synth.free;
-            });
-        });
-        ~effectsChain = nil;
-    });
-    
-    // Free individual synth references
-    [~filterSynth, ~delaySynth, ~reverbSynth, ~lfoSynth].do({ |synth|
-        if(synth.notNil and: { synth.isPlaying }, {
-            synth.free;
-        });
-    });
-    
-    ~filterSynth = nil;
-    ~delaySynth = nil;
-    ~reverbSynth = nil;
-    ~lfoSynth = nil;
-    
-    // Free buses
-    [~sourceBus, ~reverbBus, ~delayBus, ~filterBus, ~lfoControlBus].do({ |bus|
-        if(bus.notNil, {
-            bus.free;
-        });
-    });
-    
-    ~sourceBus = nil;
-    ~reverbBus = nil;
-    ~delayBus = nil;
-    ~filterBus = nil;
-    ~lfoControlBus = nil;
-    
-    "Effects chain stopped and cleaned up".postln;
-};
-
-// Function to reset the entire system
-~resetSystem = {
-    // Stop all effects
-    ~stopEffectsChain.value;
-    
-    // Clear OSC system if it exists
-    if(~cleanupOSCSystem.notNil, { ~cleanupOSCSystem.value; });
-    
-    // Clear MIDI system if it exists
-    if(~cleanupAllMIDISynths.notNil, { ~cleanupAllMIDISynths.value; });
-    
-    // Clear all OSC definitions
-    OSCdef.freeAll;
-    
-    // Reset touch synths tracking
-    ~touchSynths = ();
-    
-    "System reset complete".postln;
-    
-    // Restart effects chain
-    ~startEffectsChain.value;
-};
-
-// Test function for parameter changes - FIXED to not use problematic timing
-~testParameters = {
-    // Start effects chain if not already running
-    if(~effectsChain.isNil, { ~startEffectsChain.value; });
-    
-    // Test different oscillator types with varying parameters
-    var testParams = [
-        [\rgbSynth, 440, 0.2, -0.5, 0.05, 0.5],
-        [\rgbSynth, 330, 0.15, 0, 0.01, 0.8],
-        [\rgbSynth, 220, 0.1, 0.5, 0.1, 1.2],
-        [\rgbSynth, 550, 0.18, -0.2, 0.02, 0.7],
-        [\rgbSynth, 660, 0.15, 0.3, 0.05, 1.0]
-    ];
-    
-    testParams.do { |params, i|
-        var synthType, freq, amp, pan, attack, release;
-        #synthType, freq, amp, pan, attack, release = params;
-        
-        // Create the synth with the specified parameters
-        Synth(synthType, [
-            \out, ~sourceBus ? 0,
-            \freq, freq,
-            \amp, amp,
-            \pan, pan,
-            \ampAttack, attack,
-            \ampRelease, release,
-            \redAmt, ~synthParams.redAmt ? 0.5,
-            \greenAmt, ~synthParams.greenAmt ? 0.5,
-            \blueAmt, ~synthParams.blueAmt ? 0.5
-        ]);
-        
-        // Change effect parameters for demonstration
-        if(~filterSynth.notNil and: { ~filterSynth.isPlaying }, {
-            ~filterSynth.set(\cutoff, 500 + (i * 1000));
-        });
-        if(~delaySynth.notNil and: { ~delaySynth.isPlaying }, {
-            ~delaySynth.set(\mix, 0.2 + (i * 0.1));
-        });
-        if(~reverbSynth.notNil and: { ~reverbSynth.isPlaying }, {
-            ~reverbSynth.set(\room, 0.3 + (i * 0.1));
-        });
-        
-        // Log the current sound
-        ["Testing synth:", synthType, freq, amp].postln;
-    };
-    
-    "Parameter test complete".postln;
-};
-
-// Test function that creates sounds with scheduled timing (safer approach)
-~testSequence = {
-    var sounds = [
-        [440, 0.2, 0.1, 1.0],
-        [330, 0.15, 0.2, 0.8],
-        [550, 0.18, 0.3, 0.7],
-        [660, 0.12, 0.4, 0.9],
-        [220, 0.25, 0.5, 1.2]
-    ];
-    
-    // Start effects chain if needed
-    if(~effectsChain.isNil, { ~startEffectsChain.value; });
-    
-    sounds.do { |params, i|
-        var freq, amp, delay, release;
-        #freq, amp, delay, release = params;
-        
-        // Schedule each sound with SystemClock (safer than Routine)
-        SystemClock.sched(delay * i, {
-            Synth(\rgbSynth, [
-                \out, ~sourceBus ? 0,
-                \freq, freq,
-                \amp, amp,
-                \ampRelease, release,
-                \redAmt, ~synthParams.redAmt ? 0.5,
-                \greenAmt, ~synthParams.greenAmt ? 0.5,
-                \blueAmt, ~synthParams.blueAmt ? 0.5
-            ]);
-            
-            ["Scheduled sound:", freq, amp].postln;
-            nil; // Don't reschedule
-        });
-    };
-    
-    "Test sequence scheduled".postln;
-};
-
-// Function to simulate touch input safely
-~simulateTouch = { |count=5|
-    var touchCount = 0;
-    
-    "Simulating % touch events".format(count).postln;
-    
-    // Start the effects chain if needed
-    if(~effectsChain.isNil, { ~startEffectsChain.value; });
-    
-    // Schedule touch events
-    count.do { |i|
-        SystemClock.sched(i * 0.5, {
-            var x = (-0.5 + 1.0.rand);
-            var y = (-0.5 + 1.0.rand);
-            var pressure = 1 + 7.rand;
-            
-            // Update pad values
-            ~currentPadValues.x = x;
-            ~currentPadValues.y = y;
-            ~currentPadValues.pressure = pressure;
-            
-            // Trigger the change effect params function
-            if(~changeEffectParams.notNil, {
-                ~changeEffectParams.value;
-            });
-            
-            // Trigger sound if using appropriate pen type
-            if(~triggerSound.notNil, {
-                ~triggerSound.value;
-            });
-            
-            touchCount = touchCount + 1;
-            ["Simulated touch #%: x=%, y=%, pressure=%".format(touchCount, x.round(0.01), y.round(0.01), pressure.round(0.01))].postln;
-            
-            nil; // Don't reschedule
-        });
-    };
-    
-    // Schedule completion message
-    SystemClock.sched(count * 0.5 + 1, {
-        "Touch simulation complete".postln;
-        nil;
-    });
-};
-
-// Memory monitoring function
-~checkMemory = {
-    var serverStatus = s.queryAllNodes;
-    var activeSynths = s.numSynths;
-    var activeGroups = s.numGroups;
-    
-    "=== Memory Status ===".postln;
-    "Active synths: %".format(activeSynths).postln;
-    "Active groups: %".format(activeGroups).postln;
-    
-    if(~midiSynths.notNil, {
-        "Active MIDI synths: %".format(~midiSynths.size).postln;
-    });
-    
-    if(~activeSynths.notNil, {
-        "Active OSC synths: %".format(~activeSynths.size).postln;
-    });
-    
-    // Warning if too many synths
-    if(activeSynths > 50, {
-        "WARNING: High number of active synths (%). Consider running cleanup.".format(activeSynths).postln;
-    });
-    
-    "===================".postln;
-};
-
-// Emergency cleanup function
-~emergencyCleanup = {
-    "EMERGENCY CLEANUP - Stopping all sounds".postln;
-    
-    // Free all synths on server
-    s.freeAll;
-    
-    // Clear all tracking dictionaries
-    if(~midiSynths.notNil, { ~midiSynths.clear; });
-    if(~activeSynths.notNil, { ~activeSynths.clear; });
-    if(~touchSynths.notNil, { ~touchSynths.clear; });
-    
-    // Clear buses
-    ~stopEffectsChain.value;
-    
-    // Reset counters
-    ~synthCounter = 0;
-    
-    "Emergency cleanup complete".postln;
-    
-    // Wait a moment then restart effects
-    SystemClock.sched(1, {
-        ~startEffectsChain.value;
-        nil;
-    });
-};
-
-// Register emergency cleanup with Cmd+Period
-CmdPeriod.add({
-    ~emergencyCleanup.value;
-});
-
-"Test functions loaded with memory management.".postln;
-"Available test functions:".postln;
-"  ~testParameters.value        - Test different synth parameters".postln;
-"  ~testSequence.value          - Test scheduled sound sequence".postln;
-"  ~simulateTouch.value(10)     - Simulate 10 touch events".postln;
-"  ~checkMemory.value           - Check current memory usage".postln;
-"  ~emergencyCleanup.value      - Emergency cleanup all sounds".postln;
-"  ~resetSystem.value           - Complete system reset".postln;
-)

+ 0 - 110
SC/7_idraw_connection.scd

@@ -1,110 +0,0 @@
-(
-// Function to test iDraw OSC connection
-~testiDrawConnection = {
-    var interfaces, ip;
-
-    // Log local IP and port information
-    "SuperCollider OSC server info for iDraw OSC connection:".postln;
-    "Hostname: %".format(Platform.myHostName).postln;
-    "Local IP addresses:".postln;
-
-    try {
-        interfaces = "ifconfig".unixCmdGetStdOutLines;
-        interfaces.do { |line|
-            if(line.containsi("inet ") && line.containsStringAt(0, "inet").not, {
-                line = line.replace("\t", "").replace(" ", "");
-                ip = line.findRegexp("inet([0-9.]+)")[1][1];
-                "  %".format(ip).postln;
-            });
-        };
-    } { |err|
-        "Could not detect network interfaces: %".format(err).postln;
-    };
-
-    // Alternate way to find IP addresses that might work better on some systems
-    "Alternative method to find IP addresses:".postln;
-    try {
-        thisProcess.platform.getNetworkNameList.do { |netname|
-            var addr = netname.findRegexp("\\d+\\.\\d+\\.\\d+\\.\\d+");
-            if(addr.size > 0, {
-                "  %".format(addr[0][1]).postln;
-            });
-        };
-    } { |err|
-        "Could not use network name list method: %".format(err).postln;
-    };
-
-    "OSC Port: 57120".postln;
-    "".postln;
-    "To connect from iDraw OSC:".postln;
-    "1. Ensure iPad/iPhone is on the same WiFi network".postln;
-    "2. Open iDraw OSC app".postln;
-    "3. Set the host/IP to one of the above addresses".postln;
-    "4. Set the port to 57120".postln;
-    "5. Ensure iDraw OSC is sending messages with these addresses:".postln;
-    "   - /touch (x, y, pressure)".postln;
-    "   - /pen (pen type)".postln;
-    "   - /color (r, g, b)".postln;
-};
-
-// Function to simulate iDraw OSC messages for testing
-~simulateiDrawTouch = { |duration=10|
-    var endTime, penTypes, penType, r, g, b;
-
-    endTime = SystemClock.seconds + duration;
-    "Simulating iDraw OSC touch events for % seconds".format(duration).postln;
-
-    // Start the effects chain if needed
-    if(~effectsChain.isNil, { ~startEffectsChain.value; });
-
-    // First set a pen type
-    penTypes = [\pen, \monoline, \marker, \pencil, \crayon, \fountainPen, \waterColor];
-    penType = penTypes.choose;
-
-    OSCdef(\penTypeOSC).value(['/pen', penType], nil, nil, nil);
-
-    // Set a random color
-    r = 1.0.rand;
-    g = 1.0.rand;
-    b = 1.0.rand;
-
-    OSCdef(\colorOSC).value(['/color', r, g, b], nil, nil, nil);
-
-    // Generate simulated touch events
-    fork {
-        while { SystemClock.seconds < endTime } {
-            var x = (-0.5 + 1.0.rand);
-            var y = (-0.5 + 1.0.rand);
-            var pressure = 1 + 7.rand;
-
-            // Send touch message
-            OSCdef(\touchOSC).value(['/touch', x, y, pressure], nil, nil, nil);
-
-            // Wait random time between touch events
-            rrand(0.1, 0.3).wait;
-
-            // Occasionally change pen type or color
-            if(0.1.coin, {
-                penType = penTypes.choose;
-                OSCdef(\penTypeOSC).value(['/pen', penType], nil, nil, nil);
-                "Changed to pen type: %".format(penType).postln;
-            });
-
-            if(0.1.coin, {
-                r = 1.0.rand;
-                g = 1.0.rand;
-                b = 1.0.rand;
-                OSCdef(\colorOSC).value(['/color', r, g, b], nil, nil, nil);
-                "Changed to color: % % %".format(r, g, b).postln;
-            });
-        };
-
-        "iDraw OSC simulation complete".postln;
-    };
-};
-
-// Run these functions directly
-"iDraw OSC connection test functions loaded.".postln;
-"To test connection info, run: ~testiDrawConnection.value".postln;
-"To simulate iDraw OSC events, run: ~simulateiDrawTouch.value(20)".postln;
-)

+ 0 - 82
SC/8_mobile_connection.scd

@@ -1,82 +0,0 @@
-(
-// Function to test mobile connection
-~testMobileConnection = {
-    var interfaces, ip; // Declare variables here
-    "SuperCollider OSC server info:".postln;
-    "Hostname: %".format(Platform.myHostName).postln;
-    "Local IP addresses:".postln;
-
-    try {
-        interfaces = "ifconfig".unixCmdGetStdOutLines;
-        interfaces.do { |line|
-            if(line.containsi("inet ") && line.containsStringAt(0, "inet").not, {
-                line = line.replace("\t", "").replace(" ", "");
-                ip = line.findRegexp("inet([0-9.]+)")[1][1];
-                "  %".format(ip).postln;
-            });
-        };
-    } { |err|
-        "Could not detect network interfaces: %".format(err).postln;
-    };
-
-    "OSC Port: 57120".postln;
-    "".postln;
-    "To connect from a mobile device:".postln;
-    "1. Ensure mobile device is on the same WiFi network".postln;
-    "2. Use one of the IP addresses above in your mobile OSC app".postln;
-    "3. Set the port to 57120".postln;
-};
-
-// Function to simulate mobile touch for testing without a mobile device
-~simulateMobileTouch = { |duration=10|
-    var endTime = SystemClock.seconds + duration;
-    var touchId = 1000;
-
-    "Simulating mobile touch events for % seconds".format(duration).postln;
-
-    // Start the effects chain if needed
-    if(~effectsChain.isNil, { ~startEffectsChain.value; });
-
-    // Generate simulated touch events
-    fork {
-        while { SystemClock.seconds < endTime } {
-            var x = 1.0.rand;
-            var y = 1.0.rand;
-            var pressure = 0.3 + 0.7.rand;
-            var state = [\began, \moved, \ended].choose;
-
-            // Create realistic touch sequences
-            if(state == \began, {
-                touchId = touchId + 1;
-                OSCdef(\touchOSC).value(['/touch', touchId, x, y, \began, pressure], nil, nil, nil);
-
-                // Simulate some movement for this touch
-                fork {
-                    var moveCount = rrand(3, 8);
-                    moveCount.do {
-                        0.1.wait;
-                        // Slight movement from original position
-                        x = (x + 0.1.rand2).clip(0, 1);
-                        y = (y + 0.1.rand2).clip(0, 1);
-                        OSCdef(\touchOSC).value(['/touch', touchId, x, y, \moved, pressure], nil, nil, nil);
-                    };
-
-                    // End the touch
-                    0.2.wait;
-                    OSCdef(\touchOSC).value(['/touch', touchId, x, y, \ended, pressure], nil, nil, nil);
-                };
-            });
-
-            // Wait random time between new touch events
-            rrand(0.2, 1.0).wait;
-        };
-
-        "Mobile touch simulation complete".postln;
-    };
-};
-
-// Run these functions directly
-"Mobile connection test functions loaded.".postln;
-"To test connection info, run: ~testMobileConnection.value".postln;
-"To simulate mobile touch events, run: ~simulateMobileTouch.value(20)".postln;
-)

+ 37 - 134
SC/9_midi_controller.scd

@@ -1,153 +1,56 @@
-// Module 9: MIDI Controller - FIXED FOR MEMORY MANAGEMENT
-// Save as "9_midi_controller.scd"
-
+// MIDI note handling
 (
-// MIDI note handling with proper memory management
-var midiIn, synths;
-
-~midiSynths = IdentityDictionary.new;  // Store active synths keyed by note number
-~midiCleanupTask = nil; // For scheduled cleanup
-
-// Function to cleanup old MIDI synths
-~cleanupMIDISynths = {
-	var toRemove = Array.new;
-	
-	~midiSynths.keysValuesDo({ |noteNum, synth|
-		if(synth.isPlaying.not, {
-			toRemove.add(noteNum);
-		});
-	});
-	
-	toRemove.do({ |noteNum|
-		~midiSynths.removeAt(noteNum);
-	});
-	
-	// Log cleanup if synths were removed
-	if(toRemove.size > 0, {
-		["Cleaned up % inactive MIDI synths".format(toRemove.size)].postln;
-	});
-};
-
-// Function to force cleanup if too many synths are active
-~forceMIDICleanup = {
-	if(~midiSynths.size > 20, {
-		var oldestNotes = ~midiSynths.keys.asArray.copyRange(0, ~midiSynths.size - 15);
-		oldestNotes.do({ |noteNum|
-			if(~midiSynths[noteNum].notNil, {
-				~midiSynths[noteNum].set(\gate, 0);
-				~midiSynths.removeAt(noteNum);
-			});
-		});
-		["Force cleaned up % MIDI synths".format(oldestNotes.size)].postln;
-	});
-};
-
-// Start periodic cleanup task
-~startMIDICleanupTask = {
-	if(~midiCleanupTask.notNil, { ~midiCleanupTask.stop; });
-	
-	~midiCleanupTask = Task({
-		loop {
-			3.wait; // Wait 3 seconds between cleanups
-			~cleanupMIDISynths.value;
-			~forceMIDICleanup.value;
-		}
-	}).play;
-	
-	"MIDI cleanup task started".postln;
-};
-
-// Stop cleanup task
-~stopMIDICleanupTask = {
-	if(~midiCleanupTask.notNil, {
-		~midiCleanupTask.stop;
-		~midiCleanupTask = nil;
-		"MIDI cleanup task stopped".postln;
-	});
-};
+var midiIn, synths, activeNotes;
 
 // Connect to MIDI
 MIDIClient.init;
 MIDIIn.connectAll;
 
-// Note On: create synth
+
+// Note On: add num to activeNotes and set synth gate to 1
 MIDIdef.noteOn(\noteOn, { |vel, num, chan, src|
     var freq = num.midicps;
+	var index;
+
+	//postln("Note On: " + num + " Velocity: " + vel);
 
     if (vel > 0) {
-		// Check if note is already playing and release it first
-		if(~midiSynths[num].notNil, {
-			~midiSynths[num].set(\gate, 0);
-			~midiSynths.removeAt(num);
-		});
-		
-		// Force cleanup if too many synths
-		~forceMIDICleanup.value;
-		
-		// Create new synth with proper parameters
-        var synth = Synth(\rgbSynth, [
-			\freq, freq,
-			\amp, (vel/127) * 0.5, // Reduce amplitude to prevent overload
-			\ampAttack, ~synthParams.ampAttack ? 0.01,
-			\ampRelease, ~synthParams.ampRelease ? 1,
-			\filterAttack, ~synthParams.filterAttack ? 0,
-			\filterRelease, ~synthParams.filterRelease ? 0,
-			\pitchAttack, ~synthParams.pitchAttack ? 0,
-			\pitchRelease, ~synthParams.pitchRelease ? 0,
-			\redAmt, ~synthParams.redAmt ? 0.5,
-			\greenAmt, ~synthParams.greenAmt ? 0.5,
-			\blueAmt, ~synthParams.blueAmt ? 0.5,
-			\out, ~sourceBus ? 0
-		]);
-		
-        ~midiSynths[num] = synth;
-		
-		// Schedule automatic cleanup for sustained notes
-		SystemClock.sched(10, { // Auto-cleanup after 10 seconds maximum
-			if(~midiSynths[num] == synth, {
-				synth.set(\gate, 0);
-				~midiSynths.removeAt(num);
-			});
-			nil; // Don't reschedule
-		});
 
-    } { 
-		// Treat as noteOff if it is a noteOn with velocity 0
-		if(~midiSynths[num].notNil, {
-			~midiSynths[num].set(\gate, 0);
-			~midiSynths.removeAt(num);
-		});
+		// Find first available (nil) slot
+		index = ~activeNotes.detectIndex({ |s| s.isNil });
+        if (index.notNil) {
+			~synths[index].set(\gate, 1);
+			~synths[index].set(\freq, freq);
+			~synths[index].set(\amp, vel/127);
+            ~activeNotes[index] = num; // Map note to synth index
+        } {
+            "No available synth slots!".postln;
+        }
+
+    } { // Treat as noteOff if it is a noteOn with velocity 0
+		index = ~activeNotes.detectIndex({ |s| (s == num) });
+		if (index.notNil) {
+			~activeNotes[index] = nil;
+			~synths[index].set(\gate, 0);
+		}
 	}
 });
 
-// Note Off: release synth
+// Note Off: set synth gate to 0 and remove num from activeNotes
 MIDIdef.noteOff(\noteOff, { |vel, num, chan, src|
-	if(~midiSynths[num].notNil, {
-		~midiSynths[num].set(\gate, 0);
-		~midiSynths.removeAt(num);
-	});
-});
-
-// Cleanup all MIDI synths function
-~cleanupAllMIDISynths = {
-	~midiSynths.keysValuesDo({ |noteNum, synth|
-		synth.set(\gate, 0);
-	});
-	~midiSynths.clear;
-	~stopMIDICleanupTask.value;
-	"All MIDI synths cleaned up".postln;
-};
+	var index;
 
-// Start the cleanup task
-~startMIDICleanupTask.value;
+	//postln("Note Off: " + num + " Velocity: " + vel);
 
-// Register cleanup with CmdPeriod
-CmdPeriod.add({
-	~cleanupAllMIDISynths.value;
+	index = ~activeNotes.detectIndex({ |s| (s == num) });
+	if (index.notNil) {
+		~activeNotes[index] = nil;
+		~synths[index].set(\gate, 0);
+	}
 });
 
-"MIDI functions loaded with memory management.".postln;
-"Active MIDI synths will be automatically cleaned up.".postln;
-"To manually cleanup all MIDI synths: ~cleanupAllMIDISynths.value".postln;
-"Current active MIDI synths: % can be checked with ~midiSynths.size".postln;
-)
+
+// Run these functions directly
+"MIDI functions loaded.".postln;
+)
+

+ 0 - 17
SC/main.scd

@@ -1,17 +0,0 @@
-// Initialize the system
-(
-s.waitForBoot({
-    "Initializing Interactive Sound Canvas...".postln;
-
-    // Start effects chain
-    ~startEffectsChain.value;
-
-    // System is ready for input
-    "System ready! Touch data can now be received via OSC.".postln;
-    "To test the system, run: ~runParameterTest.value".postln;
-    "To simulate touch input, run: ~runTouchSimulation.value(10)".postln;
-});
-)
-
-~runParameterTest.value
-~runTouchSimulation.value(10)