From 751e9b2f5e8a8ff644d8d91b6f7e3b8f73c41ce1 Mon Sep 17 00:00:00 2001 From: Tim Churches Date: Sun, 25 Jun 2017 14:31:31 +1000 Subject: [PATCH 01/13] [POLYLFO] Add cascading cross-channel amplitude modulation --- software/o_c_REV/APP_POLYLFO.ino | 28 +++++++++++++++++++++++++--- software/o_c_REV/frames_poly_lfo.cpp | 7 ++++++- software/o_c_REV/frames_poly_lfo.h | 15 +++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/software/o_c_REV/APP_POLYLFO.ino b/software/o_c_REV/APP_POLYLFO.ino index 3033a452..2a79761f 100644 --- a/software/o_c_REV/APP_POLYLFO.ino +++ b/software/o_c_REV/APP_POLYLFO.ino @@ -50,6 +50,9 @@ enum POLYLFO_SETTINGS { POLYLFO_SETTING_B_XOR_A, POLYLFO_SETTING_C_XOR_A, POLYLFO_SETTING_D_XOR_A, + POLYLFO_SETTING_B_AM_BY_A, + POLYLFO_SETTING_C_AM_BY_B, + POLYLFO_SETTING_D_AM_BY_C, POLYLFO_SETTING_LAST }; @@ -76,15 +79,15 @@ public: return values_[POLYLFO_SETTING_SHAPE]; } - uint16_t get_shape_spread() const { + int16_t get_shape_spread() const { return values_[POLYLFO_SETTING_SHAPE_SPREAD]; } - uint16_t get_spread() const { + int16_t get_spread() const { return values_[POLYLFO_SETTING_SPREAD]; } - uint16_t get_coupling() const { + int16_t get_coupling() const { return values_[POLYLFO_SETTING_COUPLING]; } @@ -120,6 +123,18 @@ public: return values_[POLYLFO_SETTING_D_XOR_A]; } + uint8_t get_b_am_by_a() const { + return values_[POLYLFO_SETTING_B_AM_BY_A]; + } + + uint8_t get_c_am_by_b() const { + return values_[POLYLFO_SETTING_C_AM_BY_B]; + } + + uint8_t get_d_am_by_c() const { + return values_[POLYLFO_SETTING_D_AM_BY_C]; + } + void Init(); void freeze() { @@ -183,6 +198,9 @@ SETTINGS_DECLARE(PolyLfo, POLYLFO_SETTING_LAST) { { 0, 0, 8, "B XOR A", xor_levels, settings::STORAGE_TYPE_U8 }, { 0, 0, 8, "C XOR A", xor_levels, settings::STORAGE_TYPE_U8 }, { 0, 0, 8, "D XOR A", xor_levels, settings::STORAGE_TYPE_U8 }, + { 0, 0, 127, "B AM by A", NULL, settings::STORAGE_TYPE_U8 }, + { 0, 0, 127, "C AM by B", NULL, settings::STORAGE_TYPE_U8 }, + { 0, 0, 127, "D AM by C", NULL, settings::STORAGE_TYPE_U8 }, }; PolyLfo poly_lfo; @@ -236,6 +254,10 @@ void FASTRUN POLYLFO_isr() { poly_lfo.lfo.set_c_xor_a(poly_lfo.get_c_xor_a()); poly_lfo.lfo.set_d_xor_a(poly_lfo.get_d_xor_a()); + poly_lfo.lfo.set_b_am_by_a(poly_lfo.get_b_am_by_a()); + poly_lfo.lfo.set_c_am_by_b(poly_lfo.get_c_am_by_b()); + poly_lfo.lfo.set_d_am_by_c(poly_lfo.get_d_am_by_c()); + if (!freeze && !poly_lfo.frozen()) poly_lfo.lfo.Render(freq, reset_phase, tempo_sync); diff --git a/software/o_c_REV/frames_poly_lfo.cpp b/software/o_c_REV/frames_poly_lfo.cpp index bcc799e0..fa28ce18 100644 --- a/software/o_c_REV/frames_poly_lfo.cpp +++ b/software/o_c_REV/frames_poly_lfo.cpp @@ -51,6 +51,9 @@ void PolyLfo::Init() { attenuation_ = 58880; offset_ = 0 ; freq_div_b_ = freq_div_c_ = freq_div_d_ = POLYLFO_FREQ_MULT_NONE ; + b_am_by_a_ = 0 ; + c_am_by_b_ = 0 ; + d_am_by_c_ = 0 ; phase_reset_flag_ = false; sync_counter_ = 0 ; sync_ = false; @@ -201,6 +204,7 @@ void PolyLfo::Render(int32_t frequency, bool reset_phase, bool tempo_sync) { uint16_t wavetable_index = shape_; uint8_t xor_depths[] = {0, b_xor_a_, c_xor_a_, d_xor_a_ } ; + uint8_t am_depths[] = {0, b_am_by_a_, c_am_by_b_, d_am_by_c_ } ; // Wavetable lookup for (uint8_t i = 0; i < kNumChannels; ++i) { uint32_t phase = phase_[i]; @@ -221,8 +225,9 @@ void PolyLfo::Render(int32_t frequency, bool reset_phase, bool tempo_sync) { } else { dac_code_[i] = wt_value_[i] + 32768; //Keyframer::ConvertToDacCode(value + 32768, 0); } - dac_code_[i] = ((dac_code_[i] * attenuation_) >> 16) + offset_ ; + if (i > 0 && am_depths[i]) dac_code_[i] = (dac_code_[i] * (65535 - ((dac_code_[i-1] * am_depths[i]) >> 8))) >> 16 ; // attenuation_ // dac_code_[i] += offset_ ; + dac_code_[i] = ((dac_code_[i] * attenuation_) >> 16) + offset_ ; wavetable_index += shape_spread_; } } diff --git a/software/o_c_REV/frames_poly_lfo.h b/software/o_c_REV/frames_poly_lfo.h index a63deff5..9f2f2c2e 100644 --- a/software/o_c_REV/frames_poly_lfo.h +++ b/software/o_c_REV/frames_poly_lfo.h @@ -221,6 +221,18 @@ class PolyLfo { } } + inline void set_b_am_by_a(uint8_t am_value) { + b_am_by_a_ = am_value << 1; + } + + inline void set_c_am_by_b(uint8_t am_value) { + c_am_by_b_ = am_value << 1; + } + + inline void set_d_am_by_c(uint8_t am_value) { + d_am_by_c_ = am_value << 1; + } + inline void set_phase_reset_flag(bool reset) { phase_reset_flag_ = reset; } @@ -270,6 +282,9 @@ class PolyLfo { uint8_t b_xor_a_ ; uint8_t c_xor_a_ ; uint8_t d_xor_a_ ; + uint8_t b_am_by_a_ ; + uint8_t c_am_by_b_ ; + uint8_t d_am_by_c_ ; bool phase_reset_flag_ ; int16_t value_[kNumChannels]; From a8e2b2ad7786da662eece6928a2b573c112e680f Mon Sep 17 00:00:00 2001 From: Tim Churches Date: Sun, 25 Jun 2017 18:19:13 +1000 Subject: [PATCH 02/13] [ENVGEN] First attempt at ASAR envelope type --- software/o_c_REV/APP_ENVGEN.ino | 5 ++- software/o_c_REV/peaks_multistage_envelope.h | 34 +++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/software/o_c_REV/APP_ENVGEN.ino b/software/o_c_REV/APP_ENVGEN.ino index 4bafeb23..f921fef4 100644 --- a/software/o_c_REV/APP_ENVGEN.ino +++ b/software/o_c_REV/APP_ENVGEN.ino @@ -107,6 +107,7 @@ enum EnvelopeType { ENV_TYPE_ADL2R, ENV_TYPE_ADAL2R, ENV_TYPE_ADARL4, + ENV_TYPE_ASAR, ENV_TYPE_LAST, ENV_TYPE_FIRST = ENV_TYPE_AD }; @@ -310,6 +311,7 @@ public: case ENV_TYPE_ADL2R: case ENV_TYPE_ADARL4: case ENV_TYPE_ADAL2R: + case ENV_TYPE_ASAR: return 4; default: break; } @@ -460,6 +462,7 @@ public: case ENV_TYPE_ADL2R: env_.set_adr(s[0], s[1], s[2]>>1, s[3], 0, 2); break; case ENV_TYPE_ADARL4: env_.set_adar(s[0], s[1], s[2]>>1, s[3], 0, 4); break; case ENV_TYPE_ADAL2R: env_.set_adar(s[0], s[1], s[2]>>1, s[3], 1, 3); break; // was 2, 4 + case ENV_TYPE_ASAR: env_.set_asad(s[0], s[2]>>1, s[1], s[3], 0, 0); break; default: break; } @@ -687,7 +690,7 @@ void EnvelopeGenerator::Init(OC::DigitalInput default_trigger) { } const char* const envelope_types[ENV_TYPE_LAST] = { - "AD", "ADSR", "ADR", "ASR", "ADSAR", "ADAR", "ADL2", "ADRL3", "ADL2R", "ADAL2R", "ADARL4" + "AD", "ADSR", "ADR", "ASR", "ADSAR", "ADAR", "ADL2", "ADRL3", "ADL2R", "ADAL2R", "ADARL4", "ASAR" }; const char* const segment_names[] = { diff --git a/software/o_c_REV/peaks_multistage_envelope.h b/software/o_c_REV/peaks_multistage_envelope.h index 26b9e02e..e1c58f46 100644 --- a/software/o_c_REV/peaks_multistage_envelope.h +++ b/software/o_c_REV/peaks_multistage_envelope.h @@ -287,7 +287,39 @@ class MultistageEnvelope { loop_start_ = loop_start; loop_end_ = loop_end; } - + + inline void set_asad( + uint16_t attack, + uint16_t decay, + uint16_t sustain, + uint16_t release, + uint16_t loop_start, + uint16_t loop_end) { + num_segments_ = 4; + sustain_point_ = 1; + sustain_index_ = 1; + + level_[0] = 0; + level_[1] = sustain; + level_[2] = 32767; + level_[3] = 0; + + time_[0] = attack; + time_[1] = decay; + time_[2] = release; + + shape_[0] = attack_shape_; + shape_[1] = decay_shape_; + shape_[2] = release_shape_; + + time_multiplier_[0] = attack_multiplier_; + time_multiplier_[1] = decay_multiplier_; + time_multiplier_[2] = release_multiplier_; + + loop_start_ = loop_start ; + loop_end_ = loop_end ; + } + inline void set_attack_reset_behaviour(EnvResetBehaviour reset_behaviour) { attack_reset_behaviour_ = reset_behaviour; } From 7eb8e5baa48257eb34274fe8de7e107b29374c63 Mon Sep 17 00:00:00 2001 From: mxmxmx Date: Sun, 25 Jun 2017 18:26:16 +0200 Subject: [PATCH 03/13] [QQ] init mask --- software/o_c_REV/APP_QQ.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/software/o_c_REV/APP_QQ.ino b/software/o_c_REV/APP_QQ.ino index 75f4b553..e379c515 100644 --- a/software/o_c_REV/APP_QQ.ino +++ b/software/o_c_REV/APP_QQ.ino @@ -1205,6 +1205,7 @@ size_t QQ_restore(const void *storage) { size_t used = 0; for (size_t i = 0; i < 4; ++i) { used += quantizer_channels[i].Restore(static_cast(storage) + used); + quantizer_channels[i].update_scale_mask(quantizer_channels[i].get_mask(), 0x0); quantizer_channels[i].update_enabled_settings(); } qq_state.cursor.AdjustEnd(quantizer_channels[0].num_enabled_settings() - 1); From 7a008c79a4a8942becd3a0679a8ee577a1745440 Mon Sep 17 00:00:00 2001 From: Tim Churches Date: Mon, 26 Jun 2017 09:40:26 +1000 Subject: [PATCH 04/13] Revert "[ENVGEN] First attempt at ASAR envelope type" This reverts commit a8e2b2ad7786da662eece6928a2b573c112e680f. --- software/o_c_REV/APP_ENVGEN.ino | 5 +-- software/o_c_REV/peaks_multistage_envelope.h | 34 +------------------- 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/software/o_c_REV/APP_ENVGEN.ino b/software/o_c_REV/APP_ENVGEN.ino index f921fef4..4bafeb23 100644 --- a/software/o_c_REV/APP_ENVGEN.ino +++ b/software/o_c_REV/APP_ENVGEN.ino @@ -107,7 +107,6 @@ enum EnvelopeType { ENV_TYPE_ADL2R, ENV_TYPE_ADAL2R, ENV_TYPE_ADARL4, - ENV_TYPE_ASAR, ENV_TYPE_LAST, ENV_TYPE_FIRST = ENV_TYPE_AD }; @@ -311,7 +310,6 @@ public: case ENV_TYPE_ADL2R: case ENV_TYPE_ADARL4: case ENV_TYPE_ADAL2R: - case ENV_TYPE_ASAR: return 4; default: break; } @@ -462,7 +460,6 @@ public: case ENV_TYPE_ADL2R: env_.set_adr(s[0], s[1], s[2]>>1, s[3], 0, 2); break; case ENV_TYPE_ADARL4: env_.set_adar(s[0], s[1], s[2]>>1, s[3], 0, 4); break; case ENV_TYPE_ADAL2R: env_.set_adar(s[0], s[1], s[2]>>1, s[3], 1, 3); break; // was 2, 4 - case ENV_TYPE_ASAR: env_.set_asad(s[0], s[2]>>1, s[1], s[3], 0, 0); break; default: break; } @@ -690,7 +687,7 @@ void EnvelopeGenerator::Init(OC::DigitalInput default_trigger) { } const char* const envelope_types[ENV_TYPE_LAST] = { - "AD", "ADSR", "ADR", "ASR", "ADSAR", "ADAR", "ADL2", "ADRL3", "ADL2R", "ADAL2R", "ADARL4", "ASAR" + "AD", "ADSR", "ADR", "ASR", "ADSAR", "ADAR", "ADL2", "ADRL3", "ADL2R", "ADAL2R", "ADARL4" }; const char* const segment_names[] = { diff --git a/software/o_c_REV/peaks_multistage_envelope.h b/software/o_c_REV/peaks_multistage_envelope.h index e1c58f46..26b9e02e 100644 --- a/software/o_c_REV/peaks_multistage_envelope.h +++ b/software/o_c_REV/peaks_multistage_envelope.h @@ -287,39 +287,7 @@ class MultistageEnvelope { loop_start_ = loop_start; loop_end_ = loop_end; } - - inline void set_asad( - uint16_t attack, - uint16_t decay, - uint16_t sustain, - uint16_t release, - uint16_t loop_start, - uint16_t loop_end) { - num_segments_ = 4; - sustain_point_ = 1; - sustain_index_ = 1; - - level_[0] = 0; - level_[1] = sustain; - level_[2] = 32767; - level_[3] = 0; - - time_[0] = attack; - time_[1] = decay; - time_[2] = release; - - shape_[0] = attack_shape_; - shape_[1] = decay_shape_; - shape_[2] = release_shape_; - - time_multiplier_[0] = attack_multiplier_; - time_multiplier_[1] = decay_multiplier_; - time_multiplier_[2] = release_multiplier_; - - loop_start_ = loop_start ; - loop_end_ = loop_end ; - } - + inline void set_attack_reset_behaviour(EnvResetBehaviour reset_behaviour) { attack_reset_behaviour_ = reset_behaviour; } From 637a0352628a9713f24d5e110833e68679daac32 Mon Sep 17 00:00:00 2001 From: Tim Churches Date: Mon, 26 Jun 2017 09:42:01 +1000 Subject: [PATCH 05/13] [POLYLFO] Fix the direction in which cross-channel AM works. --- software/o_c_REV/frames_poly_lfo.cpp | 5 +++-- software/o_c_REV/frames_poly_lfo.h | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/software/o_c_REV/frames_poly_lfo.cpp b/software/o_c_REV/frames_poly_lfo.cpp index fa28ce18..788b80d4 100644 --- a/software/o_c_REV/frames_poly_lfo.cpp +++ b/software/o_c_REV/frames_poly_lfo.cpp @@ -225,8 +225,9 @@ void PolyLfo::Render(int32_t frequency, bool reset_phase, bool tempo_sync) { } else { dac_code_[i] = wt_value_[i] + 32768; //Keyframer::ConvertToDacCode(value + 32768, 0); } - if (i > 0 && am_depths[i]) dac_code_[i] = (dac_code_[i] * (65535 - ((dac_code_[i-1] * am_depths[i]) >> 8))) >> 16 ; // attenuation_ - // dac_code_[i] += offset_ ; + // cross-channel AM + dac_code_[i] = (dac_code_[i] * (65535 - (((65535 - dac_code_[i-1]) * am_depths[i]) >> 8))) >> 16 ; + // attenuationand offset dac_code_[i] = ((dac_code_[i] * attenuation_) >> 16) + offset_ ; wavetable_index += shape_spread_; } diff --git a/software/o_c_REV/frames_poly_lfo.h b/software/o_c_REV/frames_poly_lfo.h index 9f2f2c2e..7dafa196 100644 --- a/software/o_c_REV/frames_poly_lfo.h +++ b/software/o_c_REV/frames_poly_lfo.h @@ -222,15 +222,15 @@ class PolyLfo { } inline void set_b_am_by_a(uint8_t am_value) { - b_am_by_a_ = am_value << 1; + b_am_by_a_ = (am_value << 1); } inline void set_c_am_by_b(uint8_t am_value) { - c_am_by_b_ = am_value << 1; + c_am_by_b_ = (am_value << 1); } inline void set_d_am_by_c(uint8_t am_value) { - d_am_by_c_ = am_value << 1; + d_am_by_c_ = (am_value << 1); } inline void set_phase_reset_flag(bool reset) { From 39b64d310c0b0500f8a13e68ba23c166b741ca11 Mon Sep 17 00:00:00 2001 From: mxmxmx Date: Tue, 27 Jun 2017 08:38:40 +0200 Subject: [PATCH 06/13] [POLY] cv4 --- software/o_c_REV/APP_POLYLFO.ino | 72 ++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/software/o_c_REV/APP_POLYLFO.ino b/software/o_c_REV/APP_POLYLFO.ino index 2a79761f..d0b72e40 100644 --- a/software/o_c_REV/APP_POLYLFO.ino +++ b/software/o_c_REV/APP_POLYLFO.ino @@ -53,6 +53,7 @@ enum POLYLFO_SETTINGS { POLYLFO_SETTING_B_AM_BY_A, POLYLFO_SETTING_C_AM_BY_B, POLYLFO_SETTING_D_AM_BY_C, + POLYLFO_SETTING_CV4, POLYLFO_SETTING_LAST }; @@ -135,6 +136,10 @@ public: return values_[POLYLFO_SETTING_D_AM_BY_C]; } + uint8_t cv4_destination() const { + return values_[POLYLFO_SETTING_CV4]; + } + void Init(); void freeze() { @@ -158,7 +163,7 @@ public: SmoothedValue cv_freq; SmoothedValue cv_shape; SmoothedValue cv_spread; - SmoothedValue cv_coupling; + SmoothedValue cv_mappable; }; void PolyLfo::Init() { @@ -181,6 +186,10 @@ const char* const xor_levels[9] = { "off", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8" }; +const char* const cv4_destinations[7] = { + "cplg", "sprd", "attn", "offs", "a->b", "b->c", "c->d" +}; + SETTINGS_DECLARE(PolyLfo, POLYLFO_SETTING_LAST) { { 64, 0, 255, "C", NULL, settings::STORAGE_TYPE_U8 }, { 0, -128, 127, "F", NULL, settings::STORAGE_TYPE_I16 }, @@ -201,6 +210,7 @@ SETTINGS_DECLARE(PolyLfo, POLYLFO_SETTING_LAST) { { 0, 0, 127, "B AM by A", NULL, settings::STORAGE_TYPE_U8 }, { 0, 0, 127, "C AM by B", NULL, settings::STORAGE_TYPE_U8 }, { 0, 0, 127, "D AM by C", NULL, settings::STORAGE_TYPE_U8 }, + { 0, 0, 6, "CV4 ->", cv4_destinations, settings::STORAGE_TYPE_U8 }, }; PolyLfo poly_lfo; @@ -220,12 +230,15 @@ void FASTRUN POLYLFO_isr() { poly_lfo.cv_freq.push(OC::ADC::value()); poly_lfo.cv_shape.push(OC::ADC::value()); poly_lfo.cv_spread.push(OC::ADC::value()); - poly_lfo.cv_coupling.push(OC::ADC::value()); + poly_lfo.cv_mappable.push(OC::ADC::value()); // Range in settings is (0-256] so this gets scaled to (0,65535] // CV value is 12 bit so also needs scaling int32_t freq = SCALE8_16(poly_lfo.get_coarse()) + (poly_lfo.cv_freq.value() * 16) + poly_lfo.get_fine() * 2; + + // double frequency if TR4 / gate high + freq = digitalReadFast(TR4) ? freq : (freq << 1); freq = USAT16(freq); poly_lfo.lfo.set_freq_range(poly_lfo.get_freq_range()); @@ -238,13 +251,49 @@ void FASTRUN POLYLFO_isr() { int32_t spread = SCALE8_16(poly_lfo.get_spread() + 128) + (poly_lfo.cv_spread.value() * 16); poly_lfo.lfo.set_spread(USAT16(spread)); - int32_t coupling = SCALE8_16(poly_lfo.get_coupling() + 127) + (poly_lfo.cv_coupling.value() * 16); + int32_t coupling = 0; + int32_t shape_spread = 0; + int32_t attenuation = 0; + int32_t offset = 0; + int32_t b_am_by_a = 0; + int32_t c_am_by_b = 0; + int32_t d_am_by_c = 0; + + switch (poly_lfo.cv4_destination()) { + case 1: // shape spread + shape_spread = poly_lfo.cv_mappable.value() << 4; + break; + case 2: // attenuation + attenuation = poly_lfo.cv_mappable.value() << 4; + break; + case 3: // offset + offset = poly_lfo.cv_mappable.value() << 4; + break; + case 4: // "a->b" + b_am_by_a = poly_lfo.cv_mappable.value() << 4; + break; + case 5: // "b->c" + c_am_by_b = poly_lfo.cv_mappable.value() << 4; + break; + case 6: // "c->d" + d_am_by_c = poly_lfo.cv_mappable.value() << 4; + break; + default: // default == coupling + coupling = poly_lfo.cv_mappable.value() << 4; + break; + } + + coupling += SCALE8_16(poly_lfo.get_coupling() + 127); poly_lfo.lfo.set_coupling(USAT16(coupling)); - poly_lfo.lfo.set_shape_spread(SCALE8_16(poly_lfo.get_shape_spread() + 127)); + shape_spread += SCALE8_16(poly_lfo.get_shape_spread() + 127); + poly_lfo.lfo.set_shape_spread(USAT16(shape_spread)); + + attenuation += SCALE8_16(poly_lfo.get_attenuation()); + poly_lfo.lfo.set_attenuation(USAT16(attenuation)); - poly_lfo.lfo.set_attenuation(SCALE8_16(poly_lfo.get_attenuation())); - poly_lfo.lfo.set_offset(SCALE8_16(poly_lfo.get_offset())); + offset += SCALE8_16(poly_lfo.get_offset()); + poly_lfo.lfo.set_offset(USAT16(offset)); poly_lfo.lfo.set_freq_div_b(poly_lfo.get_freq_div_b()); poly_lfo.lfo.set_freq_div_c(poly_lfo.get_freq_div_c()); @@ -254,9 +303,14 @@ void FASTRUN POLYLFO_isr() { poly_lfo.lfo.set_c_xor_a(poly_lfo.get_c_xor_a()); poly_lfo.lfo.set_d_xor_a(poly_lfo.get_d_xor_a()); - poly_lfo.lfo.set_b_am_by_a(poly_lfo.get_b_am_by_a()); - poly_lfo.lfo.set_c_am_by_b(poly_lfo.get_c_am_by_b()); - poly_lfo.lfo.set_d_am_by_c(poly_lfo.get_d_am_by_c()); + b_am_by_a += poly_lfo.get_b_am_by_a(); + poly_lfo.lfo.set_b_am_by_a(USAT16(b_am_by_a)); + + c_am_by_b += poly_lfo.get_c_am_by_b(); + poly_lfo.lfo.set_c_am_by_b(USAT16(c_am_by_b)); + + d_am_by_c += poly_lfo.get_d_am_by_c(); + poly_lfo.lfo.set_d_am_by_c(USAT16(d_am_by_c)); if (!freeze && !poly_lfo.frozen()) poly_lfo.lfo.Render(freq, reset_phase, tempo_sync); From 33f8cad6d73b8b19c84ec2fc33bd109cffcfc842 Mon Sep 17 00:00:00 2001 From: mxmxmx Date: Tue, 27 Jun 2017 20:11:15 +0200 Subject: [PATCH 07/13] [POLY] AM CV --- software/o_c_REV/APP_POLYLFO.ino | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/software/o_c_REV/APP_POLYLFO.ino b/software/o_c_REV/APP_POLYLFO.ino index d0b72e40..45a7f7a4 100644 --- a/software/o_c_REV/APP_POLYLFO.ino +++ b/software/o_c_REV/APP_POLYLFO.ino @@ -260,25 +260,26 @@ void FASTRUN POLYLFO_isr() { int32_t d_am_by_c = 0; switch (poly_lfo.cv4_destination()) { - case 1: // shape spread + case 1: // shape spread: -128, 127 shape_spread = poly_lfo.cv_mappable.value() << 4; break; - case 2: // attenuation + case 2: // attenuation: 0, 230 attenuation = poly_lfo.cv_mappable.value() << 4; break; - case 3: // offset + case 3: // offset: -128, 127 offset = poly_lfo.cv_mappable.value() << 4; break; - case 4: // "a->b" - b_am_by_a = poly_lfo.cv_mappable.value() << 4; + case 4: // "a->b", 0-127 + b_am_by_a = (poly_lfo.cv_mappable.value() + 15) >> 5; break; - case 5: // "b->c" - c_am_by_b = poly_lfo.cv_mappable.value() << 4; + case 5: // "b->c", 0-127 + c_am_by_b = (poly_lfo.cv_mappable.value() + 15) >> 5; break; - case 6: // "c->d" - d_am_by_c = poly_lfo.cv_mappable.value() << 4; + case 6: // "c->d", 0-127 + d_am_by_c = (poly_lfo.cv_mappable.value() + 15) >> 5; break; - default: // default == coupling + case 0: // coupling, -128, 127 + default: coupling = poly_lfo.cv_mappable.value() << 4; break; } @@ -304,13 +305,16 @@ void FASTRUN POLYLFO_isr() { poly_lfo.lfo.set_d_xor_a(poly_lfo.get_d_xor_a()); b_am_by_a += poly_lfo.get_b_am_by_a(); - poly_lfo.lfo.set_b_am_by_a(USAT16(b_am_by_a)); + CONSTRAIN(b_am_by_a, 0, 127); + poly_lfo.lfo.set_b_am_by_a(b_am_by_a); c_am_by_b += poly_lfo.get_c_am_by_b(); - poly_lfo.lfo.set_c_am_by_b(USAT16(c_am_by_b)); + CONSTRAIN(c_am_by_b, 0, 127); + poly_lfo.lfo.set_c_am_by_b(c_am_by_b); d_am_by_c += poly_lfo.get_d_am_by_c(); - poly_lfo.lfo.set_d_am_by_c(USAT16(d_am_by_c)); + CONSTRAIN(d_am_by_c, 0, 127); + poly_lfo.lfo.set_d_am_by_c(d_am_by_c); if (!freeze && !poly_lfo.frozen()) poly_lfo.lfo.Render(freq, reset_phase, tempo_sync); From b99de65fddd14f9bf0edc6dfedd3b26db27c439f Mon Sep 17 00:00:00 2001 From: mxmxmx Date: Tue, 27 Jun 2017 20:35:38 +0200 Subject: [PATCH 08/13] [POLY] TR4: double F --- software/o_c_REV/APP_POLYLFO.ino | 23 ++++++++++++++++++----- software/o_c_REV/frames_poly_lfo.cpp | 6 +++--- software/o_c_REV/frames_poly_lfo.h | 2 +- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/software/o_c_REV/APP_POLYLFO.ino b/software/o_c_REV/APP_POLYLFO.ino index 45a7f7a4..9243d904 100644 --- a/software/o_c_REV/APP_POLYLFO.ino +++ b/software/o_c_REV/APP_POLYLFO.ino @@ -154,8 +154,17 @@ public: return frozen_; } + bool freq_mult() const { + return freq_mult_; + } + + void set_freq_mult(bool freq_mult) { + freq_mult_ = freq_mult; + } + frames::PolyLfo lfo; bool frozen_; + bool freq_mult_; // ISR update is at 16.666kHz, we don't need it that fast so smooth the values to ~1Khz static constexpr int32_t kSmoothing = 16; @@ -170,6 +179,7 @@ void PolyLfo::Init() { InitDefaults(); lfo.Init(); frozen_= false; + freq_mult_ = false; } const char* const freq_range_names[12] = { @@ -236,9 +246,6 @@ void FASTRUN POLYLFO_isr() { // CV value is 12 bit so also needs scaling int32_t freq = SCALE8_16(poly_lfo.get_coarse()) + (poly_lfo.cv_freq.value() * 16) + poly_lfo.get_fine() * 2; - - // double frequency if TR4 / gate high - freq = digitalReadFast(TR4) ? freq : (freq << 1); freq = USAT16(freq); poly_lfo.lfo.set_freq_range(poly_lfo.get_freq_range()); @@ -315,9 +322,13 @@ void FASTRUN POLYLFO_isr() { d_am_by_c += poly_lfo.get_d_am_by_c(); CONSTRAIN(d_am_by_c, 0, 127); poly_lfo.lfo.set_d_am_by_c(d_am_by_c); + + // double frequency if TR4 / gate high + bool freq_mult = digitalReadFast(TR4) ? false : true; + poly_lfo.set_freq_mult(freq_mult); if (!freeze && !poly_lfo.frozen()) - poly_lfo.lfo.Render(freq, reset_phase, tempo_sync); + poly_lfo.lfo.Render(freq, reset_phase, tempo_sync, freq_mult); OC::DAC::set(poly_lfo.lfo.dac_code(0)); OC::DAC::set(poly_lfo.lfo.dac_code(1)); @@ -356,7 +367,9 @@ void POLYLFO_menu() { if (poly_lfo.get_tap_tempo()) { graphics.print("(T) Ch A: tap tempo") ; } else { - float menu_freq_ = poly_lfo.lfo.get_freq_ch1() ; + float menu_freq_ = poly_lfo.lfo.get_freq_ch1(); + if (poly_lfo.freq_mult()) + graphics.drawBitmap8(122, menu::DefaultTitleBar::kTextY, 4, OC::bitmap_indicator_4x8); if (menu_freq_ >= 0.1f) { graphics.printf("(%s) Ch A: %6.2f Hz", PolyLfo::value_attr(poly_lfo_state.left_edit_mode).name, menu_freq_); } else { diff --git a/software/o_c_REV/frames_poly_lfo.cpp b/software/o_c_REV/frames_poly_lfo.cpp index 788b80d4..e1187ab0 100644 --- a/software/o_c_REV/frames_poly_lfo.cpp +++ b/software/o_c_REV/frames_poly_lfo.cpp @@ -130,7 +130,7 @@ uint32_t PolyLfo::FrequencyToPhaseIncrement(int32_t frequency, uint16_t frq_rng) return (a + ((b - a) * (index & 0x1f) >> 5)) << shifts; } -void PolyLfo::Render(int32_t frequency, bool reset_phase, bool tempo_sync) { +void PolyLfo::Render(int32_t frequency, bool reset_phase, bool tempo_sync, bool freq_mult) { ++sync_counter_; if (tempo_sync && sync_) { if (sync_counter_ < kSyncCounterMaxTime) { @@ -162,8 +162,8 @@ void PolyLfo::Render(int32_t frequency, bool reset_phase, bool tempo_sync) { } else { phase_increment_ch1_ = FrequencyToPhaseIncrement(frequency, freq_range_); } - phase_[0] += phase_increment_ch1_ ; - PolyLfoFreqMultipliers FreqDivs[] = {POLYLFO_FREQ_MULT_NONE, freq_div_b_, freq_div_c_ , freq_div_d_ } ; + phase_[0] += phase_increment_ch1_ << freq_mult; + PolyLfoFreqMultipliers FreqDivs[] = {POLYLFO_FREQ_MULT_NONE, freq_div_b_, freq_div_c_ , freq_div_d_} ; for (uint8_t i = 1; i < kNumChannels; ++i) { if (FreqDivs[i] == POLYLFO_FREQ_MULT_NONE) { phase_[i] += phase_increment_ch1_; diff --git a/software/o_c_REV/frames_poly_lfo.h b/software/o_c_REV/frames_poly_lfo.h index 7dafa196..970bfcd9 100644 --- a/software/o_c_REV/frames_poly_lfo.h +++ b/software/o_c_REV/frames_poly_lfo.h @@ -133,7 +133,7 @@ class PolyLfo { ~PolyLfo() { } void Init(); - void Render(int32_t frequency, bool reset_phase, bool tempo_sync); + void Render(int32_t frequency, bool reset_phase, bool tempo_sync, bool freq_mult); void RenderPreview(uint16_t shape, uint16_t *buffer, size_t size); inline void set_freq_range(uint16_t freq_range) { From c3c9600e10fa5fa1adf7f15fceb8da1aa3e1c79d Mon Sep 17 00:00:00 2001 From: mxmxmx Date: Tue, 27 Jun 2017 22:19:06 +0200 Subject: [PATCH 09/13] [POLY] CV4 --- software/o_c_REV/APP_POLYLFO.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/software/o_c_REV/APP_POLYLFO.ino b/software/o_c_REV/APP_POLYLFO.ino index 9243d904..e9b01c1b 100644 --- a/software/o_c_REV/APP_POLYLFO.ino +++ b/software/o_c_REV/APP_POLYLFO.ino @@ -197,7 +197,7 @@ const char* const xor_levels[9] = { }; const char* const cv4_destinations[7] = { - "cplg", "sprd", "attn", "offs", "a->b", "b->c", "c->d" + "cplg", "sprd", " rng", "offs", "a->b", "b->c", "c->d" }; SETTINGS_DECLARE(PolyLfo, POLYLFO_SETTING_LAST) { From 75d68b8e32f62e81c24ca5858dbbf9ad70569577 Mon Sep 17 00:00:00 2001 From: mxmxmx Date: Wed, 28 Jun 2017 14:42:57 +0200 Subject: [PATCH 10/13] [POLY] TR4: 2x for all channels --- software/o_c_REV/frames_poly_lfo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/software/o_c_REV/frames_poly_lfo.cpp b/software/o_c_REV/frames_poly_lfo.cpp index e1187ab0..800a6e01 100644 --- a/software/o_c_REV/frames_poly_lfo.cpp +++ b/software/o_c_REV/frames_poly_lfo.cpp @@ -160,15 +160,15 @@ void PolyLfo::Render(int32_t frequency, bool reset_phase, bool tempo_sync, bool if (sync_) { phase_increment_ch1_ = sync_phase_increment_; } else { - phase_increment_ch1_ = FrequencyToPhaseIncrement(frequency, freq_range_); + phase_increment_ch1_ = FrequencyToPhaseIncrement(frequency, freq_range_) << freq_mult; } - phase_[0] += phase_increment_ch1_ << freq_mult; + phase_[0] += phase_increment_ch1_; PolyLfoFreqMultipliers FreqDivs[] = {POLYLFO_FREQ_MULT_NONE, freq_div_b_, freq_div_c_ , freq_div_d_} ; for (uint8_t i = 1; i < kNumChannels; ++i) { if (FreqDivs[i] == POLYLFO_FREQ_MULT_NONE) { phase_[i] += phase_increment_ch1_; } else { - phase_[i] += multiply_u32xu32_rshift24(phase_increment_ch1_, PolyLfoFreqMultNumerators[FreqDivs[i]]) ; + phase_[i] += multiply_u32xu32_rshift24(phase_increment_ch1_, PolyLfoFreqMultNumerators[FreqDivs[i]]) ; } } From 4b86647eb7f0d5adbb550d025a42df28f4bc64ef Mon Sep 17 00:00:00 2001 From: mxmxmx Date: Wed, 28 Jun 2017 15:50:20 +0200 Subject: [PATCH 11/13] [POLY] TR4 / double F (across modes) --- software/o_c_REV/frames_poly_lfo.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/software/o_c_REV/frames_poly_lfo.cpp b/software/o_c_REV/frames_poly_lfo.cpp index 800a6e01..a9fcd132 100644 --- a/software/o_c_REV/frames_poly_lfo.cpp +++ b/software/o_c_REV/frames_poly_lfo.cpp @@ -160,8 +160,11 @@ void PolyLfo::Render(int32_t frequency, bool reset_phase, bool tempo_sync, bool if (sync_) { phase_increment_ch1_ = sync_phase_increment_; } else { - phase_increment_ch1_ = FrequencyToPhaseIncrement(frequency, freq_range_) << freq_mult; + phase_increment_ch1_ = FrequencyToPhaseIncrement(frequency, freq_range_); } + // double F (via TR4) + phase_increment_ch1_ = phase_increment_ch1_ << freq_mult; + phase_[0] += phase_increment_ch1_; PolyLfoFreqMultipliers FreqDivs[] = {POLYLFO_FREQ_MULT_NONE, freq_div_b_, freq_div_c_ , freq_div_d_} ; for (uint8_t i = 1; i < kNumChannels; ++i) { From 68d85bdac0682e75af1072bb9b0ac33aa39b77d8 Mon Sep 17 00:00:00 2001 From: mxmxmx Date: Wed, 28 Jun 2017 22:23:35 +0200 Subject: [PATCH 12/13] [POLY] TR4 choices --- software/o_c_REV/APP_POLYLFO.ino | 26 ++++++++++++++++++-------- software/o_c_REV/frames_poly_lfo.cpp | 9 ++++++--- software/o_c_REV/frames_poly_lfo.h | 2 +- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/software/o_c_REV/APP_POLYLFO.ino b/software/o_c_REV/APP_POLYLFO.ino index e9b01c1b..8e91da13 100644 --- a/software/o_c_REV/APP_POLYLFO.ino +++ b/software/o_c_REV/APP_POLYLFO.ino @@ -54,6 +54,7 @@ enum POLYLFO_SETTINGS { POLYLFO_SETTING_C_AM_BY_B, POLYLFO_SETTING_D_AM_BY_C, POLYLFO_SETTING_CV4, + POLYLFO_SETTING_TR4_MULT, POLYLFO_SETTING_LAST }; @@ -140,6 +141,10 @@ public: return values_[POLYLFO_SETTING_CV4]; } + uint8_t tr4_multiplier() const { + return values_[POLYLFO_SETTING_TR4_MULT]; + } + void Init(); void freeze() { @@ -154,17 +159,17 @@ public: return frozen_; } - bool freq_mult() const { + uint8_t freq_mult() const { return freq_mult_; } - void set_freq_mult(bool freq_mult) { + void set_freq_mult(uint8_t freq_mult) { freq_mult_ = freq_mult; } frames::PolyLfo lfo; bool frozen_; - bool freq_mult_; + uint8_t freq_mult_; // ISR update is at 16.666kHz, we don't need it that fast so smooth the values to ~1Khz static constexpr int32_t kSmoothing = 16; @@ -179,7 +184,7 @@ void PolyLfo::Init() { InitDefaults(); lfo.Init(); frozen_= false; - freq_mult_ = false; + freq_mult_ = 0x3; // == x2 / default } const char* const freq_range_names[12] = { @@ -200,6 +205,10 @@ const char* const cv4_destinations[7] = { "cplg", "sprd", " rng", "offs", "a->b", "b->c", "c->d" }; +const char* const tr4_multiplier[6] = { + "/8", "/4", "/2", "x2", "x4", "x8" +}; + SETTINGS_DECLARE(PolyLfo, POLYLFO_SETTING_LAST) { { 64, 0, 255, "C", NULL, settings::STORAGE_TYPE_U8 }, { 0, -128, 127, "F", NULL, settings::STORAGE_TYPE_I16 }, @@ -220,7 +229,8 @@ SETTINGS_DECLARE(PolyLfo, POLYLFO_SETTING_LAST) { { 0, 0, 127, "B AM by A", NULL, settings::STORAGE_TYPE_U8 }, { 0, 0, 127, "C AM by B", NULL, settings::STORAGE_TYPE_U8 }, { 0, 0, 127, "D AM by C", NULL, settings::STORAGE_TYPE_U8 }, - { 0, 0, 6, "CV4 ->", cv4_destinations, settings::STORAGE_TYPE_U8 }, + { 0, 0, 6, "CV4: DEST", cv4_destinations, settings::STORAGE_TYPE_U8 }, + { 3, 0, 5, "TR4: MULT", tr4_multiplier, settings::STORAGE_TYPE_U8 }, }; PolyLfo poly_lfo; @@ -323,8 +333,8 @@ void FASTRUN POLYLFO_isr() { CONSTRAIN(d_am_by_c, 0, 127); poly_lfo.lfo.set_d_am_by_c(d_am_by_c); - // double frequency if TR4 / gate high - bool freq_mult = digitalReadFast(TR4) ? false : true; + // div/multiply frequency if TR4 / gate high + int8_t freq_mult = digitalReadFast(TR4) ? 0xFF : poly_lfo.tr4_multiplier(); poly_lfo.set_freq_mult(freq_mult); if (!freeze && !poly_lfo.frozen()) @@ -368,7 +378,7 @@ void POLYLFO_menu() { graphics.print("(T) Ch A: tap tempo") ; } else { float menu_freq_ = poly_lfo.lfo.get_freq_ch1(); - if (poly_lfo.freq_mult()) + if (poly_lfo.freq_mult() < 0xFF) graphics.drawBitmap8(122, menu::DefaultTitleBar::kTextY, 4, OC::bitmap_indicator_4x8); if (menu_freq_ >= 0.1f) { graphics.printf("(%s) Ch A: %6.2f Hz", PolyLfo::value_attr(poly_lfo_state.left_edit_mode).name, menu_freq_); diff --git a/software/o_c_REV/frames_poly_lfo.cpp b/software/o_c_REV/frames_poly_lfo.cpp index a9fcd132..ce738a9a 100644 --- a/software/o_c_REV/frames_poly_lfo.cpp +++ b/software/o_c_REV/frames_poly_lfo.cpp @@ -130,7 +130,7 @@ uint32_t PolyLfo::FrequencyToPhaseIncrement(int32_t frequency, uint16_t frq_rng) return (a + ((b - a) * (index & 0x1f) >> 5)) << shifts; } -void PolyLfo::Render(int32_t frequency, bool reset_phase, bool tempo_sync, bool freq_mult) { +void PolyLfo::Render(int32_t frequency, bool reset_phase, bool tempo_sync, uint8_t freq_mult) { ++sync_counter_; if (tempo_sync && sync_) { if (sync_counter_ < kSyncCounterMaxTime) { @@ -162,8 +162,11 @@ void PolyLfo::Render(int32_t frequency, bool reset_phase, bool tempo_sync, bool } else { phase_increment_ch1_ = FrequencyToPhaseIncrement(frequency, freq_range_); } - // double F (via TR4) - phase_increment_ch1_ = phase_increment_ch1_ << freq_mult; + + // double F (via TR4) ? ... "/8", "/4", "/2", "x2", "x4", "x8" + if (freq_mult < 0xFF) { + phase_increment_ch1_ = (freq_mult < 0x3) ? (phase_increment_ch1_ >> (0x3 - freq_mult)) : phase_increment_ch1_ << (freq_mult - 0x2); + } phase_[0] += phase_increment_ch1_; PolyLfoFreqMultipliers FreqDivs[] = {POLYLFO_FREQ_MULT_NONE, freq_div_b_, freq_div_c_ , freq_div_d_} ; diff --git a/software/o_c_REV/frames_poly_lfo.h b/software/o_c_REV/frames_poly_lfo.h index 970bfcd9..2925a468 100644 --- a/software/o_c_REV/frames_poly_lfo.h +++ b/software/o_c_REV/frames_poly_lfo.h @@ -133,7 +133,7 @@ class PolyLfo { ~PolyLfo() { } void Init(); - void Render(int32_t frequency, bool reset_phase, bool tempo_sync, bool freq_mult); + void Render(int32_t frequency, bool reset_phase, bool tempo_sync, uint8_t freq_mult); void RenderPreview(uint16_t shape, uint16_t *buffer, size_t size); inline void set_freq_range(uint16_t freq_range) { From 856ce764f1c9d7a72ab2f19115ccf7e720f621bb Mon Sep 17 00:00:00 2001 From: mxmxmx Date: Thu, 29 Jun 2017 06:20:08 +0200 Subject: [PATCH 13/13] [OC] bump to v1.3.2 --- software/o_c_REV/OC_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/software/o_c_REV/OC_version.h b/software/o_c_REV/OC_version.h index 06e19b0d..4b1f9bda 100644 --- a/software/o_c_REV/OC_version.h +++ b/software/o_c_REV/OC_version.h @@ -3,5 +3,5 @@ // // GENERATED FILE, DO NOT EDIT // -#define OC_VERSION "v1.3.1" +#define OC_VERSION "v1.3.2" #endif