refactoring interface into modes
This commit is contained in:
parent
0626f4aa14
commit
28f8bc7711
9 changed files with 192 additions and 221 deletions
|
|
@ -13,7 +13,7 @@
|
||||||
#include "ChannelStripAudioApp.hpp"
|
#include "ChannelStripAudioApp.hpp"
|
||||||
|
|
||||||
//interface
|
//interface
|
||||||
#include "src/memllib/examples/InterfaceRL.hpp"
|
// #include "src/memllib/examples/InterfaceRL.hpp"
|
||||||
#include "src/memllib/hardware/memlnaut/display/XYPadView.hpp"
|
#include "src/memllib/hardware/memlnaut/display/XYPadView.hpp"
|
||||||
#include "src/memllib/hardware/memlnaut/display/MessageView.hpp"
|
#include "src/memllib/hardware/memlnaut/display/MessageView.hpp"
|
||||||
#include "src/memllib/hardware/memlnaut/display/VoiceSpaceSelectView.hpp"
|
#include "src/memllib/hardware/memlnaut/display/VoiceSpaceSelectView.hpp"
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
#include "modes/MEMLNautModeChannelStrip.hpp"
|
#include "modes/MEMLNautModeChannelStrip.hpp"
|
||||||
#include "modes/MEMLNautModeSoundAnalysisMIDI.hpp"
|
#include "modes/MEMLNautModeSoundAnalysisMIDI.hpp"
|
||||||
|
|
||||||
#define INTERFACE_TYPE InterfaceRL
|
// #define INTERFACE_TYPE InterfaceRL
|
||||||
|
|
||||||
#define MEMLNAUT_MODE_TYPE MEMLNautModeSoundAnalysisMIDI
|
#define MEMLNAUT_MODE_TYPE MEMLNautModeSoundAnalysisMIDI
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ uint32_t get_rosc_entropy_seed(int bits) {
|
||||||
|
|
||||||
|
|
||||||
// Global objects
|
// Global objects
|
||||||
std::shared_ptr<INTERFACE_TYPE> APP_SRAM interface;
|
// std::shared_ptr<INTERFACE_TYPE> APP_SRAM interface;
|
||||||
|
|
||||||
std::shared_ptr<MIDIInOut> APP_SRAM midi_interf;
|
std::shared_ptr<MIDIInOut> APP_SRAM midi_interf;
|
||||||
|
|
||||||
|
|
@ -99,32 +99,32 @@ void setup() {
|
||||||
MEMLNaut::Initialize();
|
MEMLNaut::Initialize();
|
||||||
pinMode(33, OUTPUT);
|
pinMode(33, OUTPUT);
|
||||||
|
|
||||||
{
|
// {
|
||||||
auto temp_interface = std::make_shared<INTERFACE_TYPE>();
|
// auto temp_interface = std::make_shared<INTERFACE_TYPE>();
|
||||||
|
|
||||||
// temp_interface->setup(kN_InputParams, PAFSynthAudioApp<>::kN_Params);
|
// // temp_interface->setup(kN_InputParams, PAFSynthAudioApp<>::kN_Params);
|
||||||
// temp_interface->setup(kN_InputParams, ChannelStripAudioApp<>::kN_Params);
|
// // temp_interface->setup(kN_InputParams, ChannelStripAudioApp<>::kN_Params);
|
||||||
temp_interface->setup(currentMode->kN_InputParams, currentMode->getNParams());
|
// temp_interface->setup(currentMode->kN_InputParams, currentMode->getNParams());
|
||||||
|
|
||||||
|
|
||||||
MEMORY_BARRIER();
|
// MEMORY_BARRIER();
|
||||||
interface = temp_interface;
|
// interface = temp_interface;
|
||||||
MEMORY_BARRIER();
|
// MEMORY_BARRIER();
|
||||||
}
|
// }
|
||||||
|
currentMode->setupInterface();
|
||||||
// Setup interface with memory barrier protection
|
// Setup interface with memory barrier protection
|
||||||
WRITE_VOLATILE(interface_ready, true);
|
WRITE_VOLATILE(interface_ready, true);
|
||||||
// Bind interface after ensuring it's fully initialized
|
// Bind interface after ensuring it's fully initialized
|
||||||
interface->bindInterface(true);
|
//TODO: control this from the mode
|
||||||
|
// interface->bindInterface(true);
|
||||||
Serial.println("Bound interface to MEMLNaut.");
|
Serial.println("Bound interface to MEMLNaut.");
|
||||||
|
|
||||||
|
|
||||||
midi_interf = std::make_shared<MIDIInOut>();
|
midi_interf = std::make_shared<MIDIInOut>();
|
||||||
midi_interf->Setup(currentMode->getNMIDICtrlOutputs());
|
|
||||||
midi_interf->SetMIDISendChannel(1);
|
|
||||||
Serial.println("MIDI setup complete.");
|
Serial.println("MIDI setup complete.");
|
||||||
if (midi_interf) {
|
if (midi_interf) {
|
||||||
currentMode->setupMIDI(midi_interf);
|
currentMode->setupMIDI(midi_interf);
|
||||||
interface->bindMIDI(midi_interf);
|
// interface->bindMIDI(midi_interf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -135,26 +135,10 @@ void setup() {
|
||||||
delay(1);
|
delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<VoiceSpaceSelectView> voiceSpaceSelectView;
|
|
||||||
voiceSpaceSelectView = std::make_shared<VoiceSpaceSelectView>("Voice Spaces");
|
|
||||||
|
|
||||||
MEMLNaut::Instance()->disp->InsertViewAfter(interface->rlStatsView, voiceSpaceSelectView);
|
|
||||||
// voiceSpaceSelectView->setOptions(voiceSpaceList); //set by core 1 on startup
|
|
||||||
// voiceSpaceSelectView->setOptions(voiceSpaceList_chstrip); //set by core 1 on startup
|
|
||||||
voiceSpaceSelectView->setOptions(currentMode->getVoiceSpaceList()); //set by core 1 on startup
|
|
||||||
voiceSpaceSelectView->setNewVoiceCallback(
|
|
||||||
[](size_t idx) {
|
|
||||||
// Serial.println(idx);
|
|
||||||
// audio_app_chstrip->setVoiceSpace(idx);
|
|
||||||
// audioAppChannelStrip.setVoiceSpace(idx);
|
|
||||||
// audio_app->setVoiceSpace(idx);
|
|
||||||
currentMode->setVoiceSpace(idx);
|
|
||||||
});
|
|
||||||
|
|
||||||
currentMode->addViews();
|
currentMode->addViews();
|
||||||
|
|
||||||
std::shared_ptr<MessageView> helpView = std::make_shared<MessageView>("Help");
|
std::shared_ptr<MessageView> helpView = std::make_shared<MessageView>("Help");
|
||||||
// helpView->post("PAF synth NISPS");
|
|
||||||
String title = currentMode->getHelpTitle();
|
String title = currentMode->getHelpTitle();
|
||||||
helpView->post(title);
|
helpView->post(title);
|
||||||
helpView->post("TA: Down: Clear replay memory");
|
helpView->post("TA: Down: Clear replay memory");
|
||||||
|
|
@ -181,7 +165,8 @@ void loop() {
|
||||||
|
|
||||||
PERIODIC_RUN_US(
|
PERIODIC_RUN_US(
|
||||||
PERF_BEGIN(MLSTATS);
|
PERF_BEGIN(MLSTATS);
|
||||||
currentMode->processAnalysisParams(interface);
|
// currentMode->processAnalysisParams(interface);
|
||||||
|
currentMode->processAnalysisParams();
|
||||||
MEMLNaut::Instance()->loop();
|
MEMLNaut::Instance()->loop();
|
||||||
PERF_END(MLSTATS);
|
PERF_END(MLSTATS);
|
||||||
, ML_INFERENCE_PERIOD_US)
|
, ML_INFERENCE_PERIOD_US)
|
||||||
|
|
@ -219,6 +204,10 @@ void AUDIO_FUNC(audio_block_callback)(float in[][kBufferSize], float out[][kBuff
|
||||||
out[0][i] = y.L;
|
out[0][i] = y.L;
|
||||||
out[1][i] = y.R;
|
out[1][i] = y.R;
|
||||||
|
|
||||||
|
// PERIODIC_RUN(
|
||||||
|
// Serial.printf("x: %f\n", x.L + x.R);
|
||||||
|
// , 100);
|
||||||
|
|
||||||
currentMode->analyse(x);
|
currentMode->analyse(x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -236,40 +225,12 @@ void setup1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Create audio app with memory barrier protection
|
currentMode->setupAudio(AudioDriver::GetSampleRate());
|
||||||
{
|
|
||||||
// PAFSynthAudioApp<>* audio_raw = new (audio_app_mem) PAFSynthAudioApp<>();
|
|
||||||
// audio_raw->Setup(AudioDriver::GetSampleRate(), interface);
|
|
||||||
|
|
||||||
// // shared_ptr with custom deleter calling only the destructor (control block still allocates)
|
|
||||||
// auto audio_deleter = [](PAFSynthAudioApp<>* p) {
|
|
||||||
// if (p) p->~PAFSynthAudioApp<>();
|
|
||||||
// };
|
|
||||||
// std::shared_ptr<PAFSynthAudioApp<>> temp_audio_app(audio_raw, audio_deleter);
|
|
||||||
// ChannelStripAudioApp<>* audio_raw = new (audio_app_mem_chstrip) ChannelStripAudioApp<>();
|
|
||||||
// audio_raw->Setup(AudioDriver::GetSampleRate(), interface);
|
|
||||||
|
|
||||||
// // shared_ptr with custom deleter calling only the destructor (control block still allocates)
|
|
||||||
// auto audio_deleter = [](ChannelStripAudioApp<>* p) {
|
|
||||||
// if (p) p->~ChannelStripAudioApp<>();
|
|
||||||
// };
|
|
||||||
// std::shared_ptr<ChannelStripAudioApp<>> temp_audio_app(audio_raw, audio_deleter);
|
|
||||||
|
|
||||||
// MEMORY_BARRIER();
|
|
||||||
// audio_app_chstrip = temp_audio_app;
|
|
||||||
// MEMORY_BARRIER();
|
|
||||||
}
|
|
||||||
// audioAppChannelStrip.Setup(AudioDriver::GetSampleRate(), interface);
|
|
||||||
currentMode->Setup(AudioDriver::GetSampleRate(), interface);
|
|
||||||
|
|
||||||
AudioDriver::SetBlockCallback(audio_block_callback);
|
AudioDriver::SetBlockCallback(audio_block_callback);
|
||||||
// AudioDriver::SetBlockCallback(currentMode->getAudioCallBack());
|
|
||||||
// Start audio driver
|
// Start audio driver
|
||||||
AudioDriver::Setup();
|
AudioDriver::Setup();
|
||||||
// AudioDriver::SetBlockCallback(audio_block_callback);
|
|
||||||
// voiceSpaceList = audio_app->getVoiceSpaceNames();
|
|
||||||
// voiceSpaceList_chstrip = audio_app_chstrip->getVoiceSpaceNames();
|
|
||||||
// voiceSpaceList_chstrip = audioAppChannelStrip.getVoiceSpaceNames();
|
|
||||||
|
|
||||||
WRITE_VOLATILE(core_1_ready, true);
|
WRITE_VOLATILE(core_1_ready, true);
|
||||||
while (!READ_VOLATILE(core_0_ready)) {
|
while (!READ_VOLATILE(core_0_ready)) {
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,9 @@ public:
|
||||||
|
|
||||||
__attribute__((hot)) stereosample_t __force_inline Process(const stereosample_t x) override
|
__attribute__((hot)) stereosample_t __force_inline Process(const stereosample_t x) override
|
||||||
{
|
{
|
||||||
|
// float y = x.L + x.R;
|
||||||
|
// y = filt.play(y);
|
||||||
|
// return stereosample_t{y, y};
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,6 +64,7 @@ public:
|
||||||
{
|
{
|
||||||
AudioAppBase<NPARAMS>::Setup(sample_rate, interface);
|
AudioAppBase<NPARAMS>::Setup(sample_rate, interface);
|
||||||
maxiSettings::sampleRate = sample_rate;
|
maxiSettings::sampleRate = sample_rate;
|
||||||
|
filt.set(maxiBiquad::filterTypes::HIGHPASS, 20.f, 0.707f, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((always_inline)) void ProcessParams(const std::array<float, NPARAMS>& params)
|
__attribute__((always_inline)) void ProcessParams(const std::array<float, NPARAMS>& params)
|
||||||
|
|
@ -71,6 +75,8 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
maxiBiquad filt;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ XiasriAnalysis::XiasriAnalysis(const float sample_rate) :
|
||||||
zc_median_filter_(kZC_MedianFilterSize) {
|
zc_median_filter_(kZC_MedianFilterSize) {
|
||||||
|
|
||||||
// Initialize filters and detectors
|
// Initialize filters and detectors
|
||||||
common_hpf_.set(maxiBiquad::filterTypes::HIGHPASS, 30.f, 0.707f, 0);
|
common_hpf_.set(maxiBiquad::filterTypes::HIGHPASS, 20.f, 0.707f, 0);
|
||||||
// Zero crossing
|
// Zero crossing
|
||||||
zc_lpf_.set(maxiBiquad::filterTypes::LOWPASS, 4000.0f, 0.707f, 0);
|
zc_lpf_.set(maxiBiquad::filterTypes::LOWPASS, 4000.0f, 0.707f, 0);
|
||||||
elapsed_samples_ = 0;
|
elapsed_samples_ = 0;
|
||||||
|
|
@ -31,6 +31,22 @@ XiasriAnalysis::XiasriAnalysis(const float sample_rate) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XiasriAnalysis::ReinitFilters() {
|
||||||
|
// Reinitialize all filters with correct maxiSettings sample rate
|
||||||
|
common_hpf_.set(maxiBiquad::filterTypes::HIGHPASS, 20.f, 0.707f, 0);
|
||||||
|
zc_lpf_.set(maxiBiquad::filterTypes::LOWPASS, 4000.0f, 0.707f, 0);
|
||||||
|
br_lpf1_.set(maxiBiquad::filterTypes::LOWPASS, 1000.0f, 0.707f, 0);
|
||||||
|
br_hpf2_.set(maxiBiquad::filterTypes::HIGHPASS, 1000.0f, 0.707f, 0);
|
||||||
|
br_lpf2_.set(maxiBiquad::filterTypes::LOWPASS, 4000.0f, 0.707f, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use fast approximation (~10 cycles):
|
||||||
|
__force_inline float fast_log2(float x) {
|
||||||
|
static constexpr float INV_MANTISSA_SCALE = 1.0f / 8388608.0f; // 1/(2^23)
|
||||||
|
union { float f; uint32_t i; } u = {x};
|
||||||
|
return (float)(((u.i >> 23) & 0xFF) - 127) +
|
||||||
|
(float)(u.i & 0x7FFFFF) * INV_MANTISSA_SCALE; // Multiply instead of divide
|
||||||
|
}
|
||||||
|
|
||||||
inline float logEnvelopeFast(float linearEnv) {
|
inline float logEnvelopeFast(float linearEnv) {
|
||||||
// -60 dBFS corresponds to a linear amplitude ratio of 10^(-60/20) = 10^(-3) = 0.001
|
// -60 dBFS corresponds to a linear amplitude ratio of 10^(-60/20) = 10^(-3) = 0.001
|
||||||
|
|
@ -53,8 +69,7 @@ inline float logEnvelopeFast(float linearEnv) {
|
||||||
// Clamp input to minimum envelope value
|
// Clamp input to minimum envelope value
|
||||||
linearEnv = (linearEnv > MIN_ENV) ? linearEnv : MIN_ENV;
|
linearEnv = (linearEnv > MIN_ENV) ? linearEnv : MIN_ENV;
|
||||||
|
|
||||||
// Precise logarithmic conversion
|
float log2_val = fast_log2(linearEnv);
|
||||||
float log2_val = std::log2f(linearEnv);
|
|
||||||
|
|
||||||
// Map to [0,1]: (log2_val - log2_min) / (log2_max - log2_min)
|
// Map to [0,1]: (log2_val - log2_min) / (log2_max - log2_min)
|
||||||
float y = (log2_val - LOG2_MIN_ENV) * INV_LOG_RANGE;
|
float y = (log2_val - LOG2_MIN_ENV) * INV_LOG_RANGE;
|
||||||
|
|
@ -66,6 +81,7 @@ inline float logEnvelopeFast(float linearEnv) {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__attribute__((hot, flatten))
|
||||||
XiasriAnalysis::parameters_t AUDIO_FUNC(XiasriAnalysis::Process)(const float x) {
|
XiasriAnalysis::parameters_t AUDIO_FUNC(XiasriAnalysis::Process)(const float x) {
|
||||||
parameters_t params = {};
|
parameters_t params = {};
|
||||||
|
|
||||||
|
|
@ -80,47 +96,40 @@ XiasriAnalysis::parameters_t AUDIO_FUNC(XiasriAnalysis::Process)(const float x)
|
||||||
zc_buffer_.push(median_elapsed_samples);
|
zc_buffer_.push(median_elapsed_samples);
|
||||||
elapsed_samples_ = 0;
|
elapsed_samples_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert zero crossing value to pitch
|
// Convert zero crossing value to pitch
|
||||||
size_t zc_value = zc_buffer_[zc_buffer_.size() - 1];
|
size_t zc_value = zc_buffer_[zc_buffer_.size() - 1];
|
||||||
float pitch = 1.0f / (zc_value * one_over_sample_rate_);
|
|
||||||
// Map [100..800] hz to [0..1] range
|
// OPTIMIZED: Direct division instead of divide-after-multiply
|
||||||
float normalized_pitch;
|
float pitch = sample_rate_ / static_cast<float>(zc_value);
|
||||||
if (pitch <= kPitchMin) {
|
float normalized_pitch = maxiMap::clamp((pitch - kPitchMin) * kPitchScale, 0.0f, 1.0f);
|
||||||
normalized_pitch = 0.0f;
|
|
||||||
} else if (pitch >= kPitchMax) {
|
|
||||||
normalized_pitch = 1.0f;
|
|
||||||
} else {
|
|
||||||
normalized_pitch = (pitch - kPitchMin) * kPitchScale;
|
|
||||||
}
|
|
||||||
elapsed_samples_++;
|
elapsed_samples_++;
|
||||||
|
|
||||||
// Aperiodicity calculation
|
// Aperiodicity calculation
|
||||||
float zc_copy[kZC_ZCBufferSize];
|
float zc_copy[kZC_ZCBufferSize];
|
||||||
// Copy contents of circular buffer to float array
|
|
||||||
for (size_t i = 0; i < kZC_ZCBufferSize; ++i) {
|
for (size_t i = 0; i < kZC_ZCBufferSize; ++i) {
|
||||||
zc_copy[i] = static_cast<float>(zc_buffer_[i]);
|
zc_copy[i] = static_cast<float>(zc_buffer_[i]);
|
||||||
}
|
}
|
||||||
float mad = meanAbsoluteDeviation(zc_copy, kZC_ZCBufferSize);
|
float mad = meanAbsoluteDeviation(zc_copy, kZC_ZCBufferSize);
|
||||||
// Scale MAD relative to median period
|
|
||||||
float medianPeriod = static_cast<float>(zc_value);
|
|
||||||
float relativeMad = mad / (medianPeriod + 1.0f); // +1 to avoid div/0
|
|
||||||
|
|
||||||
// Typical relative MAD ranges from 0 to 0.3 for musical sounds
|
// OPTIMIZED: Multiply by reciprocal
|
||||||
static constexpr float ONE_OVER_RELATIVE_MAD_MAX = 1/0.3f;
|
float medianPeriod = static_cast<float>(zc_value);
|
||||||
float normalizedAperiodicity = std::min(1.0f, relativeMad * ONE_OVER_RELATIVE_MAD_MAX);
|
float medianPeriodRcpr = 1.0f / (medianPeriod + 1.0f);
|
||||||
|
float relativeMad = mad * medianPeriodRcpr;
|
||||||
|
|
||||||
|
static constexpr float ONE_OVER_RELATIVE_MAD_MAX = 1.0f / 0.3f;
|
||||||
|
float normalizedAperiodicity = fminf(1.0f, relativeMad * ONE_OVER_RELATIVE_MAD_MAX);
|
||||||
|
|
||||||
// Envelope follower
|
// Envelope follower
|
||||||
float ef_y = ef_follower_.play(pre_filtered);
|
float ef_y = ef_follower_.play(pre_filtered);
|
||||||
// Convert to log
|
|
||||||
ef_y = logEnvelopeFast(ef_y);
|
ef_y = logEnvelopeFast(ef_y);
|
||||||
|
|
||||||
float ef_d_dy = ef_y - ef_deriv_y_;
|
float ef_d_dy = ef_y - ef_deriv_y_;
|
||||||
ef_deriv_y_ = ef_y;
|
ef_deriv_y_ = ef_y;
|
||||||
// Half-wave rectify the derivative
|
|
||||||
if (ef_d_dy < 0) {
|
|
||||||
ef_d_dy = 0;
|
|
||||||
}
|
|
||||||
// Scale to [0..1] range
|
|
||||||
ef_d_dy = std::min(ef_d_dy * 10.0f, 1.0f);
|
|
||||||
|
|
||||||
|
// OPTIMIZED: Branchless rectify and scale
|
||||||
|
ef_d_dy = fmaxf(0.0f, fminf(ef_d_dy * 10.0f, 1.0f));
|
||||||
|
|
||||||
// Brightness calculation
|
// Brightness calculation
|
||||||
float br_low = br_lpf1_.play(pre_filtered);
|
float br_low = br_lpf1_.play(pre_filtered);
|
||||||
|
|
@ -129,13 +138,10 @@ XiasriAnalysis::parameters_t AUDIO_FUNC(XiasriAnalysis::Process)(const float x)
|
||||||
|
|
||||||
br_low = br_follower_[0].play(br_low);
|
br_low = br_follower_[0].play(br_low);
|
||||||
br_high = br_follower_[1].play(br_high);
|
br_high = br_follower_[1].play(br_high);
|
||||||
// brightness = high_band_energy / (low_band_energy + high_band_energy)
|
|
||||||
float br_energy = br_low + br_high;
|
// OPTIMIZED: Branchless with reciprocal
|
||||||
if (br_energy > 0.0f) {
|
float br_energy = br_low + br_high + 1e-8f;
|
||||||
br_high /= br_energy;
|
br_high = fminf(br_high / br_energy, 1.0f); // Compiler may optimize this division
|
||||||
} else {
|
|
||||||
br_high = 0.0f; // Avoid division by zero
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill parameters
|
// Fill parameters
|
||||||
params.pitch = normalized_pitch;
|
params.pitch = normalized_pitch;
|
||||||
|
|
@ -143,7 +149,7 @@ XiasriAnalysis::parameters_t AUDIO_FUNC(XiasriAnalysis::Process)(const float x)
|
||||||
params.energy = ef_y;
|
params.energy = ef_y;
|
||||||
params.attack = ef_d_dy;
|
params.attack = ef_d_dy;
|
||||||
params.brightness = br_high;
|
params.brightness = br_high;
|
||||||
params.energy_crude = std::abs(x);
|
params.energy_crude = fabsf(x); // Use fabsf instead of std::abs
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
@ -26,6 +26,9 @@ public:
|
||||||
|
|
||||||
parameters_t Process(const float x);
|
parameters_t Process(const float x);
|
||||||
|
|
||||||
|
// Reinitialize filters after maxiSettings is properly configured
|
||||||
|
void ReinitFilters();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const float sample_rate_;
|
const float sample_rate_;
|
||||||
const float one_over_sample_rate_;
|
const float one_over_sample_rate_;
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,17 @@
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept MEMLNautMode = requires(T proc) {
|
concept MEMLNautMode = requires(T proc) {
|
||||||
{proc.getHelpTitle()} -> std::same_as<String>;
|
{proc.getHelpTitle()} -> std::same_as<String>;
|
||||||
{proc.getNParams()} -> std::same_as<size_t>;
|
// {proc.getNParams()} -> std::same_as<size_t>;
|
||||||
{proc.setVoiceSpace(size_t{})} -> std::same_as<void>;
|
// {proc.setVoiceSpace(size_t{})} -> std::same_as<void>;
|
||||||
{proc.setupMIDI(std::shared_ptr<MIDIInOut>{})} -> std::same_as<void>;
|
{proc.setupMIDI(std::shared_ptr<MIDIInOut>{})} -> std::same_as<void>;
|
||||||
{proc.addViews()} -> std::same_as<void>;
|
{proc.addViews()} -> std::same_as<void>;
|
||||||
{proc.Setup(float{}, std::shared_ptr<InterfaceBase>{})} -> std::same_as<void>;
|
{proc.setupAudio(float{})} -> std::same_as<void>;
|
||||||
{proc.loop()} -> std::same_as<void>;
|
{proc.loop()} -> std::same_as<void>;
|
||||||
{proc.getVoiceSpaceList()} -> std::same_as<std::span<String>>;
|
// {proc.getVoiceSpaceList()} -> std::same_as<std::span<String>>;
|
||||||
{proc.process(stereosample_t{})} -> std::same_as<stereosample_t>;
|
{proc.process(stereosample_t{})} -> std::same_as<stereosample_t>;
|
||||||
{proc.analyse(stereosample_t{})} -> std::same_as<void>;
|
{proc.analyse(stereosample_t{})} -> std::same_as<void>;
|
||||||
{proc.processAnalysisParams(std::shared_ptr<InterfaceBase>{})} -> std::same_as<void>;
|
{proc.processAnalysisParams()} -> std::same_as<void>;
|
||||||
{proc.getNMIDICtrlOutputs()} -> std::same_as<size_t>;
|
// {proc.getNMIDICtrlOutputs()} -> std::same_as<size_t>;
|
||||||
|
{proc.setupInterface()} -> std::same_as<void>;
|
||||||
requires std::same_as<decltype(T::kN_InputParams), const size_t>;
|
requires std::same_as<decltype(T::kN_InputParams), const size_t>;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
#include "../src/memllib/interface/MIDIInOut.hpp"
|
#include "../src/memllib/interface/MIDIInOut.hpp"
|
||||||
#include "../ChannelStripAudioApp.hpp"
|
#include "../ChannelStripAudioApp.hpp"
|
||||||
|
#include "../src/memllib/examples/InterfaceRL.hpp"
|
||||||
#include "MEMLNautMode.hpp"
|
#include "MEMLNautMode.hpp"
|
||||||
|
#include "../src/memllib/PicoDefs.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
|
@ -11,21 +13,29 @@ public:
|
||||||
constexpr static size_t kN_InputParams = 3; // joystick x, y, rotate
|
constexpr static size_t kN_InputParams = 3; // joystick x, y, rotate
|
||||||
ChannelStripAudioApp<> audioAppChannelStrip;
|
ChannelStripAudioApp<> audioAppChannelStrip;
|
||||||
std::array<String, ChannelStripAudioApp<>::nVoiceSpaces> voiceSpaceList;
|
std::array<String, ChannelStripAudioApp<>::nVoiceSpaces> voiceSpaceList;
|
||||||
|
InterfaceRL interface;
|
||||||
|
std::shared_ptr<InterfaceRL> interfacePtr;
|
||||||
|
|
||||||
|
void setupInterface() {
|
||||||
|
interface.setup(kN_InputParams, ChannelStripAudioApp<>::kN_Params);
|
||||||
|
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK);
|
||||||
|
interfacePtr = make_non_owning(interface);
|
||||||
|
}
|
||||||
|
|
||||||
String getHelpTitle() {
|
String getHelpTitle() {
|
||||||
return "Channel Strip Mode";
|
return "Channel Strip Mode";
|
||||||
}
|
}
|
||||||
size_t getNParams() {
|
// size_t getNParams() {
|
||||||
return ChannelStripAudioApp<>::kN_Params;
|
// return ChannelStripAudioApp<>::kN_Params;
|
||||||
}
|
// }
|
||||||
|
|
||||||
void setVoiceSpace(size_t i) {
|
// void setVoiceSpace(size_t i) {
|
||||||
audioAppChannelStrip.setVoiceSpace(i);
|
// audioAppChannelStrip.setVoiceSpace(i);
|
||||||
}
|
// }
|
||||||
|
|
||||||
std::span<String> getVoiceSpaceList() {
|
// std::span<String> getVoiceSpaceList() {
|
||||||
return voiceSpaceList;
|
// return voiceSpaceList;
|
||||||
}
|
// }
|
||||||
|
|
||||||
__force_inline stereosample_t process(stereosample_t x) {
|
__force_inline stereosample_t process(stereosample_t x) {
|
||||||
return audioAppChannelStrip.Process(x);
|
return audioAppChannelStrip.Process(x);
|
||||||
|
|
@ -35,11 +45,20 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void addViews() {
|
void addViews() {
|
||||||
|
std::shared_ptr<VoiceSpaceSelectView> voiceSpaceSelectView;
|
||||||
|
voiceSpaceSelectView = std::make_shared<VoiceSpaceSelectView>("Voice Spaces");
|
||||||
|
|
||||||
|
MEMLNaut::Instance()->disp->InsertViewAfter(interface.rlStatsView, voiceSpaceSelectView);
|
||||||
|
voiceSpaceSelectView->setOptions(voiceSpaceList); //set by core 1 on startup
|
||||||
|
voiceSpaceSelectView->setNewVoiceCallback(
|
||||||
|
[this](size_t idx) {
|
||||||
|
audioAppChannelStrip.setVoiceSpace(idx);
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void Setup(float sample_rate, std::shared_ptr<InterfaceBase> interface) {
|
void setupAudio(float sample_rate) {
|
||||||
audioAppChannelStrip.Setup(sample_rate, interface);
|
audioAppChannelStrip.Setup(sample_rate, interfacePtr);
|
||||||
voiceSpaceList = audioAppChannelStrip.getVoiceSpaceNames();
|
voiceSpaceList = audioAppChannelStrip.getVoiceSpaceNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,6 +70,6 @@ public:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void processAnalysisParams(std::shared_ptr<InterfaceBase> interface) {}
|
inline void processAnalysisParams() {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
#include "../src/memllib/hardware/memlnaut/display/XYPadView.hpp"
|
#include "../src/memllib/hardware/memlnaut/display/XYPadView.hpp"
|
||||||
#include "../src/memllib/hardware/memlnaut/MEMLNaut.hpp"
|
#include "../src/memllib/hardware/memlnaut/MEMLNaut.hpp"
|
||||||
#include "../PAFSynthAudioApp.hpp"
|
#include "../PAFSynthAudioApp.hpp"
|
||||||
|
#include "../src/memllib/examples/InterfaceRL.hpp"
|
||||||
|
#include "../src/memllib/PicoDefs.hpp"
|
||||||
#include "MEMLNautMode.hpp"
|
#include "MEMLNautMode.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
@ -15,27 +17,36 @@ public:
|
||||||
inline static PAFSynthAudioApp<> audioAppPAFSynth;
|
inline static PAFSynthAudioApp<> audioAppPAFSynth;
|
||||||
std::array<String, PAFSynthAudioApp<>::nVoiceSpaces> voiceSpaceList;
|
std::array<String, PAFSynthAudioApp<>::nVoiceSpaces> voiceSpaceList;
|
||||||
|
|
||||||
|
InterfaceRL interface;
|
||||||
|
std::shared_ptr<InterfaceRL> interfacePtr;
|
||||||
|
|
||||||
|
void setupInterface() {
|
||||||
|
interface.setup(kN_InputParams, PAFSynthAudioApp<>::kN_Params);
|
||||||
|
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK);
|
||||||
|
interfacePtr = make_non_owning(interface);
|
||||||
|
}
|
||||||
|
|
||||||
String getHelpTitle() {
|
String getHelpTitle() {
|
||||||
return "PAF Synth Mode";
|
return "PAF Synth Mode";
|
||||||
}
|
}
|
||||||
size_t getNParams() {
|
// size_t getNParams() {
|
||||||
return PAFSynthAudioApp<>::kN_Params;
|
// return PAFSynthAudioApp<>::kN_Params;
|
||||||
}
|
// }
|
||||||
|
|
||||||
void setVoiceSpace(size_t i) {
|
// void setVoiceSpace(size_t i) {
|
||||||
audioAppPAFSynth.setVoiceSpace(i);
|
// audioAppPAFSynth.setVoiceSpace(i);
|
||||||
}
|
// }
|
||||||
|
|
||||||
std::span<String> getVoiceSpaceList() {
|
// std::span<String> getVoiceSpaceList() {
|
||||||
return voiceSpaceList;
|
// return voiceSpaceList;
|
||||||
}
|
// }
|
||||||
|
|
||||||
__force_inline stereosample_t process(stereosample_t x) {
|
__force_inline stereosample_t process(stereosample_t x) {
|
||||||
return audioAppPAFSynth.Process(x);
|
return audioAppPAFSynth.Process(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Setup(float sample_rate, std::shared_ptr<InterfaceBase> interface) {
|
void setupAudio(float sample_rate) {
|
||||||
audioAppPAFSynth.Setup(sample_rate, interface);
|
audioAppPAFSynth.Setup(sample_rate, interfacePtr);
|
||||||
voiceSpaceList = audioAppPAFSynth.getVoiceSpaceNames();
|
voiceSpaceList = audioAppPAFSynth.getVoiceSpaceNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,6 +58,10 @@ public:
|
||||||
|
|
||||||
void setupMIDI(std::shared_ptr<MIDIInOut> new_midi_interf) {
|
void setupMIDI(std::shared_ptr<MIDIInOut> new_midi_interf) {
|
||||||
midi_interf = new_midi_interf;
|
midi_interf = new_midi_interf;
|
||||||
|
midi_interf->Setup(16);
|
||||||
|
midi_interf->SetMIDISendChannel(1);
|
||||||
|
interface.bindMIDI(midi_interf);
|
||||||
|
|
||||||
midi_interf->SetNoteCallback([this](bool noteon, uint8_t note_number, uint8_t vel_value) {
|
midi_interf->SetNoteCallback([this](bool noteon, uint8_t note_number, uint8_t vel_value) {
|
||||||
if (noteon) {
|
if (noteon) {
|
||||||
uint8_t midimsg[2] = { note_number, vel_value };
|
uint8_t midimsg[2] = { note_number, vel_value };
|
||||||
|
|
@ -61,6 +76,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void addViews() {
|
void addViews() {
|
||||||
|
std::shared_ptr<VoiceSpaceSelectView> voiceSpaceSelectView;
|
||||||
|
voiceSpaceSelectView = std::make_shared<VoiceSpaceSelectView>("Voice Spaces");
|
||||||
|
|
||||||
|
MEMLNaut::Instance()->disp->InsertViewAfter(interface.rlStatsView, voiceSpaceSelectView);
|
||||||
|
voiceSpaceSelectView->setOptions(voiceSpaceList); //set by core 1 on startup
|
||||||
|
voiceSpaceSelectView->setNewVoiceCallback(
|
||||||
|
[this](size_t idx) {
|
||||||
|
audioAppPAFSynth.setVoiceSpace(idx);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<XYPadView> noteTrigView = std::make_shared<XYPadView>("Play", TFT_SILVER);
|
std::shared_ptr<XYPadView> noteTrigView = std::make_shared<XYPadView>("Play", TFT_SILVER);
|
||||||
|
|
||||||
// Cache MIDI notes being echoed
|
// Cache MIDI notes being echoed
|
||||||
|
|
@ -92,10 +118,10 @@ public:
|
||||||
MEMLNaut::Instance()->disp->AddView(noteTrigView);
|
MEMLNaut::Instance()->disp->AddView(noteTrigView);
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t getNMIDICtrlOutputs() {
|
// size_t getNMIDICtrlOutputs() {
|
||||||
return 16;
|
// return 16;
|
||||||
}
|
// }
|
||||||
|
|
||||||
inline void processAnalysisParams(std::shared_ptr<InterfaceBase> interface) {}
|
inline void processAnalysisParams() {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,16 @@
|
||||||
#include "../XiasriAnalysis.hpp"
|
#include "../XiasriAnalysis.hpp"
|
||||||
#include "../src/memllib/utils/sharedMem.hpp"
|
#include "../src/memllib/utils/sharedMem.hpp"
|
||||||
#include "../src/memllib/audio/AudioDriver.hpp"
|
#include "../src/memllib/audio/AudioDriver.hpp"
|
||||||
|
#include "../src/memllib/examples/InterfaceRL.hpp"
|
||||||
|
#include "../src/memllib/PicoDefs.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MEMLNautModeSoundAnalysisMIDI {
|
class MEMLNautModeSoundAnalysisMIDI {
|
||||||
public:
|
public:
|
||||||
constexpr static size_t kN_InputParams = XiasriAnalysis::kN_Params; // joystick x, y, rotate
|
constexpr static size_t kN_InputParams = XiasriAnalysis::kN_Params + 3; //ML + joystick
|
||||||
|
InterfaceRL interface;
|
||||||
|
std::shared_ptr<InterfaceRL> interfacePtr;
|
||||||
XiasriAnalysis mlAnalysis{kSampleRate};
|
XiasriAnalysis mlAnalysis{kSampleRate};
|
||||||
SharedBuffer<float, XiasriAnalysis::kN_Params> machine_list_buffer;
|
SharedBuffer<float, XiasriAnalysis::kN_Params> machine_list_buffer;
|
||||||
|
|
||||||
|
|
@ -20,20 +25,15 @@ public:
|
||||||
std::array<String, ThruAudioApp<>::nVoiceSpaces> voiceSpaceList;
|
std::array<String, ThruAudioApp<>::nVoiceSpaces> voiceSpaceList;
|
||||||
std::shared_ptr<MIDIInOut> midi_interf;
|
std::shared_ptr<MIDIInOut> midi_interf;
|
||||||
|
|
||||||
|
void setupInterface() {
|
||||||
|
interface.setup(kN_InputParams, ThruAudioApp<>::kN_Params);
|
||||||
|
interface.bindInterface(InterfaceRL::INPUT_MODES::JOYSTICK_AND_MACHINE_LISTENING);
|
||||||
|
interfacePtr = make_non_owning(interface);
|
||||||
|
}
|
||||||
|
|
||||||
String getHelpTitle() {
|
String getHelpTitle() {
|
||||||
return "Sound Analysis MIDI Mode";
|
return "Sound Analysis MIDI Mode";
|
||||||
}
|
}
|
||||||
size_t getNParams() {
|
|
||||||
return ThruAudioApp<>::kN_Params;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setVoiceSpace(size_t i) {
|
|
||||||
audioAppSoundAnalysisMIDI.setVoiceSpace(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::span<String> getVoiceSpaceList() {
|
|
||||||
return voiceSpaceList;
|
|
||||||
}
|
|
||||||
|
|
||||||
__force_inline stereosample_t process(stereosample_t x) {
|
__force_inline stereosample_t process(stereosample_t x) {
|
||||||
return audioAppSoundAnalysisMIDI.Process(x);
|
return audioAppSoundAnalysisMIDI.Process(x);
|
||||||
|
|
@ -41,21 +41,25 @@ public:
|
||||||
|
|
||||||
void setupMIDI(std::shared_ptr<MIDIInOut> new_midi_interf) {
|
void setupMIDI(std::shared_ptr<MIDIInOut> new_midi_interf) {
|
||||||
midi_interf = new_midi_interf;
|
midi_interf = new_midi_interf;
|
||||||
|
midi_interf->Setup(8);
|
||||||
|
midi_interf->SetMIDISendChannel(1);
|
||||||
|
interface.bindMIDI(midi_interf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addViews() {
|
void addViews() {
|
||||||
};
|
};
|
||||||
|
|
||||||
void Setup(float sample_rate, std::shared_ptr<InterfaceBase> interface) {
|
void setupAudio(float sample_rate) {
|
||||||
audioAppSoundAnalysisMIDI.Setup(sample_rate, interface);
|
audioAppSoundAnalysisMIDI.Setup(sample_rate, interfacePtr);
|
||||||
voiceSpaceList = audioAppSoundAnalysisMIDI.getVoiceSpaceNames();
|
// Reinitialize XiasriAnalysis filters after maxiSettings is properly configured
|
||||||
|
mlAnalysis.ReinitFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
__force_inline void loop() {
|
__force_inline void loop() {
|
||||||
audioAppSoundAnalysisMIDI.loop();
|
audioAppSoundAnalysisMIDI.loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void analyse(stereosample_t x) {
|
__force_inline void analyse(stereosample_t x) {
|
||||||
union {
|
union {
|
||||||
XiasriAnalysis::parameters_t p;
|
XiasriAnalysis::parameters_t p;
|
||||||
float v[XiasriAnalysis::kN_Params];
|
float v[XiasriAnalysis::kN_Params];
|
||||||
|
|
@ -65,16 +69,20 @@ public:
|
||||||
machine_list_buffer.writeNonBlocking(param_u.v, XiasriAnalysis::kN_Params);
|
machine_list_buffer.writeNonBlocking(param_u.v, XiasriAnalysis::kN_Params);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t getNMIDICtrlOutputs() {
|
// size_t getNMIDICtrlOutputs() {
|
||||||
return 8;
|
// return 8;
|
||||||
}
|
// }
|
||||||
|
|
||||||
inline void processAnalysisParams(std::shared_ptr<InterfaceBase> interface) {
|
__force_inline void processAnalysisParams() {
|
||||||
// Read SharedBuffer
|
// Read SharedBuffer
|
||||||
std::vector<float> mlist_params(XiasriAnalysis::kN_Params, 0);
|
std::vector<float> mlist_params(XiasriAnalysis::kN_Params, 0);
|
||||||
machine_list_buffer.readNonBlocking(mlist_params);
|
machine_list_buffer.readNonBlocking(mlist_params);
|
||||||
// Send parameters to RL interface
|
// Send parameters to RL interface
|
||||||
interface->readAnalysisParameters(mlist_params);
|
interface.readAnalysisParameters(mlist_params);
|
||||||
|
// PERIODIC_RUN(
|
||||||
|
// Serial.printf("%f %f %f\n", mlist_params[0], mlist_params[1], mlist_params[2]);
|
||||||
|
// , 100);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../src/memllib/interface/MIDIInOut.hpp"
|
|
||||||
#include "../ChannelStripAudioApp.hpp"
|
|
||||||
#include "MEMLNautMode.hpp"
|
|
||||||
#include <memory>
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
class MEMLNautModeXIASRI {
|
|
||||||
public:
|
|
||||||
constexpr static size_t kN_InputParams = XiasriAnalysis::kN_Params; // joystick x, y, rotate
|
|
||||||
|
|
||||||
ChannelStripAudioApp<> audioAppXIASRI;
|
|
||||||
std::array<String, ChannelStripAudioApp<>::nVoiceSpaces> voiceSpaceList;
|
|
||||||
|
|
||||||
String getHelpTitle() {
|
|
||||||
return "XIASRI Mode";
|
|
||||||
}
|
|
||||||
size_t getNParams() {
|
|
||||||
return ChannelStripAudioApp<>::kN_Params;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setVoiceSpace(size_t i) {
|
|
||||||
audioAppXIASRI.setVoiceSpace(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::span<String> getVoiceSpaceList() {
|
|
||||||
return voiceSpaceList;
|
|
||||||
}
|
|
||||||
|
|
||||||
__force_inline stereosample_t process(stereosample_t x) {
|
|
||||||
return audioAppXIASRI.Process(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupMIDI(std::shared_ptr<MIDIInOut> midi_interf) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void addViews() {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
void Setup(float sample_rate, std::shared_ptr<InterfaceBase> interface) {
|
|
||||||
audioAppXIASRI.Setup(sample_rate, interface);
|
|
||||||
voiceSpaceList = audioAppXIASRI.getVoiceSpaceNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
__force_inline void loop() {
|
|
||||||
audioAppXIASRI.loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t getNMIDICtrlOutputs() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void processAnalysisParams(std::shared_ptr<InterfaceBase> interface) {}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
Loading…
Reference in a new issue