9_midi_controller.scd 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // Module 9: MIDI Controller - Modified to use Synth Pool
  2. // Save as "9_midi_controller.scd" (REPLACE YOUR EXISTING VERSION)
  3. (
  4. // MIDI note handling using synth pool
  5. var midiIn, synths;
  6. ~midiNoteKeys = IdentityDictionary.new; // Track which pool keys are used for MIDI notes
  7. // Connect to MIDI
  8. MIDIClient.init;
  9. MIDIIn.connectAll;
  10. // Note On: get synth from pool instead of creating new one
  11. MIDIdef.noteOn(\noteOn, { |vel, num, chan, src|
  12. var freq = num.midicps;
  13. var amp = (vel/127) * 0.4; // Reduced max amplitude
  14. var noteKey = "midi_" ++ num ++ "_" ++ chan;
  15. if (vel > 0) {
  16. // Check if note is already playing and release it first
  17. if(~midiNoteKeys[num].notNil, {
  18. ~returnSynthToPool.value(~midiNoteKeys[num]);
  19. ~midiNoteKeys.removeAt(num);
  20. });
  21. // Get a synth from the pool instead of creating new one
  22. var synth = ~startPoolSynth.value(noteKey, freq, amp);
  23. if(synth.notNil, {
  24. // Track this note
  25. ~midiNoteKeys[num] = noteKey;
  26. // Uncomment for debugging: ["MIDI Note ON: % - Got synth from pool".format(num)].postln;
  27. }, {
  28. ["MIDI Note ON: % - No free synths available!".format(num)].postln;
  29. });
  30. } {
  31. // Treat as noteOff if it is a noteOn with velocity 0
  32. if(~midiNoteKeys[num].notNil, {
  33. ~returnSynthToPool.value(~midiNoteKeys[num]);
  34. ~midiNoteKeys.removeAt(num);
  35. // Uncomment for debugging: ["MIDI Note OFF: % (vel 0)".format(num)].postln;
  36. });
  37. }
  38. });
  39. // Note Off: return synth to pool instead of setting gate
  40. MIDIdef.noteOff(\noteOff, { |vel, num, chan, src|
  41. if(~midiNoteKeys[num].notNil, {
  42. ~returnSynthToPool.value(~midiNoteKeys[num]);
  43. ~midiNoteKeys.removeAt(num);
  44. // Uncomment for debugging: ["MIDI Note OFF: %".format(num)].postln;
  45. });
  46. });
  47. // All Notes Off (MIDI Panic) - return all MIDI synths to pool
  48. MIDIdef.cc(\allNotesOff, { |val, num, chan, src|
  49. if(num == 123, { // All Notes Off CC
  50. ~midiNoteKeys.keysValuesDo({ |noteNum, noteKey|
  51. ~returnSynthToPool.value(noteKey);
  52. });
  53. ~midiNoteKeys.clear;
  54. "MIDI: All notes off - All synths returned to pool".postln;
  55. });
  56. });
  57. // Cleanup all MIDI synths function
  58. ~cleanupAllMIDI = {
  59. ~midiNoteKeys.keysValuesDo({ |noteNum, noteKey|
  60. ~returnSynthToPool.value(noteKey);
  61. });
  62. ~midiNoteKeys.clear;
  63. "All MIDI synths returned to pool".postln;
  64. };
  65. // Get MIDI status
  66. ~getMIDIStatus = {
  67. "=== MIDI Status ===".postln;
  68. "Active MIDI notes: %".format(~midiNoteKeys.size).postln;
  69. if(~midiNoteKeys.size > 0, {
  70. "Playing notes: %".format(~midiNoteKeys.keys.asArray.sort).postln;
  71. });
  72. "==================".postln;
  73. };
  74. // Register cleanup with CmdPeriod
  75. CmdPeriod.add({
  76. ~cleanupAllMIDI.value;
  77. });
  78. "MIDI functions loaded with synth pool integration.".postln;
  79. "Notes will use pre-allocated synths from the pool.".postln;
  80. "No more memory leaks or stuck notes!".postln;
  81. "Available functions:".postln;
  82. " ~cleanupAllMIDI.value - Return all MIDI synths to pool".postln;
  83. " ~getMIDIStatus.value - Show active MIDI notes".postln;
  84. )