6_test_functions.scd 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. // Module 6: Test Functions & Effect Chain Setup - FIXED (No s.sync)
  2. // Save as "6_test_functions.scd" (REPLACE YOUR EXISTING VERSION)
  3. (
  4. // Function to start effects chain - FIXED VERSION
  5. ~startEffectsChain = {
  6. // Stop existing effects first
  7. ~stopEffectsChain.value;
  8. "Starting effects chain...".postln;
  9. // Create audio buses for effects chain
  10. ~sourceBus = Bus.audio(s, 2);
  11. ~reverbBus = Bus.audio(s, 2);
  12. ~delayBus = Bus.audio(s, 2);
  13. ~filterBus = Bus.audio(s, 2);
  14. // Create control buses for modulation
  15. ~lfoControlBus = Bus.control(s, 1);
  16. // Create effects synths in chain with error handling
  17. try {
  18. ~filterSynth = Synth(\lpf, [
  19. \in, ~sourceBus,
  20. \out, ~delayBus,
  21. \cutoff, 1000,
  22. \res, 0.5
  23. ]);
  24. ~delaySynth = Synth(\delay, [
  25. \in, ~delayBus,
  26. \out, ~reverbBus,
  27. \delaytime, 0.4,
  28. \feedback, 0.3,
  29. \mix, 0.3
  30. ], ~filterSynth, \addAfter);
  31. ~reverbSynth = Synth(\reverb, [
  32. \in, ~reverbBus,
  33. \out, 0,
  34. \mix, 0.2,
  35. \room, 0.5,
  36. \damp, 0.5
  37. ], ~delaySynth, \addAfter);
  38. // Create LFO separately
  39. ~lfoSynth = Synth(\lfoEffect, [
  40. \out, ~lfoControlBus,
  41. \freq, 1,
  42. \min, 100,
  43. \max, 5000,
  44. \waveform, 0
  45. ]);
  46. // Schedule LFO mapping after a short delay (instead of s.sync)
  47. SystemClock.sched(0.1, {
  48. if(~filterSynth.notNil and: { ~lfoControlBus.notNil }, {
  49. try {
  50. ~filterSynth.map(\cutoff, ~lfoControlBus);
  51. "LFO mapped to filter cutoff".postln;
  52. } { |error|
  53. "Warning: Could not map LFO to filter: %".format(error).postln;
  54. };
  55. });
  56. nil; // Don't reschedule
  57. });
  58. // Store the effects chain nodes in an array for easy access
  59. ~effectsChain = [~filterSynth, ~delaySynth, ~reverbSynth, ~lfoSynth];
  60. "Effects chain started successfully".postln;
  61. "Chain includes: Filter -> Delay -> Reverb + LFO".postln;
  62. } { |error|
  63. "Error starting effects chain: %".format(error).postln;
  64. ~stopEffectsChain.value;
  65. };
  66. };
  67. // Function to stop effects chain
  68. ~stopEffectsChain = {
  69. if(~effectsChain.notNil, {
  70. ~effectsChain.do({ |synth|
  71. if(synth.notNil, {
  72. try {
  73. synth.free;
  74. } { |error|
  75. // Silent cleanup
  76. };
  77. });
  78. });
  79. ~effectsChain = nil;
  80. });
  81. // Free individual synth references
  82. [~filterSynth, ~delaySynth, ~reverbSynth, ~lfoSynth].do({ |synth|
  83. if(synth.notNil, {
  84. try {
  85. synth.free;
  86. } { |error|
  87. // Silent cleanup
  88. };
  89. });
  90. });
  91. ~filterSynth = nil;
  92. ~delaySynth = nil;
  93. ~reverbSynth = nil;
  94. ~lfoSynth = nil;
  95. // Free buses
  96. [~sourceBus, ~reverbBus, ~delayBus, ~filterBus, ~lfoControlBus].do({ |bus|
  97. if(bus.notNil, {
  98. try {
  99. bus.free;
  100. } { |error|
  101. // Silent cleanup
  102. };
  103. });
  104. });
  105. ~sourceBus = nil;
  106. ~reverbBus = nil;
  107. ~delayBus = nil;
  108. ~filterBus = nil;
  109. ~lfoControlBus = nil;
  110. "Effects chain stopped and cleaned up".postln;
  111. };
  112. // Function to reset the entire system
  113. ~resetSystem = {
  114. // Stop all effects
  115. ~stopEffectsChain.value;
  116. // Clear OSC system if it exists
  117. if(~cleanupOSCSystem.notNil, {
  118. try { ~cleanupOSCSystem.value; } { |error| };
  119. });
  120. // Clear MIDI system if it exists
  121. if(~cleanupAllMIDI.notNil, {
  122. try { ~cleanupAllMIDI.value; } { |error| };
  123. });
  124. // Clear synth pool if it exists
  125. if(~cleanupSynthPool.notNil, {
  126. try { ~cleanupSynthPool.value; } { |error| };
  127. });
  128. // Clear all OSC definitions
  129. OSCdef.freeAll;
  130. // Reset touch synths tracking
  131. ~touchSynths = ();
  132. "System reset complete".postln;
  133. // Restart effects chain
  134. SystemClock.sched(0.5, {
  135. ~startEffectsChain.value;
  136. nil;
  137. });
  138. };
  139. // Test function for parameter changes - FIXED to not use problematic timing
  140. ~testParameters = {
  141. // Start effects chain if not already running
  142. if(~effectsChain.isNil, { ~startEffectsChain.value; });
  143. // Test different oscillator types with varying parameters
  144. var testParams = [
  145. [\rgbSynth, 440, 0.2, -0.5, 0.05, 0.5],
  146. [\rgbSynth, 330, 0.15, 0, 0.01, 0.8],
  147. [\rgbSynth, 220, 0.1, 0.5, 0.1, 1.2],
  148. [\rgbSynth, 550, 0.18, -0.2, 0.02, 0.7],
  149. [\rgbSynth, 660, 0.15, 0.3, 0.05, 1.0]
  150. ];
  151. testParams.do { |params, i|
  152. var synthType, freq, amp, pan, attack, release;
  153. #synthType, freq, amp, pan, attack, release = params;
  154. // Create the synth with the specified parameters
  155. Synth(synthType, [
  156. \out, ~sourceBus ? 0,
  157. \freq, freq,
  158. \amp, amp,
  159. \pan, pan,
  160. \ampAttack, attack,
  161. \ampRelease, release,
  162. \redAmt, ~synthParams.redAmt ? 0.5,
  163. \greenAmt, ~synthParams.greenAmt ? 0.5,
  164. \blueAmt, ~synthParams.blueAmt ? 0.5
  165. ]);
  166. // Change effect parameters for demonstration
  167. if(~filterSynth.notNil, {
  168. try {
  169. ~filterSynth.set(\cutoff, 500 + (i * 1000));
  170. } { |error| };
  171. });
  172. if(~delaySynth.notNil, {
  173. try {
  174. ~delaySynth.set(\mix, 0.2 + (i * 0.1));
  175. } { |error| };
  176. });
  177. if(~reverbSynth.notNil, {
  178. try {
  179. ~reverbSynth.set(\room, 0.3 + (i * 0.1));
  180. } { |error| };
  181. });
  182. // Log the current sound
  183. ["Testing synth:", synthType, freq, amp].postln;
  184. };
  185. "Parameter test complete".postln;
  186. };
  187. // Test function that creates sounds with scheduled timing (safer approach)
  188. ~testSequence = {
  189. var sounds = [
  190. [440, 0.2, 0.1, 1.0],
  191. [330, 0.15, 0.2, 0.8],
  192. [550, 0.18, 0.3, 0.7],
  193. [660, 0.12, 0.4, 0.9],
  194. [220, 0.25, 0.5, 1.2]
  195. ];
  196. // Start effects chain if needed
  197. if(~effectsChain.isNil, { ~startEffectsChain.value; });
  198. sounds.do { |params, i|
  199. var freq, amp, delay, release;
  200. #freq, amp, delay, release = params;
  201. // Schedule each sound with SystemClock (safer than Routine)
  202. SystemClock.sched(delay * i, {
  203. Synth(\rgbSynth, [
  204. \out, ~sourceBus ? 0,
  205. \freq, freq,
  206. \amp, amp,
  207. \ampRelease, release,
  208. \redAmt, ~synthParams.redAmt ? 0.5,
  209. \greenAmt, ~synthParams.greenAmt ? 0.5,
  210. \blueAmt, ~synthParams.blueAmt ? 0.5
  211. ]);
  212. ["Scheduled sound:", freq, amp].postln;
  213. nil; // Don't reschedule
  214. });
  215. };
  216. "Test sequence scheduled".postln;
  217. };
  218. // Function to simulate touch input safely
  219. ~simulateTouch = { |count=5|
  220. var touchCount = 0;
  221. "Simulating % touch events".format(count).postln;
  222. // Start the effects chain if needed
  223. if(~effectsChain.isNil, { ~startEffectsChain.value; });
  224. // Schedule touch events
  225. count.do { |i|
  226. SystemClock.sched(i * 0.5, {
  227. var x = (-0.5 + 1.0.rand);
  228. var y = (-0.5 + 1.0.rand);
  229. var pressure = 1 + 7.rand;
  230. // Update pad values
  231. ~currentPadValues.x = x;
  232. ~currentPadValues.y = y;
  233. ~currentPadValues.pressure = pressure;
  234. // Trigger the change effect params function
  235. if(~changeEffectParams.notNil, {
  236. try {
  237. ~changeEffectParams.value;
  238. } { |error|
  239. "Error in changeEffectParams: %".format(error).postln;
  240. };
  241. });
  242. // Trigger sound if using appropriate pen type
  243. if(~smartTriggerSound.notNil, {
  244. try {
  245. ~smartTriggerSound.value;
  246. } { |error|
  247. "Error in smartTriggerSound: %".format(error).postln;
  248. };
  249. });
  250. touchCount = touchCount + 1;
  251. ["Simulated touch #%: x=%, y=%, pressure=%".format(touchCount, x.round(0.01), y.round(0.01), pressure.round(0.01))].postln;
  252. nil; // Don't reschedule
  253. });
  254. };
  255. // Schedule completion message
  256. SystemClock.sched(count * 0.5 + 1, {
  257. "Touch simulation complete".postln;
  258. nil;
  259. });
  260. };
  261. // Memory monitoring function
  262. ~checkMemory = {
  263. var activeSynths = s.numSynths;
  264. var activeGroups = s.numGroups;
  265. "=== Memory Status ===".postln;
  266. "Active synths: %".format(activeSynths).postln;
  267. "Active groups: %".format(activeGroups).postln;
  268. if(~midiNoteKeys.notNil, {
  269. "Active MIDI notes: %".format(~midiNoteKeys.size).postln;
  270. });
  271. if(~activeSynths.notNil, {
  272. "Active pool synths: %".format(~activeSynths.size).postln;
  273. });
  274. if(~effectsChain.notNil, {
  275. "Effects chain active: true".postln;
  276. }, {
  277. "Effects chain active: false".postln;
  278. });
  279. // Warning if too many synths
  280. if(activeSynths > 50, {
  281. "WARNING: High number of active synths (%). Consider running cleanup.".format(activeSynths).postln;
  282. });
  283. "===================".postln;
  284. };
  285. // Emergency cleanup function
  286. ~emergencyCleanup = {
  287. "EMERGENCY CLEANUP - Stopping all sounds".postln;
  288. // Free all synths on server
  289. s.freeAll;
  290. // Clear all tracking dictionaries
  291. if(~midiNoteKeys.notNil, { ~midiNoteKeys.clear; });
  292. if(~activeSynths.notNil, { ~activeSynths.clear; });
  293. if(~touchSynths.notNil, { ~touchSynths.clear; });
  294. // Clear buses and effects
  295. ~stopEffectsChain.value;
  296. // Reset pool if it exists
  297. if(~cleanupSynthPool.notNil, {
  298. try {
  299. ~cleanupSynthPool.value;
  300. } { |error|
  301. "Error during pool cleanup: %".format(error).postln;
  302. };
  303. });
  304. "Emergency cleanup complete".postln;
  305. // Wait a moment then restart effects
  306. SystemClock.sched(1, {
  307. ~startEffectsChain.value;
  308. nil;
  309. });
  310. };
  311. // Register emergency cleanup with Cmd+Period
  312. CmdPeriod.add({
  313. ~emergencyCleanup.value;
  314. });
  315. "Test functions loaded with NO S.SYNC CALLS.".postln;
  316. "Available test functions:".postln;
  317. " ~startEffectsChain.value - Start the effects chain".postln;
  318. " ~stopEffectsChain.value - Stop the effects chain".postln;
  319. " ~testParameters.value - Test different synth parameters".postln;
  320. " ~testSequence.value - Test scheduled sound sequence".postln;
  321. " ~simulateTouch.value(10) - Simulate 10 touch events".postln;
  322. " ~checkMemory.value - Check current memory usage".postln;
  323. " ~emergencyCleanup.value - Emergency cleanup all sounds".postln;
  324. " ~resetSystem.value - Complete system reset".postln;
  325. )