| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- // Module 9: MIDI Controller - ROBUST VERSION
- // Save as "9_midi_controller.scd" (REPLACE YOUR EXISTING VERSION)
- (
- // MIDI note handling using synth pool - ROBUST VERSION
- var midiIn, synths;
- ~midiNoteKeys = IdentityDictionary.new; // Track which pool keys are used for MIDI notes
- // Connect to MIDI
- MIDIClient.init;
- MIDIIn.connectAll;
- // Note On: get synth from pool instead of creating new one
- MIDIdef.noteOn(\noteOn, { |vel, num, chan, src|
- var freq = num.midicps;
- var amp = (vel/127) * 0.4; // Reduced max amplitude
- var noteKey = "midi_" ++ num ++ "_" ++ chan;
- if (vel > 0) {
- // Check if note is already playing and release it first
- if(~midiNoteKeys[num].notNil, {
- // Safely return synth to pool
- try {
- if(~returnSynthToPool.notNil, {
- ~returnSynthToPool.value(~midiNoteKeys[num]);
- });
- } { |error|
- // Silent error handling
- };
- ~midiNoteKeys.removeAt(num);
- });
-
- // Check if synth pool functions exist and pool is initialized
- if(~startPoolSynth.notNil and: { ~poolInitialized == true }, {
- try {
- var synth = ~startPoolSynth.value(noteKey, freq, amp);
-
- if(synth.notNil, {
- // Track this note
- ~midiNoteKeys[num] = noteKey;
- // Uncomment for debugging: ["MIDI Note ON: % - Got synth from pool".format(num)].postln;
- }, {
- ["MIDI Note ON: % - No free synths available!".format(num)].postln;
- });
- } { |error|
- "MIDI Error getting synth from pool: %".format(error).postln;
- };
- }, {
- if(~poolInitialized != true, {
- "MIDI Error: Synth pool not initialized! Run ~initializeSynthPool.value first".postln;
- }, {
- "MIDI Error: Synth pool functions not available!".postln;
- });
- });
- } {
- // Treat as noteOff if it is a noteOn with velocity 0
- if(~midiNoteKeys[num].notNil, {
- try {
- if(~returnSynthToPool.notNil, {
- ~returnSynthToPool.value(~midiNoteKeys[num]);
- });
- } { |error|
- // Silent error handling
- };
- ~midiNoteKeys.removeAt(num);
- // Uncomment for debugging: ["MIDI Note OFF: % (vel 0)".format(num)].postln;
- });
- }
- });
- // Note Off: return synth to pool instead of setting gate
- MIDIdef.noteOff(\noteOff, { |vel, num, chan, src|
- if(~midiNoteKeys[num].notNil, {
- try {
- if(~returnSynthToPool.notNil, {
- ~returnSynthToPool.value(~midiNoteKeys[num]);
- });
- } { |error|
- // Silent error handling
- };
- ~midiNoteKeys.removeAt(num);
- // Uncomment for debugging: ["MIDI Note OFF: %".format(num)].postln;
- });
- });
- // All Notes Off (MIDI Panic) - return all MIDI synths to pool
- MIDIdef.cc(\allNotesOff, { |val, num, chan, src|
- if(num == 123, { // All Notes Off CC
- try {
- if(~returnSynthToPool.notNil, {
- ~midiNoteKeys.keysValuesDo({ |noteNum, noteKey|
- ~returnSynthToPool.value(noteKey);
- });
- });
- } { |error|
- "Error during All Notes Off: %".format(error).postln;
- };
- ~midiNoteKeys.clear;
- "MIDI: All notes off - All synths returned to pool".postln;
- });
- });
- // Cleanup all MIDI synths function
- ~cleanupAllMIDI = {
- try {
- if(~returnSynthToPool.notNil, {
- ~midiNoteKeys.keysValuesDo({ |noteNum, noteKey|
- ~returnSynthToPool.value(noteKey);
- });
- });
- } { |error|
- "Error during MIDI cleanup: %".format(error).postln;
- };
- ~midiNoteKeys.clear;
- "All MIDI synths returned to pool".postln;
- };
- // Get MIDI status
- ~getMIDIStatus = {
- "=== MIDI Status ===".postln;
- if(~midiNoteKeys.notNil, {
- "Active MIDI notes: %".format(~midiNoteKeys.size).postln;
- if(~midiNoteKeys.size > 0, {
- "Playing notes: %".format(~midiNoteKeys.keys.asArray.sort).postln;
- });
- }, {
- "MIDI note tracking not initialized".postln;
- });
-
- if(~poolInitialized.notNil, {
- "Synth pool initialized: %".format(~poolInitialized).postln;
- }, {
- "Synth pool status: Unknown".postln;
- });
- "==================".postln;
- };
- // Register cleanup with CmdPeriod
- CmdPeriod.add({
- ~cleanupAllMIDI.value;
- });
- "MIDI functions loaded with ROBUST synth pool integration.".postln;
- "Notes will use pre-allocated synths from the pool.".postln;
- "No more memory leaks or stuck notes!".postln;
- "Available functions:".postln;
- " ~cleanupAllMIDI.value - Return all MIDI synths to pool".postln;
- " ~getMIDIStatus.value - Show active MIDI notes".postln;
- )
|