(
// Function to start effects chain
~startEffectsChain = {
    // Create audio buses for effects chain
    ~sourceBus = Bus.audio(s, 2);
    ~filterBus = Bus.audio(s, 2);
    ~delayBus = Bus.audio(s, 2);
    ~reverbBus = Bus.audio(s, 2);

    // Create control buses for modulation
    ~lfoControlBus = Bus.control(s, 1);

    // Create effects synths in chain
    ~lfoSynth = Synth(\lfoEffect, [
        \out, ~lfoControlBus,
        \freq, 1,
        \min, 100,
        \max, 5000,
        \waveform, 0,
        \target, 0
    ]);

    ~filterSynth = Synth(\lpf, [
        \in, ~sourceBus,
        \out, ~delayBus,
        \cutoff, 1000,
        \res, 0.5
    ]);

    ~delaySynth = Synth(\delay, [
        \in, ~delayBus,
        \out, ~reverbBus,
        \delaytime, 0.4,
        \feedback, 0.3,
        \mix, 0.3
    ], ~filterSynth, \addAfter);

    ~reverbSynth = Synth(\reverb, [
        \in, ~reverbBus,
        \out, 0,
        \mix, 0.2,
        \room, 0.5,
        \damp, 0.5
    ], ~delaySynth, \addAfter);

    // Create a mapping for the LFO to control the filter
    s.sync;
    ~lfoControlBus.asMap.postln;
    ~filterSynth.map(\cutoff, ~lfoControlBus);

    // Store the effects chain nodes in an array for easy access
    ~effectsChain = [~lfoSynth, ~filterSynth, ~delaySynth, ~reverbSynth];

    "Effects chain started with LFO mapping".postln;
};
// Function to stop effects chain
~stopEffectsChain = {
    if(~effectsChain.notNil, {
        ~effectsChain.do(_.free);
        ~effectsChain = nil;
    });

    if(~sourceBus.notNil, { ~sourceBus.free; ~sourceBus = nil; });
    if(~reverbBus.notNil, { ~reverbBus.free; ~reverbBus = nil; });
    if(~delayBus.notNil, { ~delayBus.free; ~delayBus = nil; });

    "Effects chain stopped".postln;
};

// Function to reset the entire system
~resetSystem = {
    ~stopEffectsChain.value;
    OSCdef.freeAll;

    // Reload OSC definitions
    thisProcess.interpreter.executeFile("5_osc_communication.scd");

    "System reset complete".postln;
	~touchSynths = ();  // Clear any active touch synths

};

// Test function for parameter changes
~testParameters = {
    // Start effects chain if not already running
    if(~effectsChain.isNil, { ~startEffectsChain.value; });

    // Test different oscillator types with varying parameters
    [
        [\sineTone, 440, 0.3, -0.5, 0.05, 0.5],
        [\squareTone, 330, 0.2, 0, 0.01, 0.8],
        [\sawTone, 220, 0.15, 0.5, 0.1, 1.2],
        [\triTone, 550, 0.25, -0.2, 0.02, 0.7],
        [\fmTone, 660, 0.2, 0.3, 0.05, 1.0]
    ].do { |params, i|
        var synthType, freq, amp, pan, attack, release;
        #synthType, freq, amp, pan, attack, release = params;

        // Create the synth with the specified parameters
        Synth(synthType, [
            \out, ~sourceBus,
            \freq, freq,
            \amp, amp,
            \pan, pan,
            \attack, attack,
            \release, release
        ]);

        // Change effect parameters for demonstration
        ~filterSynth.set(\cutoff, 500 + (i * 1000));
        ~delaySynth.set(\mix, 0.2 + (i * 0.1));
        ~reverbSynth.set(\room, 0.3 + (i * 0.1));

        // Log the current sound
        ["Testing synth:", synthType, freq, amp].postln;

        // Wait between notes
        0.8.wait;
    };

    // Clean up
    "Parameter test complete".postln;
};

// Function to simulate Arduino touch input
~simulateTouch = { |numTouches=10, duration=5|
    var endTime = SystemClock.seconds + duration;

    "Starting touch simulation for % seconds".format(duration).postln;

    // Start the effects chain
    ~startEffectsChain.value;

    // Generate random touches until the duration expires
    while { SystemClock.seconds < endTime } {
        var x = 1.0.rand;
        var y = 1.0.rand;
        var pressure = 0.3 + 0.7.rand;
        var color = 5.rand;  // 0-4 for different synth types

        // Send the simulated touch data through our OSC handler
        OSCdef(\touchOSC).value(['/touch', x, y, pressure, color], nil, nil, nil);

        // Random wait time between touches
        (0.1 + 0.3.rand).wait;
    };

    "Touch simulation complete".postln;
};

// Run parameter test in a Routine
~runParameterTest = {
    Routine(~testParameters).play;
};

// Run touch simulation in a Routine
~runTouchSimulation = { |duration=5|
    Routine({ ~simulateTouch.value(10, duration) }).play;
};

"Test functions loaded".postln;
)

