Skip to content

Commit

Permalink
Merge pull request #58 from mxmxmx/v1.3.2_POLY_cv4
Browse files Browse the repository at this point in the history
[OC] bump v.1.3.2
  • Loading branch information
mxmxmx committed Jun 29, 2017
2 parents 50ac76e + 856ce76 commit 193b2bf
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 18 deletions.
125 changes: 114 additions & 11 deletions software/o_c_REV/APP_POLYLFO.ino
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ 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_CV4,
POLYLFO_SETTING_TR4_MULT,
POLYLFO_SETTING_LAST
};

Expand All @@ -76,15 +81,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];
}

Expand Down Expand Up @@ -120,6 +125,26 @@ 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];
}

uint8_t cv4_destination() const {
return values_[POLYLFO_SETTING_CV4];
}

uint8_t tr4_multiplier() const {
return values_[POLYLFO_SETTING_TR4_MULT];
}

void Init();

void freeze() {
Expand All @@ -134,22 +159,32 @@ public:
return frozen_;
}

uint8_t freq_mult() const {
return freq_mult_;
}

void set_freq_mult(uint8_t freq_mult) {
freq_mult_ = freq_mult;
}

frames::PolyLfo lfo;
bool frozen_;
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;

SmoothedValue<int32_t, kSmoothing> cv_freq;
SmoothedValue<int32_t, kSmoothing> cv_shape;
SmoothedValue<int32_t, kSmoothing> cv_spread;
SmoothedValue<int32_t, kSmoothing> cv_coupling;
SmoothedValue<int32_t, kSmoothing> cv_mappable;
};

void PolyLfo::Init() {
InitDefaults();
lfo.Init();
frozen_= false;
freq_mult_ = 0x3; // == x2 / default
}

const char* const freq_range_names[12] = {
Expand All @@ -166,6 +201,14 @@ const char* const xor_levels[9] = {
"off", " 1", " 2", " 3", " 4", " 5", " 6", " 7", " 8"
};

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 },
Expand All @@ -183,6 +226,11 @@ 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 },
{ 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;
Expand All @@ -202,7 +250,7 @@ void FASTRUN POLYLFO_isr() {
poly_lfo.cv_freq.push(OC::ADC::value<ADC_CHANNEL_1>());
poly_lfo.cv_shape.push(OC::ADC::value<ADC_CHANNEL_2>());
poly_lfo.cv_spread.push(OC::ADC::value<ADC_CHANNEL_3>());
poly_lfo.cv_coupling.push(OC::ADC::value<ADC_CHANNEL_4>());
poly_lfo.cv_mappable.push(OC::ADC::value<ADC_CHANNEL_4>());

// Range in settings is (0-256] so this gets scaled to (0,65535]
// CV value is 12 bit so also needs scaling
Expand All @@ -220,13 +268,50 @@ 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: -128, 127
shape_spread = poly_lfo.cv_mappable.value() << 4;
break;
case 2: // attenuation: 0, 230
attenuation = poly_lfo.cv_mappable.value() << 4;
break;
case 3: // offset: -128, 127
offset = poly_lfo.cv_mappable.value() << 4;
break;
case 4: // "a->b", 0-127
b_am_by_a = (poly_lfo.cv_mappable.value() + 15) >> 5;
break;
case 5: // "b->c", 0-127
c_am_by_b = (poly_lfo.cv_mappable.value() + 15) >> 5;
break;
case 6: // "c->d", 0-127
d_am_by_c = (poly_lfo.cv_mappable.value() + 15) >> 5;
break;
case 0: // coupling, -128, 127
default:
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());
Expand All @@ -236,8 +321,24 @@ 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());

b_am_by_a += poly_lfo.get_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();
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();
CONSTRAIN(d_am_by_c, 0, 127);
poly_lfo.lfo.set_d_am_by_c(d_am_by_c);

// 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())
poly_lfo.lfo.Render(freq, reset_phase, tempo_sync);
poly_lfo.lfo.Render(freq, reset_phase, tempo_sync, freq_mult);

OC::DAC::set<DAC_CHANNEL_A>(poly_lfo.lfo.dac_code(0));
OC::DAC::set<DAC_CHANNEL_B>(poly_lfo.lfo.dac_code(1));
Expand Down Expand Up @@ -276,7 +377,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() < 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_);
} else {
Expand Down
1 change: 1 addition & 0 deletions software/o_c_REV/APP_QQ.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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<const char*>(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);
Expand Down
2 changes: 1 addition & 1 deletion software/o_c_REV/OC_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
//
// GENERATED FILE, DO NOT EDIT
//
#define OC_VERSION "v1.3.1"
#define OC_VERSION "v1.3.2"
#endif
22 changes: 17 additions & 5 deletions software/o_c_REV/frames_poly_lfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -127,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, uint8_t freq_mult) {
++sync_counter_;
if (tempo_sync && sync_) {
if (sync_counter_ < kSyncCounterMaxTime) {
Expand Down Expand Up @@ -159,13 +162,19 @@ 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_ } ;

// 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_} ;
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]]) ;
}
}

Expand Down Expand Up @@ -201,6 +210,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];
Expand All @@ -221,8 +231,10 @@ 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);
}
// 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_ ;
// dac_code_[i] += offset_ ;
wavetable_index += shape_spread_;
}
}
Expand Down
17 changes: 16 additions & 1 deletion software/o_c_REV/frames_poly_lfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, uint8_t freq_mult);
void RenderPreview(uint16_t shape, uint16_t *buffer, size_t size);

inline void set_freq_range(uint16_t freq_range) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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];
Expand Down

0 comments on commit 193b2bf

Please sign in to comment.