diff --git a/README.md b/README.md index 6d54c22..6a072b2 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ ChangeLog ```` +== 2024-12-14 + * Bugfix/Enchancement + * SEQ triggered & trig-input triggered engines were not in sync + * V_OCT/Scale parameter, semitones from active quantizer (#117) + * Claps less RAM usage == 2024-12-07 * Bugfix: * EnvFollower - IO-page AUX input diff --git a/app/DRUMS/Claps.bin b/app/DRUMS/Claps.bin index 60d8492..57604aa 100644 Binary files a/app/DRUMS/Claps.bin and b/app/DRUMS/Claps.bin differ diff --git a/app/DRUMS/Claps.cpp b/app/DRUMS/Claps.cpp index 9921c47..28d81ef 100644 --- a/app/DRUMS/Claps.cpp +++ b/app/DRUMS/Claps.cpp @@ -28,8 +28,6 @@ #include "lib/drumsynth/drumsynth_claps.h" #include "lib/misc/noise.hxx" -float tmp[FRAME_BUFFER_SIZE]; -float tmp2[FRAME_BUFFER_SIZE]; static constexpr size_t n = 8; DrumSynth _instA = nullptr; @@ -80,25 +78,66 @@ void engine::setup() // unpack const uint8_t *p = packed_drumKit; p += 4; - for (size_t i = 0; i < inst_count; i++) + for (size_t i = 0; i < packed_drumKit[0]; i++) { inst[i].name = reinterpret_cast(p); p += 12; - inst[i].n = p[0]; - p += 4; - inst[i].part = reinterpret_cast(p); - p += inst[i].n * sizeof(PartArgs); + + inst[i].n = *reinterpret_cast(p); + p += sizeof(inst[i].n); + + PartArgs *part = new PartArgs[inst[i].n]{}; + inst[i].part = part; + + for (int j = 0; j < inst[i].n; j++) + { + part->flags = *reinterpret_cast(p); + p += sizeof(part->flags); + + part->osc = *reinterpret_cast(p); + p += sizeof(part->osc); + + part->osc_pitch.n = *reinterpret_cast(p); + p += sizeof(part->osc_pitch.n); + part->osc_pitch.xy = reinterpret_cast(p); + p += sizeof(EnvXY) * 16; + + part->osc_amp.n = *reinterpret_cast(p); + p += sizeof(part->osc_amp.n); + part->osc_amp.xy = reinterpret_cast(p); + p += sizeof(EnvXY) * 16; + + part->vca.n = *reinterpret_cast(p); + p += sizeof(part->vca.n); + part->vca.xy = reinterpret_cast(p); + p += sizeof(EnvXY) * 16; + + part->bq1 = *reinterpret_cast(p); + p += sizeof(BiquadArgs); + + part->bq2 = *reinterpret_cast(p); + p += sizeof(BiquadArgs); + + part->ws.n = *reinterpret_cast(p); + p += sizeof(part->ws.n); + part->ws.xy = reinterpret_cast(p); + p += sizeof(WS_XY) * 8; + + part->level = *reinterpret_cast(p); + p += sizeof(part->level); + part++; + } } engine::addParam("Color", &pitch, 0.5f, 1.5f); char *tmp = inst_name_buff; - for (int i = 0; i < LEN_OF(inst_names); i++) + for (int i = 0; i < (inst_count + LEN_OF(seeds)); i++) { inst_names[i] = tmp; tmp += sprint_inst_name(tmp, i) + 1; } - engine::addParam("Clap", &inst_selection, 0, LEN_OF(inst_names) - 1, inst_names); + engine::addParam("Clap", &inst_selection, 0, (inst_count + LEN_OF(seeds)) - 1, inst_names); engine::addParam("Decay", &stretch, 0.1f, 2.0f); engine::addParam("Stereo", &stereo); // param[0].init("Crispy", &crispy, crispy, -1.1f, 1.1f); @@ -191,6 +230,8 @@ void engine::process() auto bufferAux = engine::outputBuffer<1>(); memset(buffer, 0, sizeof(float) * FRAME_BUFFER_SIZE); memset(bufferAux, 0, sizeof(float) * FRAME_BUFFER_SIZE); + float tmpL[FRAME_BUFFER_SIZE]; + float tmpR[FRAME_BUFFER_SIZE]; if (engine::trig()) { @@ -218,30 +259,30 @@ void engine::process() { if (stereo > 0.01f && _cur_inst.part[k].osc.type >= OSC_METALLIC) { - drum_synth_process_frame(_instA, k, (f - (f * 0.01f * stereo)), ¶ms, tmp, FRAME_BUFFER_SIZE); - drum_synth_process_frame(_instB, k, (f + (f * 0.01f * stereo)), ¶ms, tmp2, FRAME_BUFFER_SIZE); + drum_synth_process_frame(_instA, k, (f - (f * 0.01f * stereo)), ¶ms, tmpL, tmpL, FRAME_BUFFER_SIZE); + drum_synth_process_frame(_instB, k, (f + (f * 0.01f * stereo)), ¶ms, tmpR, tmpR, FRAME_BUFFER_SIZE); if (_cur_inst.part[k].osc.type == OSC_METALLIC) { for (int i = 0; i < FRAME_BUFFER_SIZE; i++) { - buffer[i] += tmp[i]; - bufferAux[i] += tmp2[i]; + buffer[i] += tmpL[i]; + bufferAux[i] += tmpR[i]; } } else for (int i = 0; i < FRAME_BUFFER_SIZE; i++) { - buffer[i] += tmp[i]; - bufferAux[i] += tmp[i] * b + tmp2[i] * a; + buffer[i] += tmpL[i]; + bufferAux[i] += tmpL[i] * b + tmpR[i] * a; } } else { - drum_synth_process_frame(_instA, k, f, ¶ms, tmp, FRAME_BUFFER_SIZE); + drum_synth_process_frame(_instA, k, f, ¶ms, tmpL, tmpR, FRAME_BUFFER_SIZE); for (int i = 0; i < FRAME_BUFFER_SIZE; i++) { - buffer[i] += tmp[i]; - bufferAux[i] += tmp[i]; + buffer[i] += tmpL[i]; + bufferAux[i] += tmpR[i]; } } // bufferAux[i] += p._vca.value() * p._amp.value() * 0.99f; diff --git a/app/squares-and-circles-api.h b/app/squares-and-circles-api.h index de5dc07..671ee16 100644 --- a/app/squares-and-circles-api.h +++ b/app/squares-and-circles-api.h @@ -127,6 +127,7 @@ EXTERN_C extern uint8_t *__mixer_level; extern uint8_t *__mixer_pan; + extern uint32_t *__multi_trigs_mask; extern float **__audio_in_l_fpp; extern float **__audio_in_r_fpp; diff --git a/app/upload.py b/app/upload.py index 0f996b8..4cdb779 100755 --- a/app/upload.py +++ b/app/upload.py @@ -172,7 +172,7 @@ def get_appid(binfile): engine["crc32"] = "%x" % crc32sum engines.append(engine) print("NEW ->", file, engine) - continue + #continue #exit(0) elif engine["crc32"] == "%x" % crc32sum: onext = int(engine["addr"], 16) + int(engine["size"]) diff --git a/lib/braids/quantizer.cc b/lib/braids/quantizer.cc index 84083a9..7477132 100644 --- a/lib/braids/quantizer.cc +++ b/lib/braids/quantizer.cc @@ -38,6 +38,8 @@ void Quantizer::Init() { codeword_ = 0; previous_boundary_ = 0; next_boundary_ = 0; + last_note = 64; + num_notes_ = 12; for (int16_t i = 0; i < 128; ++i) { codebook_[i] = (i - 64) << 7; } @@ -56,7 +58,12 @@ void Quantizer::Configure( int16_t span, size_t num_notes) { enabled_ = notes != NULL && num_notes != 0 && span != 0; + num_notes_ = num_notes; if (enabled_) { + codeword_ = 0; + previous_boundary_ = 0; + next_boundary_ = 0; + last_note = 64; int32_t octave = 0; size_t note = 0; int16_t root = 0; diff --git a/lib/braids/quantizer.h b/lib/braids/quantizer.h index bb78720..3367ed1 100644 --- a/lib/braids/quantizer.h +++ b/lib/braids/quantizer.h @@ -62,6 +62,10 @@ class Quantizer { bool enabled(); + size_t NumNotes() { + return num_notes_; + } + private: int8_t last_note; bool enabled_; @@ -69,6 +73,7 @@ class Quantizer { int32_t codeword_; int32_t previous_boundary_; int32_t next_boundary_; + size_t num_notes_; DISALLOW_COPY_AND_ASSIGN(Quantizer); }; diff --git a/lib/drumsynth/drumsynth.cpp b/lib/drumsynth/drumsynth.cpp index b45654a..ef3f98b 100644 --- a/lib/drumsynth/drumsynth.cpp +++ b/lib/drumsynth/drumsynth.cpp @@ -106,6 +106,11 @@ class Envelope } } + inline bool finished() + { + return pos_ != 0 && pos_ == len_; + } + inline float value() { return value_; @@ -183,7 +188,10 @@ class Oscillator inline void Sine(float &out) { - out = stmlib::Interpolate(plaits::lut_sine + 256, osc.phase_, 1024.0f); + // #define PI_F 3.1415927410125732421875f + // out = sinf((0.25f + osc.phase_) * PI_F * 2.f); + + out = stmlib::Interpolate(plaits::lut_sine + 128, osc.phase_, 512.0f); osc.phase_ += phase_inc_; if (osc.phase_ > 1.0f) @@ -207,6 +215,9 @@ struct drum_synth_Part Biquad biquad1 = {}; Biquad biquad2 = {}; + std::pair biquad1b; + std::pair biquad2b; + const PartArgs *part; float amp = 0.4380016479995117f; @@ -284,16 +295,23 @@ struct drum_synth_Part uint32_t last_f = 0; - inline void process_frame(float f, uint32_t t, float stretch, float *out, size_t size) + inline void process_frame(float f, const DrumParams *params, float *outL, float *outR, size_t size) { + uint32_t t = params->t; float osc = 0; + float osc2 = 0; uint32_t ff = f * SAMPLE_RATE; + // if (t > 0 && this->_amp.finished() && this->_vca.finished()) + // { + // return; + // } + while (size--) { - this->_amp.process(t, stretch); - this->_vca.process(t, stretch); - this->_pitch.process(t, stretch); + this->_amp.process(t, params->decay); + this->_vca.process(t, params->decay); + this->_pitch.process(t, params->decay); ++t; @@ -307,8 +325,14 @@ struct drum_synth_Part { case OSC_NOISE1: case OSC_NOISE2: - osc = this->noise.nextf(-1, 1); - break; + { + float a = this->noise.nextf(-1, 1); + float b = this->noise.nextf(-1, 1); + float st = 0.5f - (params->stereo / 2); + osc = (a * (1 - st) + b * st); + osc2 = (b * (1 - st) + a * st); + } + break; case OSC_METALLIC: osc = 0; @@ -374,6 +398,33 @@ struct drum_synth_Part if (part->bq2.mode < BIQUAD_NOTCH) osc *= part->bq2.g; } + + if (params->stereo > 0 && (part->osc.type == OSC_NOISE1 || part->osc.type == OSC_NOISE2)) + { + osc2 *= amp; + osc2 *= this->_amp.value(); + + if (part->bq1.mode) + { + osc2 = this->biquad1.process(osc2, this->biquad1b.first, this->biquad1b.second); + if (part->bq1.mode < BIQUAD_NOTCH) + osc2 *= part->bq1.g; + } + + if (part->ws.n) + osc = waveshaper_transform(osc); + + if (part->bq2.mode) + { + osc2 = this->biquad2.process(osc2, this->biquad2b.first, this->biquad2b.second); + if (part->bq2.mode < BIQUAD_NOTCH) + osc2 *= part->bq2.g; + } + } + else + { + osc2 = osc; + } } else if (part->flags & BIQUAD_PARALLEL) { @@ -383,7 +434,8 @@ struct drum_synth_Part osc = this->biquad2.process(osc) * part->bq2.g; } - *out++ = osc * this->_vca.value() * part->level; + *outL++ = osc * this->_vca.value() * part->level; + *outR++ = osc2 * this->_vca.value() * part->level; } last_f = ff; @@ -423,11 +475,11 @@ extern "C" void drum_synth_reset(DrumSynth inst) } } } -extern "C" void drum_synth_process_frame(DrumSynth inst, int part, float freq, const DrumParams *params, float *out, size_t size) +extern "C" void drum_synth_process_frame(DrumSynth inst, int part, float freq, const DrumParams *params, float *outL, float *outR, size_t size) { if (inst) { auto _part = (drum_synth_Part *)&inst[1]; - _part[part].process_frame(freq, params->t, params->decay, out, size); + _part[part].process_frame(freq, params, outL, outR, size); } } \ No newline at end of file diff --git a/lib/drumsynth/drumsynth.h b/lib/drumsynth/drumsynth.h index 7708079..da35c7b 100644 --- a/lib/drumsynth/drumsynth.h +++ b/lib/drumsynth/drumsynth.h @@ -38,10 +38,22 @@ struct EnvXY struct EnvArgs { int32_t n; - EnvXY xy[16]; + const EnvXY *xy; //[16]; }; -enum BiquadMode +struct WS_XY +{ + float x; + float y; +}; + +struct WSArgs +{ + uint32_t n; + const WS_XY *xy; //[8]; +}; + +enum BiquadMode : uint32_t { BIQUAD_THRU = 0, BIQUAD_LP, @@ -61,7 +73,7 @@ struct BiquadArgs float g; }; -enum OscType +enum OscType : uint32_t { OSC_NONE = 0, OSC_SINE = 1, @@ -85,7 +97,7 @@ struct OscArgs uint32_t n; }; -enum PartFlags +enum PartFlags : uint32_t { BIQUAD_SERIAL = 1 << 1, BIQUAD_PARALLEL = 1 << 2, @@ -93,30 +105,22 @@ enum PartFlags struct PartArgs { - uint32_t flags; + PartFlags flags; OscArgs osc; EnvArgs osc_pitch; EnvArgs osc_amp; EnvArgs vca; BiquadArgs bq1; BiquadArgs bq2; - struct - { - uint32_t n; - struct _ - { - float x; - float y; - } xy[8]; - } ws; + WSArgs ws; float level; }; struct DrumModel { - const char* name; + const char *name; size_t n; - const PartArgs* part; + const PartArgs *part; }; struct DrumParams @@ -124,6 +128,7 @@ struct DrumParams uint32_t t; float attack; float decay; + float stereo; }; struct DrumKit @@ -137,6 +142,6 @@ typedef uint32_t *DrumSynth; extern "C" { DrumSynth drum_synth_init(const DrumModel *inst, void *(*malloc)(size_t size)); - void drum_synth_process_frame(DrumSynth inst, int part, float freq, const DrumParams *params, float *out, size_t size); + void drum_synth_process_frame(DrumSynth inst, int part, float freq, const DrumParams *params, float *outL, float *outR, size_t size); void drum_synth_reset(DrumSynth inst); } \ No newline at end of file diff --git a/lib/misc/Biquad.h b/lib/misc/Biquad.h index 7e12ed2..765910a 100644 --- a/lib/misc/Biquad.h +++ b/lib/misc/Biquad.h @@ -42,7 +42,7 @@ class Biquad void setPeakGain(float peakGainDB); void setBiquad(int type, float Fc, float Q, float peakGainDB); float process(float in); - + float process(float in, float& z1, float& z2); protected: void calcBiquad(void); @@ -74,4 +74,22 @@ inline float Biquad::process(float in) // return y; } +inline float Biquad::process(float in, float& _z1, float& _z2) +{ + float out = in * a0 + _z1; + _z1 = in * a1 + _z2 - b1 * out; + _z2 = in * a2 - b2 * out; + return out; + + // float x = in; + // float y = a0 * x + a1 * x1 + a2 * x2 - b1 * y1 - b2 * y2; + + // x2 = x1; + // x1 = x; + // y2 = y1; + // y1 = y; + + // return y; +} + #endif // Biquad_h diff --git a/platformio.ini b/platformio.ini index 03f42d8..8adc2e0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,5 +9,5 @@ [env:squares-and-circles] apps_json = ./app/index.json -squares_and_circles_loader = 5e1e08e ; minimum loader version +squares_and_circles_loader = 18c0102 ; minimum loader version platform = .pio/ \ No newline at end of file