diff --git a/MEMLNaut-PAF-IML.ino b/MEMLNaut-PAF-IML.ino index df84c61..13aded7 100644 --- a/MEMLNaut-PAF-IML.ino +++ b/MEMLNaut-PAF-IML.ino @@ -6,8 +6,9 @@ #include #include "IMLInterface.hpp" #include "interfaceRL.hpp" -#include "src/memllib/synth/maxiPAF.hpp" #include "hardware/structs/bus_ctrl.h" +#include "PAFSynthAudioApp.hpp" + #define APP_SRAM __not_in_flash("app") @@ -28,264 +29,12 @@ uint32_t get_rosc_entropy_seed(int bits) { return seed; } -class PAFSynthApp : public AudioAppBase -{ -public: - static constexpr size_t kN_Params = 21; - - PAFSynthApp() : AudioAppBase() {} - - bool euclidean(float phase, const size_t n, const size_t k, const size_t offset, const float pulseWidth) - { - // Euclidean function - const float fi = phase * n; - int i = static_cast(fi); - const float rem = fi - i; - if (i == n) - { - i--; - } - const int idx = ((i + n - offset) * k) % n; - return (idx < k && rem < pulseWidth) ? 1 : 0; - } - - // // NOTE: Phasor is the last arg - // const double phasor = args.back().as_float(); - // const int n = args[0].as_int(); - // const int k = args[1].as_int(); - // const int offset = (args.size() >= 4) ? args[2].as_int() : 0; - // const float pulseWidth = (args.size() == 5) ? args[3].as_float() : 0.5; - // const float fi = phasor * n; - // int i = static_cast(fi); - // const float rem = fi - i; - // if (i == n) - // { - // i--; - // } - // const int idx = ((i + n - offset) * k) % n; - // result = Value(idx < k && rem < pulseWidth ? 1 : 0); - - // return result; - // } - - - - stereosample_t __force_inline Process(const stereosample_t x) override - { - float x1[1]; - - // const float trig = pulse.square(1); - - paf0.play(x1, 1, arpFreq, arpFreq + (paf0_cf * arpFreq), paf0_bw * arpFreq, paf0_vib, paf0_vfr, paf0_shift, 0); - float y = x1[0]; - - const float freq1 = arpFreq * detune; - - paf1.play(x1, 1, freq1, freq1 + (paf1_cf * freq1), paf1_bw * freq1, paf1_vib, paf1_vfr, paf1_shift, 1); - y += x1[0]; - - const float freq2 = freq1 * detune; - - paf2.play(x1, 1, freq2, freq2 + (paf2_cf * freq2), paf2_bw * freq2, paf2_vib, paf2_vfr, paf2_shift, 1); - y += x1[0]; - - const float ph = phasorOsc.phasor(1); - const bool euclidNewNote = euclidean(ph, 12, euclidN, 0, 0.1f); - // y = y * 0.3f; - // const float envamp = env.play(counter==0); - // const float envamp = line.play(counter==0); - if(zxdetect.onZX(euclidNewNote)) { - envamp=0.2f; - freqIndex++; - if(freqIndex >= 4) { - freqIndex = 0; - } - arpFreq = frequencies[freqIndex]; - }else{ - constexpr float envdec = 0.2f/9000.f; - envamp -= envdec; - if (envamp < 0.f) { - envamp = 0.f; - } - } - // PERIODIC_DEBUG(3000, Serial.println(y);) - y = y * envamp* envamp; - // counter++; - // if(counter>=9000) { - // counter=0; - // freqIndex++; - // if(freqIndex >= 4) { - // freqIndex = 0; - // } - // arpFreq = frequencies[freqIndex]; - // } - - // PERIODIC_DEBUG(10000, { - // Serial.println(envamp); - // }) - - float d1 = (dl1.play(y, 3500, 0.8f) * dl1mix); - // float d2 = (dl2.play(y, 15000, 0.8f) * dl2mix); - y = y + d1;// + d2; - stereosample_t ret { y, y }; - frame++; - return ret; - } - - void Setup(float sample_rate, std::shared_ptr interface) override - { - AudioAppBase::Setup(sample_rate, interface); - maxiSettings::sampleRate = sample_rate; - paf0.init(); - paf0.setsr(maxiSettings::getSampleRate(), 1); - // paf0.freq(100, 0); - // // paf0.amp(1,0); - // paf0.bw(200,0); - // paf0.cf(210,0); - // paf0.vfr(5,0); - // paf0.vib(0.1,0); - // paf0.shift(10,0); - - paf1.init(); - paf1.setsr(maxiSettings::getSampleRate(), 1); - // paf1.freq(150, 0); - // // paf1.amp(1,0); - // paf1.bw(200,0); - // paf1.cf(210,0); - // paf1.vfr(5,0); - // paf1.vib(0.1,0); - // paf1.shift(10,0); - - paf2.init(); - paf2.setsr(maxiSettings::getSampleRate(), 1); - // paf2.freq(190, 0); - // // paf2.amp(1,0); - // paf2.bw(500,0); - // paf2.cf(210,0); - // paf2.vfr(5,0); - // paf2.vib(0.1,0); - // paf2.shift(6,0); - - env.setupAR(10,100); - arpFreq = frequencies[0]; - // line.prepare(1.f,0.f,100.f,false); - // line.triggerEnable(true); - envamp=1.f; - } - - void ProcessParams(const std::vector& params) override - { - // // Map parameters to the synth - // synth_.mapParameters(params); - // //Serial.print("Params processed."); - // paf0_freq = 50.f + (params[0] * params[0] * 1000.f); - // paf1_freq = 50.f + (params[1] * params[1] * 1000.f); - - // paf0_cf = arpFreq + (params[2] * params[2] * arpFreq * 1.f); - // paf1_cf = arpFreq + (params[3] * params[3] * arpFreq * 1.f); - // paf2_cf = arpFreq + (params[4] * params[4] * arpFreq * 1.f); - paf0_cf = (params[2] * params[2] * 1.f); - paf1_cf = (params[3] * params[3] * 1.f); - paf2_cf = (params[4] * params[4] * 1.f); - - // paf0_bw = 5.f + (params[5] * arpFreq * 0.5f); - // paf1_bw = 5.f + (params[6] * arpFreq * 0.5f); - // paf2_bw = 5.f + (params[7] * arpFreq * 0.5f); - paf0_bw = 0.1f + (params[5] * 2.f); - paf1_bw = 0.1f + (params[6] * 2.f); - paf2_bw = 0.1f + (params[7] * 2.f); - - paf0_vib = (params[8] * params[8] * 0.99f); - paf1_vib = (params[9] * params[9] * 0.99f); - paf2_vib = (params[10] * params[10] * 0.99f); - - paf0_vfr = (params[11] * params[11]* 10.f); - paf1_vfr = (params[12] * params[12] * 10.f); - paf2_vfr = (params[13] * params[13] * 10.f); - - paf0_shift = (params[14] * 1000.f); - paf1_shift = (params[15] * 1000.f); - paf2_shift = (params[16] * 1000.f); - - dl1mix = params[17] * params[17] * 0.4f; - // dl2mix = params[18] * params[18] * 0.4f; - detune = 1.0f + (params[18] * 0.1); - - euclidN = static_cast(2 + (params[19] * 5)); - - // Serial.printf("%f %f %f %f %f\n", paf0_cf, paf0_bw, paf0_vib, paf0_vfr, paf0_shift); - - } - -protected: - - maxiPAFOperator paf0; - maxiPAFOperator paf1; - maxiPAFOperator paf2; - - maxiDelayline<5000> dl1; - maxiDelayline<15100> dl2; - - maxiOsc pulse; - maxiEnvGen env; - - - float frame=0; - - float paf0_freq = 100; - float paf1_freq = 100; - float paf2_freq = 50; - - float paf0_cf = 200; - float paf1_cf = 250; - float paf2_cf = 250; - - float paf0_bw = 100; - float paf1_bw = 5000; - float paf2_bw = 5000; - - float paf0_vib = 0; - float paf1_vib = 1; - float paf2_vib = 1; - - float paf0_vfr = 2; - float paf1_vfr = 2; - float paf2_vfr = 2; - - float paf0_shift = 0; - float paf1_shift = 0; - float paf2_shift = 0; - - float dl1mix = 0.0f; - float dl2mix = 0.0f; - - size_t counter=0; - const size_t nFREQs = 17; - const float frequencies[nFREQs] = {100, 200, 400,800, 400, 800, 100,1600,100,400,100,50,1600,200,100,800,400}; - size_t freqIndex = 0; - size_t freqOffset = 0; - float arpFreq=50; - - maxiLine line; - float envamp; - - float detune = 1.0; - - maxiOsc phasorOsc; - maxiTrigger zxdetect; - - size_t euclidN=4; - -}; - - - // Global objects std::shared_ptr APP_SRAM interfaceIML; std::shared_ptr APP_SRAM RLInterface; -std::shared_ptr __scratch_y("audio") audio_app; +std::shared_ptr __scratch_y("audio") audio_app; // Inter-core communication volatile bool APP_SRAM core_0_ready = false; @@ -311,7 +60,7 @@ void bind_RL_interface(std::shared_ptr interface) String msg = msgs[rand() % msgs.size()]; interface->storeExperience(1.f); Serial.println(msg); - + scr.post(msg); }); MEMLNaut::Instance()->setMomA2Callback([interface] () { @@ -355,7 +104,7 @@ void bind_RL_interface(std::shared_ptr interface) interface->setOptimiseDivisor(divisor); Serial.println(msg); }); - + // Set up loop callback MEMLNaut::Instance()->setLoopCallback([interface] () { @@ -363,7 +112,7 @@ void bind_RL_interface(std::shared_ptr interface) interface->generateAction(); }); - + } void bind_IML_interface(std::shared_ptr interface) @@ -410,7 +159,7 @@ void bind_IML_interface(std::shared_ptr interface) }); } -enum MLMODES {IML, RL}; +enum MLMODES {IML, RL}; MLMODES APP_SRAM mlMode = RL; @@ -419,7 +168,7 @@ inline bool __not_in_flash_func(displayUpdate)(__unused struct repeating_timer * scr.update(); return true; } - + void setup() { @@ -443,7 +192,7 @@ void setup() case IML: { { auto temp_interface = std::make_shared(); - temp_interface->setup(kN_InputParams, PAFSynthApp::kN_Params); + temp_interface->setup(kN_InputParams, PAFSynthAudioApp::kN_Params); MEMORY_BARRIER(); interfaceIML = temp_interface; MEMORY_BARRIER(); @@ -458,7 +207,7 @@ void setup() case RL: { { auto temp_interface = std::make_shared(); - temp_interface->setup(kN_InputParams, PAFSynthApp::kN_Params); + temp_interface->setup(kN_InputParams, PAFSynthAudioApp::kN_Params); MEMORY_BARRIER(); RLInterface = temp_interface; MEMORY_BARRIER(); @@ -487,7 +236,7 @@ void setup() void loop() { - + MEMLNaut::Instance()->loop(); static int AUDIO_MEM blip_counter = 0; @@ -518,7 +267,7 @@ void setup1() // Create audio app with memory barrier protection { - auto temp_audio_app = std::make_shared(); + auto temp_audio_app = std::make_shared(); std::shared_ptr selectedInterface; if (mlMode == IML) { @@ -553,11 +302,3 @@ void loop1() delay(1); } -extern "C" int getentropy (void * buffer, size_t how_many) { - uint8_t* pBuf = (uint8_t*) buffer; - while(how_many--) { - uint8_t rand_val = rp2040.hwrand32() % UINT8_MAX; - *pBuf++ = rand_val; - } - return 0; // return "no error". Can also do EFAULT, EIO, ENOSYS -} diff --git a/PAFSynthAudioApp.cpp b/PAFSynthAudioApp.cpp new file mode 100644 index 0000000..4886469 --- /dev/null +++ b/PAFSynthAudioApp.cpp @@ -0,0 +1,164 @@ +#include "PAFSynthAudioApp.hpp" +#include "src/memllib/synth/maximilian.h" // Required for maxiSettings etc. + +PAFSynthAudioApp::PAFSynthAudioApp() : AudioAppBase() {} + +bool PAFSynthAudioApp::euclidean(float phase, const size_t n, const size_t k, const size_t offset, const float pulseWidth) +{ + // Euclidean function + const float fi = phase * n; + int i = static_cast(fi); + const float rem = fi - i; + if (i == n) + { + i--; + } + const int idx = ((i + n - offset) * k) % n; + return (idx < k && rem < pulseWidth) ? 1 : 0; +} + +stereosample_t PAFSynthAudioApp::Process(const stereosample_t x) +{ + float x1[1]; + + // const float trig = pulse.square(1); + + paf0.play(x1, 1, arpFreq, arpFreq + (paf0_cf * arpFreq), paf0_bw * arpFreq, paf0_vib, paf0_vfr, paf0_shift, 0); + float y = x1[0]; + + const float freq1 = arpFreq * detune; + + paf1.play(x1, 1, freq1, freq1 + (paf1_cf * freq1), paf1_bw * freq1, paf1_vib, paf1_vfr, paf1_shift, 1); + y += x1[0]; + + const float freq2 = freq1 * detune; + + paf2.play(x1, 1, freq2, freq2 + (paf2_cf * freq2), paf2_bw * freq2, paf2_vib, paf2_vfr, paf2_shift, 1); + y += x1[0]; + + const float ph = phasorOsc.phasor(1); + const bool euclidNewNote = euclidean(ph, 12, euclidN, 0, 0.1f); + // y = y * 0.3f; + // const float envamp = env.play(counter==0); + // const float envamp = line.play(counter==0); + if(zxdetect.onZX(euclidNewNote)) { + envamp=0.2f; + freqIndex++; + if(freqIndex >= 4) { + freqIndex = 0; + } + arpFreq = frequencies[freqIndex]; + }else{ + constexpr float envdec = 0.2f/9000.f; + envamp -= envdec; + if (envamp < 0.f) { + envamp = 0.f; + } + } + // PERIODIC_DEBUG(3000, Serial.println(y);) + y = y * envamp* envamp; + // counter++; + // if(counter>=9000) { + // counter=0; + // freqIndex++; + // if(freqIndex >= 4) { + // freqIndex = 0; + // } + // arpFreq = frequencies[freqIndex]; + // } + + // PERIODIC_DEBUG(10000, { + // Serial.println(envamp); + // }) + + float d1 = (dl1.play(y, 3500, 0.8f) * dl1mix); + // float d2 = (dl2.play(y, 15000, 0.8f) * dl2mix); + y = y + d1;// + d2; + stereosample_t ret { y, y }; + frame++; + return ret; +} + +void PAFSynthAudioApp::Setup(float sample_rate, std::shared_ptr interface) +{ + AudioAppBase::Setup(sample_rate, interface); + maxiSettings::sampleRate = sample_rate; + paf0.init(); + paf0.setsr(maxiSettings::getSampleRate(), 1); + // paf0.freq(100, 0); + // // paf0.amp(1,0); + // paf0.bw(200,0); + // paf0.cf(210,0); + // paf0.vfr(5,0); + // paf0.vib(0.1,0); + // paf0.shift(10,0); + + paf1.init(); + paf1.setsr(maxiSettings::getSampleRate(), 1); + // paf1.freq(150, 0); + // // paf1.amp(1,0); + // paf1.bw(200,0); + // paf1.cf(210,0); + // paf1.vfr(5,0); + // paf1.vib(0.1,0); + // paf1.shift(10,0); + + paf2.init(); + paf2.setsr(maxiSettings::getSampleRate(), 1); + // paf2.freq(190, 0); + // // paf2.amp(1,0); + // paf2.bw(500,0); + // paf2.cf(210,0); + // paf2.vfr(5,0); + // paf2.vib(0.1,0); + // paf2.shift(6,0); + + env.setupAR(10,100); + arpFreq = frequencies[0]; + // line.prepare(1.f,0.f,100.f,false); + // line.triggerEnable(true); + envamp=1.f; +} + +void PAFSynthAudioApp::ProcessParams(const std::vector& params) +{ + // // Map parameters to the synth + // synth_.mapParameters(params); + // //Serial.print("Params processed."); + // paf0_freq = 50.f + (params[0] * params[0] * 1000.f); + // paf1_freq = 50.f + (params[1] * params[1] * 1000.f); + + // paf0_cf = arpFreq + (params[2] * params[2] * arpFreq * 1.f); + // paf1_cf = arpFreq + (params[3] * params[3] * arpFreq * 1.f); + // paf2_cf = arpFreq + (params[4] * params[4] * arpFreq * 1.f); + paf0_cf = (params[2] * params[2] * 1.f); + paf1_cf = (params[3] * params[3] * 1.f); + paf2_cf = (params[4] * params[4] * 1.f); + + // paf0_bw = 5.f + (params[5] * arpFreq * 0.5f); + // paf1_bw = 5.f + (params[6] * arpFreq * 0.5f); + // paf2_bw = 5.f + (params[7] * arpFreq * 0.5f); + paf0_bw = 0.1f + (params[5] * 2.f); + paf1_bw = 0.1f + (params[6] * 2.f); + paf2_bw = 0.1f + (params[7] * 2.f); + + paf0_vib = (params[8] * params[8] * 0.99f); + paf1_vib = (params[9] * params[9] * 0.99f); + paf2_vib = (params[10] * params[10] * 0.99f); + + paf0_vfr = (params[11] * params[11]* 10.f); + paf1_vfr = (params[12] * params[12] * 10.f); + paf2_vfr = (params[13] * params[13] * 10.f); + + paf0_shift = (params[14] * 1000.f); + paf1_shift = (params[15] * 1000.f); + paf2_shift = (params[16] * 1000.f); + + dl1mix = params[17] * params[17] * 0.4f; + // dl2mix = params[18] * params[18] * 0.4f; + detune = 1.0f + (params[18] * 0.1); + + euclidN = static_cast(2 + (params[19] * 5)); + + // Serial.printf("%f %f %f %f %f\n", paf0_cf, paf0_bw, paf0_vib, paf0_vfr, paf0_shift); +} diff --git a/PAFSynthAudioApp.hpp b/PAFSynthAudioApp.hpp new file mode 100644 index 0000000..b29d171 --- /dev/null +++ b/PAFSynthAudioApp.hpp @@ -0,0 +1,93 @@ +#ifndef __PAF_SYNTH_AUDIO_APP_HPP__ +#define __PAF_SYNTH_AUDIO_APP_HPP__ + +#include "src/memllib/audio/AudioAppBase.hpp" // Added missing include +#include "src/memllib/synth/maximilian.h" // Added missing include for maxiSettings, maxiOsc, maxiTrigger, maxiDelayline, maxiEnvGen, maxiLine + +#include +#include +#include +#include // Added for std::shared_ptr + +#include "src/memllib/synth/maxiPAF.hpp" +#include "src/memllib/interface/InterfaceBase.hpp" // Added missing include + + +class PAFSynthAudioApp : public AudioAppBase +{ +public: + static constexpr size_t kN_Params = 21; + static constexpr size_t nFREQs = 17; + static constexpr float frequencies[nFREQs] = {100, 200, 400,800, 400, 800, 100,1600,100,400,100,50,1600,200,100,800,400}; + + + PAFSynthAudioApp(); + + bool euclidean(float phase, const size_t n, const size_t k, const size_t offset, const float pulseWidth); + + stereosample_t __force_inline Process(const stereosample_t x) override; + + void Setup(float sample_rate, std::shared_ptr interface) override; + + void ProcessParams(const std::vector& params) override; + +protected: + + maxiPAFOperator paf0; + maxiPAFOperator paf1; + maxiPAFOperator paf2; + + maxiDelayline<5000> dl1; + maxiDelayline<15100> dl2; + + maxiOsc pulse; + maxiEnvGen env; + + + float frame=0; + + float paf0_freq = 100; + float paf1_freq = 100; + float paf2_freq = 50; + + float paf0_cf = 200; + float paf1_cf = 250; + float paf2_cf = 250; + + float paf0_bw = 100; + float paf1_bw = 5000; + float paf2_bw = 5000; + + float paf0_vib = 0; + float paf1_vib = 1; + float paf2_vib = 1; + + float paf0_vfr = 2; + float paf1_vfr = 2; + float paf2_vfr = 2; + + float paf0_shift = 0; + float paf1_shift = 0; + float paf2_shift = 0; + + float dl1mix = 0.0f; + float dl2mix = 0.0f; + + size_t counter=0; + size_t freqIndex = 0; + size_t freqOffset = 0; + float arpFreq=50; + + maxiLine line; + float envamp; + + float detune = 1.0; + + maxiOsc phasorOsc; + maxiTrigger zxdetect; + + size_t euclidN=4; + +}; + +#endif // __PAF_SYNTH_AUDIO_APP_HPP__ diff --git a/src/memllib b/src/memllib index 0348bce..943dfb1 160000 --- a/src/memllib +++ b/src/memllib @@ -1 +1 @@ -Subproject commit 0348bce5c4b28f7266fd6f650914ef6a47496f98 +Subproject commit 943dfb169cb64b30b3e759cda80d295dd01ebc05 diff --git a/src/memlp b/src/memlp index abd9def..e932fd7 160000 --- a/src/memlp +++ b/src/memlp @@ -1 +1 @@ -Subproject commit abd9def766ad389a03bc4f0842e6b0c970c3994b +Subproject commit e932fd7e77d16b439650eedbfa5990e8a19454b1