| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- // Module 9: MIDI Controller - FIXED VERSION
- // Save as "9_midi_controller.scd" (REPLACE YOUR EXISTING VERSION)
- (
- // MIDI note handling using synth pool
- 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, {
- if(~returnSynthToPool.notNil, {
- ~returnSynthToPool.value(~midiNoteKeys[num]);
- });
- ~midiNoteKeys.removeAt(num);
- });
-
- // Get a synth from the pool instead of creating new one
- if(~startPoolSynth.notNil, {
- 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: Synth pool not initialized! Run ~initializeSynthPool.value first".postln;
- });
- } {
- // Treat as noteOff if it is a noteOn with velocity 0
- if(~midiNoteKeys[num].notNil, {
- if(~returnSynthToPool.notNil, {
- ~returnSynthToPool.value(~midiNoteKeys[num]);
- });
- ~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, {
- if(~returnSynthToPool.notNil, {
- ~returnSynthToPool.value(~midiNoteKeys[num]);
- });
- ~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
- if(~returnSynthToPool.notNil, {
- ~midiNoteKeys.keysValuesDo({ |noteNum, noteKey|
- ~returnSynthToPool.value(noteKey);
- });
- });
- ~midiNoteKeys.clear;
- "MIDI: All notes off - All synths returned to pool".postln;
- });
- });
- // Cleanup all MIDI synths function
- ~cleanupAllMIDI = {
- if(~returnSynthToPool.notNil, {
- ~midiNoteKeys.keysValuesDo({ |noteNum, noteKey|
- ~returnSynthToPool.value(noteKey);
- });
- });
- ~midiNoteKeys.clear;
- "All MIDI synths returned to pool".postln;
- };
- // Get MIDI status
- ~getMIDIStatus = {
- "=== MIDI Status ===".postln;
- "Active MIDI notes: %".format(~midiNoteKeys.size).postln;
- if(~midiNoteKeys.size > 0, {
- "Playing notes: %".format(~midiNoteKeys.keys.asArray.sort).postln;
- });
- "==================".postln;
- };
- // Register cleanup with CmdPeriod
- CmdPeriod.add({
- ~cleanupAllMIDI.value;
- });
- "MIDI functions loaded with 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;
- )
|