Farnoosh Rad 6 ヶ月 前
コミット
60adf725f6
1 ファイル変更114 行追加69 行削除
  1. 114 69
      SC/5_osc_communication.scd

+ 114 - 69
SC/5_osc_communication.scd

@@ -1,5 +1,5 @@
-// Module 5: OSC Communication Setup - FIXED FOR MEMORY MANAGEMENT
-// Save as "5_osc_communication.scd"
+// Module 5: OSC Communication Setup - FIXED FOR PROPER TOUCH MANAGEMENT
+// Save as "5_osc_communication.scd" (REPLACE THE PREVIOUS VERSION)
 
 (
 // Clear any existing OSC definitions
@@ -10,9 +10,13 @@ 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
 
-// Track active synths to prevent memory leaks
-~activeSynths = IdentityDictionary.new;
-~synthCounter = 0;
+// Touch state management
+~touchState = (
+    isActive: false,
+    currentSynth: nil,
+    lastTriggerTime: 0,
+    minTriggerInterval: 0.1  // Minimum time between new synths (100ms)
+);
 
 ~synthParams = (
 	out: 0,
@@ -32,6 +36,10 @@ OSCdef.freeAll;
 	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|
@@ -41,8 +49,8 @@ OSCdef.freeAll;
 	});
 	
 	// If too many synths are active, force cleanup of oldest ones
-	if(~activeSynths.size > 10, {
-		var oldestKeys = ~activeSynths.keys.asArray.sort.copyRange(0, ~activeSynths.size - 6);
+	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);
@@ -52,7 +60,7 @@ OSCdef.freeAll;
 	});
 };
 
-// Function to create a new synth safely
+// Function to create a new synth safely (only when needed)
 ~createSafeSynth = { |synthType = \rgbSynth, args|
 	var synth, synthId;
 	
@@ -91,23 +99,84 @@ OSCdef.freeAll;
 	synth;
 };
 
-// Define OSC responder for creating sounds (only for envelope-controlling pens)
-~triggerSound = {
+// 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.8);
+    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), {
-        ~createSafeSynth.value(\rgbSynth, [
+        // 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
         ]);
         
-        ["Sound triggered:", ~currentPenType, freq, amp].postln;
+        ~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;
     });
 };
 
@@ -117,10 +186,7 @@ OSCdef.freeAll;
     var y = ~currentPadValues.y;
     var pressure = ~currentPadValues.pressure;
 
-    // Log the received data
-    ["Touch data:", x, y, pressure, ~currentPenType, ~currentColor].postln;
-
-    // Handle touch based on current pen type
+    // Update synthesis parameters but DON'T log every change to avoid spam
     switch(~currentPenType.asSymbol,
         // Pen - Controls amplitude envelope
 		\pen, {
@@ -129,8 +195,6 @@ OSCdef.freeAll;
 
 			~synthParams.ampAttack = ampAttack;
 			~synthParams.ampRelease = ampRelease;
-
-            ["Amplitude envelope:", ampAttack, ampRelease].postln;
         },
 
         // Monoline - Controls filter envelope
@@ -140,8 +204,6 @@ OSCdef.freeAll;
 
 			~synthParams.filterAttack = filterAttack;
 			~synthParams.filterRelease = filterRelease;
-
-            ["Filter envelope:", filterAttack, filterRelease].postln;
         },
 
         // Marker - Controls pitch envelope
@@ -151,8 +213,6 @@ OSCdef.freeAll;
 
 			~synthParams.pitchAttack = pitchAttack;
 			~synthParams.pitchRelease = pitchRelease;
-
-            ["Pitch envelope:", pitchAttack, pitchRelease].postln;
         },
 
         // Pencil - Effect preset 1
@@ -177,8 +237,6 @@ OSCdef.freeAll;
                     \room, 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
@@ -209,20 +267,16 @@ OSCdef.freeAll;
                     \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, {
             // Apply Preset 3 effects (TBD in documentation)
-            ["Fountain pen preset (TBD)"].postln;
         },
 
         // Water color - Effect preset 4 (placeholder)
 		\waterColor, {
             // Apply Preset 4 effects (TBD in documentation)
-            ["Water color preset (TBD)"].postln;
         }
     );
 };
@@ -235,6 +289,11 @@ 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');
 
@@ -245,10 +304,15 @@ 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
+// OSC responder for pressure coordinate - THIS IS THE KEY ONE
 OSCdef(\pressureOSC, { |msg, time, addr, port|
     var pressure = msg[1].asFloat;
 
@@ -256,140 +320,121 @@ OSCdef(\pressureOSC, { |msg, time, addr, port|
     ~currentPadValues.pressure = pressure;
 	~changeEffectParams.value;
 	
-	// Trigger sound for envelope-controlling pens
-	~triggerSound.value;
+	// Use smart trigger logic instead of always creating new synths
+	~smartTriggerSound.value;
 
 }, '/pressure');
 
-// ----- OSC Pen Types -----
-// OSC responder for pen
+// ----- OSC Pen Types ----- (unchanged)
 OSCdef(\penOSC, { |msg, time, addr, port|
     var penType = msg[1].asFloat;
-
 	if (penType == 1.0) {
 		~currentPenType = \pen;
 		["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;
 		["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;
 		["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; });
 		["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; });
 		["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; });
 		["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; });
 		["Current pen type:", ~currentPenType].postln;
 	}
-
 }, '/waterColor');
 
-// ----- OSC RGB Colors -----
-// OSC responder for red changes
+// ----- OSC RGB Colors ----- (unchanged)
 OSCdef(\redOSC, { |msg, time, addr, port|
     var component = msg[1].asFloat;
-
-    // Update current color
     ~currentColor.r = component;
 	~synthParams.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;
-
     ["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;
-
     ["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".postln;
-"Registered OSC commands for pad values, pen types, and colors".postln;
+"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;
 "Ready to receive data from iDraw OSC app".postln;
 "To cleanup system, run: ~cleanupOSCSystem.value".postln;
 )