diff --git a/software/o_c_REV/APP_DQ.ino b/software/o_c_REV/APP_DQ.ino index 08deac0d..1371635a 100644 --- a/software/o_c_REV/APP_DQ.ino +++ b/software/o_c_REV/APP_DQ.ino @@ -365,7 +365,7 @@ public: for (int i = 0; i < NUM_SCALE_SLOTS; i++) { last_scale_[i] = -1; - last_mask_[i] = 0; + last_mask_[i] = 0xFFFF; } aux_sample_ = 0; @@ -434,20 +434,22 @@ public: update_asr_ = true; aux_sample_ = ON; } - + + if (scale_reset_) { + // manual change? + scale_reset_ = false; + scale_sequence_cnt_ = 0x0; + scale_advance_state_ = 0x1; + active_scale_slot_ = get_scale_select(); + prev_scale_slot_ = display_scale_slot_ = active_scale_slot_; + } + if (get_scale_seq_mode()) { // to do, don't hardcode .. uint8_t _advance_trig = (dac_channel == DAC_CHANNEL_A) ? digitalReadFast(TR2) : digitalReadFast(TR4); if (_advance_trig < scale_advance_state_) scale_advance_ = true; scale_advance_state_ = _advance_trig; - - if (scale_reset_) { - // manual change? - scale_reset_ = false; - active_scale_slot_ = get_scale_select(); - prev_scale_slot_ = display_scale_slot_ = active_scale_slot_; - } } else if (prev_scale_slot_ != get_scale_select()) { active_scale_slot_ = get_scale_select(); @@ -504,6 +506,7 @@ public: // if scale changes, we have to update the root and transpose values, too; mask gets updated in update_scale root = get_root(display_scale_slot_); transpose = get_transpose(display_scale_slot_); + schedule_scale_update_ = true; break; case DQ_DEST_ROOT: root += (OC::ADC::value(static_cast(channel_id)) + 127) >> 8; @@ -519,7 +522,12 @@ public: break; default: break; - } // end switch + } // end switch + + if (schedule_scale_update_) { + force_update_ = true; + schedule_scale_update_ = false; + } } // -> triggered update // constrain values: @@ -658,7 +666,7 @@ public: // update scale? if (schedule_scale_update_ && _continuous_update) { - update_scale(false, display_scale_slot_, schedule_mask_rotate_); + update_scale(true, display_scale_slot_, schedule_mask_rotate_); schedule_scale_update_ = false; } @@ -1046,7 +1054,7 @@ private: force_update_ = false; const int scale = get_scale(scale_select); uint16_t mask = get_mask(scale_select); - + if (mask_rotate) mask = OC::ScaleEditor::RotateMask(mask, OC::Scales::GetScale(scale).num_notes, mask_rotate); @@ -1389,6 +1397,7 @@ void DQ_handleEncoderEvent(const UI::Event &event) { dq_state.cursor.AdjustEnd(selected.num_enabled_settings() - 1); break; case DQ_CHANNEL_SETTING_SCALE_SEQ: + case DQ_CHANNEL_SETTING_SEQ_MODE: selected.update_enabled_settings(); dq_state.cursor.AdjustEnd(selected.num_enabled_settings() - 1); selected.reset_scale(); diff --git a/software/o_c_REV/APP_ENVGEN.ino b/software/o_c_REV/APP_ENVGEN.ino index f8ed3695..0647aec9 100644 --- a/software/o_c_REV/APP_ENVGEN.ino +++ b/software/o_c_REV/APP_ENVGEN.ino @@ -446,7 +446,11 @@ public: CONSTRAIN(s[CV_MAPPING_EUCLIDEAN_FILL], 0, 32); CONSTRAIN(s[CV_MAPPING_EUCLIDEAN_OFFSET], 0, 32); CONSTRAIN(s[CV_MAPPING_DELAY_MSEC], 0, 65535); + #ifdef VOR + CONSTRAIN(s[CV_MAPPING_AMPLITUDE], 0, 62850); + #else CONSTRAIN(s[CV_MAPPING_AMPLITUDE], 0, 65535); + #endif CONSTRAIN(s[CV_MAPPING_MAX_LOOPS], 0, 65535); EnvelopeType type = get_type(); diff --git a/software/o_c_REV/APP_QQ.ino b/software/o_c_REV/APP_QQ.ino index 85fa1ab9..fa115ae1 100644 --- a/software/o_c_REV/APP_QQ.ino +++ b/software/o_c_REV/APP_QQ.ino @@ -953,7 +953,8 @@ public: *settings++ = CHANNEL_SETTING_TURING_RANGE; *settings++ = CHANNEL_SETTING_TURING_PROB; if (OC::Scales::SCALE_NONE != get_scale(DUMMY)) - *settings++ = CHANNEL_SETTING_TURING_RANGE_CV_SOURCE; + *settings++ = CHANNEL_SETTING_TURING_MODULUS_CV_SOURCE; + *settings++ = CHANNEL_SETTING_TURING_RANGE_CV_SOURCE; *settings++ = CHANNEL_SETTING_TURING_PROB_CV_SOURCE; break; case CHANNEL_SOURCE_LOGISTIC_MAP: @@ -1565,4 +1566,3 @@ void QQ_debug() { } } #endif // QQ_DEBUG - diff --git a/software/o_c_REV/APP_REFS.ino b/software/o_c_REV/APP_REFS.ino index e800eeed..8366b202 100644 --- a/software/o_c_REV/APP_REFS.ino +++ b/software/o_c_REV/APP_REFS.ino @@ -596,6 +596,8 @@ const char* const error[] = { SETTINGS_DECLARE(ReferenceChannel, REF_SETTING_LAST) { #ifdef BUCHLA_4U { 0, 0, 9, "Octave", nullptr, settings::STORAGE_TYPE_I8 }, + #elif defined(VOR) + {0, 0, 10, "Octave", nullptr, settings::STORAGE_TYPE_I8 }, #else { 0, -3, 6, "Octave", nullptr, settings::STORAGE_TYPE_I8 }, #endif diff --git a/software/o_c_REV/OC_DAC.cpp b/software/o_c_REV/OC_DAC.cpp index a3029f34..c1e0b8db 100644 --- a/software/o_c_REV/OC_DAC.cpp +++ b/software/o_c_REV/OC_DAC.cpp @@ -54,13 +54,21 @@ void DAC::Init(CalibrationData *calibration_data) { // set up DAC pins OC::pinMode(DAC_CS, OUTPUT); - OC::pinMode(DAC_RST,OUTPUT); + #ifndef VOR + OC::pinMode(DAC_RST,OUTPUT); #ifdef DAC8564 // A0 = 0, A1 = 0 digitalWrite(DAC_RST, LOW); #else // default to DAC8565 - pull RST high digitalWrite(DAC_RST, HIGH); #endif + #endif + +#ifdef VOR + // set Vbias, using onboard DAC: + init_Vbias(); + delay(10); +#endif history_tail_ = 0; memset(history_, 0, sizeof(uint16_t) * kHistoryDepth * DAC_CHANNEL_LAST); @@ -185,6 +193,7 @@ void DAC::restore_scaling(uint32_t scaling) { set_scaling(_scaling, i); } } +/*static*/ uint32_t DAC::store_scaling() { uint32_t _scaling = 0; @@ -193,6 +202,17 @@ uint32_t DAC::store_scaling() { _scaling |= (DAC_scaling[i] << (i * 8)); return _scaling; } +/*static*/ +void DAC::init_Vbias() { + /* using MK20 DAC0 for Vbias*/ + VREF_TRM = 0x60; VREF_SC = 0xE1; // enable 1v2 reference + SIM_SCGC2 |= SIM_SCGC2_DAC0; // DAC clock + DAC0_C0 = DAC_C0_DACEN; // enable module + use internal 1v2 reference +} +/*static*/ +void DAC::set_Vbias(uint32_t data) { + *(volatile int16_t *)&(DAC0_DAT0L) = data; +} /*static*/ DAC::CalibrationData *DAC::calibration_data_ = nullptr; /*static*/ diff --git a/software/o_c_REV/OC_DAC.h b/software/o_c_REV/OC_DAC.h index 219b1a8e..a9038b6c 100644 --- a/software/o_c_REV/OC_DAC.h +++ b/software/o_c_REV/OC_DAC.h @@ -41,6 +41,11 @@ class DAC { #ifdef BUCHLA_4U static constexpr int kOctaveZero = 0; + #elif defined(VOR) + static constexpr int kOctaveZero = 0; + static constexpr int VBiasUnipolar = 3900; // onboard DAC @ Vref 1.2V (internal), 1.75x gain + static constexpr int VBiasBipolar = 2000; // onboard DAC @ Vref 1.2V (internal), 1.75x gain + static constexpr int VBiasAsymmetric = 2760; // onboard DAC @ Vref 1.2V (internal), 1.75x gain #else static constexpr int kOctaveZero = 3; #endif @@ -62,6 +67,8 @@ class DAC { static void restore_scaling(uint32_t scaling); static uint8_t get_voltage_scaling(uint8_t channel_id); static uint32_t store_scaling(); + static void set_Vbias(uint32_t data); + static void init_Vbias(); static void set_all(uint32_t value) { for (int i = DAC_CHANNEL_A; i < DAC_CHANNEL_LAST; ++i) diff --git a/software/o_c_REV/OC_apps.ino b/software/o_c_REV/OC_apps.ino index 060fd954..8388e98e 100644 --- a/software/o_c_REV/OC_apps.ino +++ b/software/o_c_REV/OC_apps.ino @@ -207,6 +207,11 @@ void restore_app_data() { } restored_bytes += chunk->length; data += chunk->length; + +#ifdef VOR + VBiasManager *vbias_m = vbias_m->get(); + vbias_m->SetStateForApp(apps::index_of(global_settings.current_app_id)); +#endif } SERIAL_PRINTLN("App data restored: %u, expected %u", restored_bytes, app_settings.used); @@ -407,6 +412,10 @@ void Ui::AppSettings() { // Restore state apps::current_app->HandleAppEvent(APP_EVENT_RESUME); CORE::app_isr_enabled = true; +#ifdef VOR + VBiasManager *vbias_m = vbias_m->get(); + vbias_m->SetStateForApp(apps::index_of(global_settings.current_app_id)); +#endif } bool Ui::ConfirmReset() { diff --git a/software/o_c_REV/OC_autotuner.h b/software/o_c_REV/OC_autotuner.h index dd33d780..2b8c526b 100644 --- a/software/o_c_REV/OC_autotuner.h +++ b/software/o_c_REV/OC_autotuner.h @@ -12,6 +12,10 @@ const char* const AT_steps[] = { const char* const AT_steps[] = { "0.0V", "1.0V", "2.0V", "3.0V", "4.0V", "5.0V", "6.0V", "7.0V", "8.0V", "9.0V", " " }; +#elif defined(VOR) +const char* const AT_steps[] = { + "0.0V", "1.0V", "2.0V", "3.0V", "4.0V", "5.0V", "6.0V", "7.0V", "8.0V", "9.0V", "10.0V", " " +}; #else const char* const AT_steps[] = { "-3V", "-2V", "-1V", " 0V", "+1V", "+2V", "+3V", "+4V", "+5V", "+6V", " " diff --git a/software/o_c_REV/OC_calibration.h b/software/o_c_REV/OC_calibration.h index fa61a22b..5ae0fd73 100644 --- a/software/o_c_REV/OC_calibration.h +++ b/software/o_c_REV/OC_calibration.h @@ -2,8 +2,9 @@ #define OC_CALIBRATION_H_ #include "OC_ADC.h" -#include "OC_config.h" #include "OC_DAC.h" +#include "OC_config.h" +#include "OC_options.h" #include "util/util_pagestorage.h" #include "util/EEPROMStorage.h" @@ -44,7 +45,12 @@ struct CalibrationData { uint32_t flags; uint8_t screensaver_timeout; // 0: default, else seconds uint8_t reserved0[3]; - uint32_t reserved1; + #ifdef VOR + /* less complicated this way than adding it to DAC::CalibrationData... */ + uint32_t v_bias; // upper 2 bytes: asymmetric; lower 2 bytes: bipolar. + #else + uint32_t reserved1; + #endif EncoderConfig encoder_config() const { return static_cast(flags & CALIBRATION_FLAG_ENCODER_MASK); diff --git a/software/o_c_REV/OC_calibration.ino b/software/o_c_REV/OC_calibration.ino index ad7a8ad3..b76cd44d 100644 --- a/software/o_c_REV/OC_calibration.ino +++ b/software/o_c_REV/OC_calibration.ino @@ -10,7 +10,7 @@ using OC::DAC; -#ifdef BUCHLA_cOC +#if defined(BUCHLA_cOC) || defined(VOR) static constexpr uint16_t DAC_OFFSET = 0; // DAC offset, initial approx., ish (Easel card) #else static constexpr uint16_t DAC_OFFSET = 4890; // DAC offset, initial approx., ish --> -3.5V to 6V @@ -38,6 +38,11 @@ const OC::CalibrationData kCalibrationDefaults = { {197, 6634, 13083, 19517, 25966, 32417, 38850, 45301, 51733, 58180, 64400}, {197, 6634, 13083, 19517, 25966, 32417, 38850, 45301, 51733, 58180, 64400}, {197, 6634, 13083, 19517, 25966, 32417, 38850, 45301, 51733, 58180, 64400} + #elif defined(VOR) + {880, 7190, 13510, 19830, 26300, 32460, 38770, 45090, 51410, 57720, 64040}, + {880, 7190, 13510, 19830, 26300, 32460, 38770, 45090, 51410, 57720, 64040}, + {880, 7190, 13510, 19830, 26300, 32460, 38770, 45090, 51410, 57720, 64040}, + {880, 7190, 13510, 19830, 26300, 32460, 38770, 45090, 51410, 57720, 64040} #else {0, 6553, 13107, 19661, 26214, 32768, 39321, 45875, 52428, 58981, 65535}, {0, 6553, 13107, 19661, 26214, 32768, 39321, 45875, 52428, 58981, 65535}, @@ -54,8 +59,13 @@ const OC::CalibrationData kCalibrationDefaults = { // display_offset SH1106_128x64_Driver::kDefaultOffset, OC_CALIBRATION_DEFAULT_FLAGS, - SCREENSAVER_TIMEOUT_S, { 0, 0, 0 }, - 0 // reserved + SCREENSAVER_TIMEOUT_S, + { 0, 0, 0 }, // reserved0 + #ifdef VOR + DAC::VBiasBipolar | (DAC::VBiasAsymmetric << 16) // default v_bias values + #else + 0 // reserved1 + #endif }; void calibration_reset() { @@ -107,12 +117,20 @@ void calibration_save() { enum CALIBRATION_STEP { HELLO, CENTER_DISPLAY, - + + #ifdef VOR + DAC_A_VOLT_3m, DAC_A_VOLT_2m, DAC_A_VOLT_1m, DAC_A_VOLT_0, DAC_A_VOLT_1, DAC_A_VOLT_2, DAC_A_VOLT_3, DAC_A_VOLT_4, DAC_A_VOLT_5, DAC_A_VOLT_6, DAC_A_VOLT_7, + DAC_B_VOLT_3m, DAC_B_VOLT_2m, DAC_B_VOLT_1m, DAC_B_VOLT_0, DAC_B_VOLT_1, DAC_B_VOLT_2, DAC_B_VOLT_3, DAC_B_VOLT_4, DAC_B_VOLT_5, DAC_B_VOLT_6, DAC_B_VOLT_7, + DAC_C_VOLT_3m, DAC_C_VOLT_2m, DAC_C_VOLT_1m, DAC_C_VOLT_0, DAC_C_VOLT_1, DAC_C_VOLT_2, DAC_C_VOLT_3, DAC_C_VOLT_4, DAC_C_VOLT_5, DAC_C_VOLT_6, DAC_C_VOLT_7, + DAC_D_VOLT_3m, DAC_D_VOLT_2m, DAC_D_VOLT_1m, DAC_D_VOLT_0, DAC_D_VOLT_1, DAC_D_VOLT_2, DAC_D_VOLT_3, DAC_D_VOLT_4, DAC_D_VOLT_5, DAC_D_VOLT_6, DAC_D_VOLT_7, + V_BIAS_BIPOLAR, V_BIAS_ASYMMETRIC, + #else DAC_A_VOLT_3m, DAC_A_VOLT_2m, DAC_A_VOLT_1m, DAC_A_VOLT_0, DAC_A_VOLT_1, DAC_A_VOLT_2, DAC_A_VOLT_3, DAC_A_VOLT_4, DAC_A_VOLT_5, DAC_A_VOLT_6, DAC_B_VOLT_3m, DAC_B_VOLT_2m, DAC_B_VOLT_1m, DAC_B_VOLT_0, DAC_B_VOLT_1, DAC_B_VOLT_2, DAC_B_VOLT_3, DAC_B_VOLT_4, DAC_B_VOLT_5, DAC_B_VOLT_6, DAC_C_VOLT_3m, DAC_C_VOLT_2m, DAC_C_VOLT_1m, DAC_C_VOLT_0, DAC_C_VOLT_1, DAC_C_VOLT_2, DAC_C_VOLT_3, DAC_C_VOLT_4, DAC_C_VOLT_5, DAC_C_VOLT_6, DAC_D_VOLT_3m, DAC_D_VOLT_2m, DAC_D_VOLT_1m, DAC_D_VOLT_0, DAC_D_VOLT_1, DAC_D_VOLT_2, DAC_D_VOLT_3, DAC_D_VOLT_4, DAC_D_VOLT_5, DAC_D_VOLT_6, - + #endif + CV_OFFSET_0, CV_OFFSET_1, CV_OFFSET_2, CV_OFFSET_3, ADC_PITCH_C2, ADC_PITCH_C4, CALIBRATION_SCREENSAVER_TIMEOUT, @@ -124,6 +142,10 @@ enum CALIBRATION_STEP { enum CALIBRATION_TYPE { CALIBRATE_NONE, CALIBRATE_OCTAVE, + #ifdef VOR + CALIBRATE_VBIAS_BIPOLAR, + CALIBRATE_VBIAS_ASYMMETRIC, + #endif CALIBRATE_ADC_OFFSET, CALIBRATE_ADC_1V, CALIBRATE_ADC_3V, @@ -149,7 +171,8 @@ DAC_CHANNEL step_to_channel(int step) { if (step >= DAC_D_VOLT_3m) return DAC_CHANNEL_D; if (step >= DAC_C_VOLT_3m) return DAC_CHANNEL_C; if (step >= DAC_B_VOLT_3m) return DAC_CHANNEL_B; - /*if (step >= DAC_B_VOLT_3m)*/ return DAC_CHANNEL_A; + /*if (step >= DAC_B_VOLT_3m)*/ + return DAC_CHANNEL_A; } struct CalibrationState { @@ -161,7 +184,7 @@ struct CalibrationState { uint16_t adc_1v; uint16_t adc_3v; - + bool used_defaults; }; @@ -222,7 +245,7 @@ const CalibrationStep calibration_steps[CALIBRATION_STEP_LAST] = { { DAC_D_VOLT_4, "DAC D 8.4 volts", "-> 8.400V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 7, nullptr, 0, DAC::MAX_VALUE }, { DAC_D_VOLT_5, "DAC D 9.6 volts", "-> 9.600V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 8, nullptr, 0, DAC::MAX_VALUE }, { DAC_D_VOLT_6, "DAC D 10.8 volts", "-> 10.800V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 9, nullptr, 0, DAC::MAX_VALUE }, - #elif defined(IO_10V) + #elif defined(IO_10V) && !defined(VOR) { DAC_A_VOLT_3m, "DAC A 0.0 volts", "-> 0.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 0, nullptr, 0, DAC::MAX_VALUE }, { DAC_A_VOLT_2m, "DAC A 1.0 volts", "-> 1.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 1, nullptr, 0, DAC::MAX_VALUE }, { DAC_A_VOLT_1m, "DAC A 2.0 volts", "-> 2.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 2, nullptr, 0, DAC::MAX_VALUE }, @@ -266,6 +289,54 @@ const CalibrationStep calibration_steps[CALIBRATION_STEP_LAST] = { { DAC_D_VOLT_4, "DAC D 7.0 volts", "-> 7.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 7, nullptr, 0, DAC::MAX_VALUE }, { DAC_D_VOLT_5, "DAC D 8.0 volts", "-> 8.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 8, nullptr, 0, DAC::MAX_VALUE }, { DAC_D_VOLT_6, "DAC D 9.0 volts", "-> 9.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 9, nullptr, 0, DAC::MAX_VALUE }, + #elif defined(VOR) + { DAC_A_VOLT_3m, "DAC A 0.0 volts", "-> 0.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 0, nullptr, 0, DAC::MAX_VALUE }, + { DAC_A_VOLT_2m, "DAC A 1.0 volts", "-> 1.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 1, nullptr, 0, DAC::MAX_VALUE }, + { DAC_A_VOLT_1m, "DAC A 2.0 volts", "-> 2.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 2, nullptr, 0, DAC::MAX_VALUE }, + { DAC_A_VOLT_0, "DAC A 3.0 volts", "-> 3.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 3, nullptr, 0, DAC::MAX_VALUE }, + { DAC_A_VOLT_1, "DAC A 4.0 volts", "-> 4.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 4, nullptr, 0, DAC::MAX_VALUE }, + { DAC_A_VOLT_2, "DAC A 5.0 volts", "-> 5.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 5, nullptr, 0, DAC::MAX_VALUE }, + { DAC_A_VOLT_3, "DAC A 6.0 volts", "-> 6.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 6, nullptr, 0, DAC::MAX_VALUE }, + { DAC_A_VOLT_4, "DAC A 7.0 volts", "-> 7.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 7, nullptr, 0, DAC::MAX_VALUE }, + { DAC_A_VOLT_5, "DAC A 8.0 volts", "-> 8.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 8, nullptr, 0, DAC::MAX_VALUE }, + { DAC_A_VOLT_6, "DAC A 9.0 volts", "-> 9.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 9, nullptr, 0, DAC::MAX_VALUE }, + { DAC_A_VOLT_7, "DAC A 10.0 volts", "-> 10.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 10, nullptr, 0, DAC::MAX_VALUE }, + + { DAC_B_VOLT_3m, "DAC B 0.0 volts", "-> 0.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 0, nullptr, 0, DAC::MAX_VALUE }, + { DAC_B_VOLT_2m, "DAC B 1.0 volts", "-> 1.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 1, nullptr, 0, DAC::MAX_VALUE }, + { DAC_B_VOLT_1m, "DAC B 2.0 volts", "-> 2.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 2, nullptr, 0, DAC::MAX_VALUE }, + { DAC_B_VOLT_0, "DAC B 3.0 volts", "-> 3.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 3, nullptr, 0, DAC::MAX_VALUE }, + { DAC_B_VOLT_1, "DAC B 4.0 volts", "-> 4.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 4, nullptr, 0, DAC::MAX_VALUE }, + { DAC_B_VOLT_2, "DAC B 5.0 volts", "-> 5.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 5, nullptr, 0, DAC::MAX_VALUE }, + { DAC_B_VOLT_3, "DAC B 6.0 volts", "-> 6.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 6, nullptr, 0, DAC::MAX_VALUE }, + { DAC_B_VOLT_4, "DAC B 7.0 volts", "-> 7.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 7, nullptr, 0, DAC::MAX_VALUE }, + { DAC_B_VOLT_5, "DAC B 8.0 volts", "-> 8.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 8, nullptr, 0, DAC::MAX_VALUE }, + { DAC_B_VOLT_6, "DAC B 9.0 volts", "-> 9.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 9, nullptr, 0, DAC::MAX_VALUE }, + { DAC_B_VOLT_7, "DAC B 10.0 volts", "-> 10.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 10, nullptr, 0, DAC::MAX_VALUE }, + + { DAC_C_VOLT_3m, "DAC C 0.0 volts", "-> 0.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 0, nullptr, 0, DAC::MAX_VALUE }, + { DAC_C_VOLT_2m, "DAC C 1.0 volts", "-> 1.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 1, nullptr, 0, DAC::MAX_VALUE }, + { DAC_C_VOLT_1m, "DAC C 2.0 volts", "-> 2.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 2, nullptr, 0, DAC::MAX_VALUE }, + { DAC_C_VOLT_0, "DAC C 3.0 volts", "-> 3.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 3, nullptr, 0, DAC::MAX_VALUE }, + { DAC_C_VOLT_1, "DAC C 4.0 volts", "-> 4.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 4, nullptr, 0, DAC::MAX_VALUE }, + { DAC_C_VOLT_2, "DAC C 5.0 volts", "-> 5.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 5, nullptr, 0, DAC::MAX_VALUE }, + { DAC_C_VOLT_3, "DAC C 6.0 volts", "-> 6.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 6, nullptr, 0, DAC::MAX_VALUE }, + { DAC_C_VOLT_4, "DAC C 7.0 volts", "-> 7.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 7, nullptr, 0, DAC::MAX_VALUE }, + { DAC_C_VOLT_5, "DAC C 8.0 volts", "-> 8.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 8, nullptr, 0, DAC::MAX_VALUE }, + { DAC_C_VOLT_6, "DAC C 9.0 volts", "-> 9.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 9, nullptr, 0, DAC::MAX_VALUE }, + { DAC_C_VOLT_7, "DAC C 10.0 volts", "-> 10.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 10, nullptr, 0, DAC::MAX_VALUE }, + + { DAC_D_VOLT_3m, "DAC D 0.0 volts", "-> 0.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 0, nullptr, 0, DAC::MAX_VALUE }, + { DAC_D_VOLT_2m, "DAC D 1.0 volts", "-> 1.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 1, nullptr, 0, DAC::MAX_VALUE }, + { DAC_D_VOLT_1m, "DAC D 2.0 volts", "-> 2.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 2, nullptr, 0, DAC::MAX_VALUE }, + { DAC_D_VOLT_0, "DAC D 3.0 volts", "-> 3.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 3, nullptr, 0, DAC::MAX_VALUE }, + { DAC_D_VOLT_1, "DAC D 4.0 volts", "-> 4.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 4, nullptr, 0, DAC::MAX_VALUE }, + { DAC_D_VOLT_2, "DAC D 5.0 volts", "-> 5.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 5, nullptr, 0, DAC::MAX_VALUE }, + { DAC_D_VOLT_3, "DAC D 6.0 volts", "-> 6.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 6, nullptr, 0, DAC::MAX_VALUE }, + { DAC_D_VOLT_4, "DAC D 7.0 volts", "-> 7.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 7, nullptr, 0, DAC::MAX_VALUE }, + { DAC_D_VOLT_5, "DAC D 8.0 volts", "-> 8.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 8, nullptr, 0, DAC::MAX_VALUE }, + { DAC_D_VOLT_6, "DAC D 9.0 volts", "-> 9.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 9, nullptr, 0, DAC::MAX_VALUE }, + { DAC_D_VOLT_7, "DAC D 10.0 volts", "-> 10.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 10, nullptr, 0, DAC::MAX_VALUE }, #else { DAC_A_VOLT_3m, "DAC A -3 volts", "-> -3.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, -3, nullptr, 0, DAC::MAX_VALUE }, { DAC_A_VOLT_2m, "DAC A -2 volts", "-> -2.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, -2, nullptr, 0, DAC::MAX_VALUE }, @@ -311,6 +382,11 @@ const CalibrationStep calibration_steps[CALIBRATION_STEP_LAST] = { { DAC_D_VOLT_5, "DAC D 5 volts", "-> 5.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 5, nullptr, 0, DAC::MAX_VALUE }, { DAC_D_VOLT_6, "DAC D 6 volts", "-> 6.000V ", default_help_r, default_footer, CALIBRATE_OCTAVE, 6, nullptr, 0, DAC::MAX_VALUE }, #endif + + #ifdef VOR + { V_BIAS_BIPOLAR, "0.000V: bipolar", "--> 0.000V", default_help_r, default_footer, CALIBRATE_VBIAS_BIPOLAR, 0, nullptr, 0, 4095 }, + { V_BIAS_ASYMMETRIC, "0.000V: asym.", "--> 0.000V", default_help_r, default_footer, CALIBRATE_VBIAS_ASYMMETRIC, 0, nullptr, 0, 4095 }, + #endif { CV_OFFSET_0, "ADC CV1", "ADC value at 0V", default_help_r, default_footer, CALIBRATE_ADC_OFFSET, ADC_CHANNEL_1, nullptr, 0, 4095 }, { CV_OFFSET_1, "ADC CV2", "ADC value at 0V", default_help_r, default_footer, CALIBRATE_ADC_OFFSET, ADC_CHANNEL_2, nullptr, 0, 4095 }, @@ -441,13 +517,23 @@ void OC::Ui::Calibrate() { calibration_state.encoder_value = OC::calibration_data.dac.calibrated_octaves[step_to_channel(next_step->step)][next_step->index + DAC::kOctaveZero]; break; + + #ifdef VOR + case CALIBRATE_VBIAS_BIPOLAR: + calibration_state.encoder_value = (0xFFFF & OC::calibration_data.v_bias); // bipolar = lower 2 bytes + break; + case CALIBRATE_VBIAS_ASYMMETRIC: + calibration_state.encoder_value = (OC::calibration_data.v_bias >> 16); // asymmetric = upper 2 bytes + break; + #endif + case CALIBRATE_ADC_OFFSET: calibration_state.encoder_value = OC::calibration_data.adc.offset[next_step->index]; break; case CALIBRATE_DISPLAY: calibration_state.encoder_value = OC::calibration_data.display_offset; break; - + case CALIBRATE_ADC_1V: case CALIBRATE_ADC_3V: SERIAL_PRINTLN("offset=%d", OC::calibration_data.adc.offset[ADC_CHANNEL_1]); @@ -502,6 +588,10 @@ void calibration_draw(const CalibrationState &state) { switch (step->calibration_type) { case CALIBRATE_OCTAVE: case CALIBRATE_SCREENSAVER: + #ifdef VOR + case CALIBRATE_VBIAS_BIPOLAR: + case CALIBRATE_VBIAS_ASYMMETRIC: + #endif graphics.print(step->message); graphics.setPrintPos(kValueX, y + 2); graphics.print((int)state.encoder_value, 5); @@ -594,10 +684,32 @@ void calibration_update(CalibrationState &state) { OC::calibration_data.dac.calibrated_octaves[step_to_channel(step->step)][step->index + DAC::kOctaveZero] = state.encoder_value; DAC::set_all_octave(step->index); + #ifdef VOR + /* set 0V @ unipolar range */ + DAC::set_Vbias(DAC::VBiasUnipolar); + #endif + break; + #ifdef VOR + case CALIBRATE_VBIAS_BIPOLAR: + /* set 0V @ bipolar range */ + DAC::set_all_octave(5); + OC::calibration_data.v_bias = (OC::calibration_data.v_bias & 0xFFFF0000) | state.encoder_value; + DAC::set_Vbias(0xFFFF & OC::calibration_data.v_bias); break; + case CALIBRATE_VBIAS_ASYMMETRIC: + /* set 0V @ asym. range */ + DAC::set_all_octave(3); + OC::calibration_data.v_bias = (OC::calibration_data.v_bias & 0xFFFF) | (state.encoder_value << 16); + DAC::set_Vbias(OC::calibration_data.v_bias >> 16); + break; + #endif case CALIBRATE_ADC_OFFSET: OC::calibration_data.adc.offset[step->index] = state.encoder_value; DAC::set_all_octave(0); + #ifdef VOR + /* set 0V @ unipolar range */ + DAC::set_Vbias(DAC::VBiasUnipolar); + #endif break; case CALIBRATE_ADC_1V: DAC::set_all_octave(1); @@ -626,42 +738,4 @@ uint32_t adc_average() { OC::ADC::smoothed_raw_value(ADC_CHANNEL_3) + OC::ADC::smoothed_raw_value(ADC_CHANNEL_4); } -#ifdef CALIBRATION_LOAD_LEGACY -/* read settings from original O&C */ -void calibration_read_old() { - - delay(1000); - uint8_t byte0, byte1, adr; - - adr = 0; - SERIAL_PRINTLN("Loading original O&C calibration from eeprom:"); - - for (int i = 0; i < OCTAVES; i++) { - - byte0 = EEPROM.read(adr); - adr++; - byte1 = EEPROM.read(adr); - adr++; - OC::calibration_data.dac.octaves[i] = (uint16_t)(byte0 << 8) + byte1; - SERIAL_PRINTLN(" OCTAVE %2d: %u", i, OC::calibration_data.dac.octaves[i]); - } - - uint16_t _offset[ADC_CHANNEL_LAST]; - - for (int i = 0; i < ADC_CHANNEL_LAST; i++) { - - byte0 = EEPROM.read(adr); - adr++; - byte1 = EEPROM.read(adr); - adr++; - _offset[i] = (uint16_t)(byte0 << 8) + byte1; - SERIAL_PRINTLN("ADC %d: %u", i, _offset[i]); - } - - OC::calibration_data.adc.offset[ADC_CHANNEL_1] = _offset[0]; - OC::calibration_data.adc.offset[ADC_CHANNEL_2] = _offset[1]; - OC::calibration_data.adc.offset[ADC_CHANNEL_3] = _offset[2]; - OC::calibration_data.adc.offset[ADC_CHANNEL_4] = _offset[3]; - SERIAL_PRINTLN("......"); -} -#endif +// end diff --git a/software/o_c_REV/OC_gpio.h b/software/o_c_REV/OC_gpio.h index 5c6b25f9..c9e14446 100644 --- a/software/o_c_REV/OC_gpio.h +++ b/software/o_c_REV/OC_gpio.h @@ -39,9 +39,14 @@ #define OLED_CS_ACTIVE LOW #define OLED_CS_INACTIVE HIGH -#define DAC_RST 9 #define DAC_CS 10 +#ifdef VOR + #define but_mid 9 +#else + #define DAC_RST 9 +#endif + // NOTE: encoder pins R1/R2 changed for rev >= 2c #ifdef FLIP_180 #define encL1 16 diff --git a/software/o_c_REV/OC_options.h b/software/o_c_REV/OC_options.h index 10fc13d6..bc884293 100644 --- a/software/o_c_REV/OC_options.h +++ b/software/o_c_REV/OC_options.h @@ -7,27 +7,39 @@ #ifndef OC_OPTIONS_H_ #define OC_OPTIONS_H_ -/* ------------ uncomment for Buchla/non-octaval/quartertone support: ------------------------------- */ +/* ------------ uncomment for use with Plum Audio VOR anabled versions (OCP, 1uO_c v2, 4Robots) --------------------------------------------------------- */ +//#define VOR +/* ------------ uncomment for use with Plum Audio 1uO_c 4Robots (To use Up button long press to change VOR instead activate screensaver) ---------------- */ +//#define VOR_NO_RANGE_BUTTON + +/* ------------ uncomment for Buchla/non-octaval/quartertone support: ----------------------------------------------------------------------------------- */ //#define BUCHLA_SUPPORT -/* ------------ uncomment for use with Northernlight cOC program card: ------------------------------ */ +/* ------------ uncomment for use with Northernlight cOC program card: ---------------------------------------------------------------------------------- */ //#define BUCHLA_cOC -/* ------------ uncomment for use with Northernlight 4U / cOC : ------------------------------------- */ +/* ------------ uncomment for use with Northernlight 4U / cOC : ----------------------------------------------------------------------------------------- */ //#define BUCHLA_4U -/* ------------ uncomment for boring app names ------------------------------------------------------ */ +/* ------------ uncomment for boring app names ---------------------------------------------------------------------------------------------------------- */ //#define BORING_APP_NAMES -/* ------------ print debug messages to USB serial -------------------------------------------------- */ +/* ------------ print debug messages to USB serial ------------------------------------------------------------------------------------------------------ */ //#define PRINT_DEBUG -/* ------------ flip screen / IO mapping ------------------------------------------------------------ */ +/* ------------ flip screen / IO mapping ---------------------------------------------------------------------------------------------------------------- */ //#define FLIP_180 -/* ------------ invert screen pixels ---------------------------------------------------------------- */ +/* ------------ invert screen pixels -------------------------------------------------------------------------------------------------------------------- */ //#define INVERT_DISPLAY -/* ------------ use DAC8564 ------------------------------------------------------------------------- */ +/* ------------ use DAC8564 ----------------------------------------------------------------------------------------------------------------------------- */ //#define DAC8564 -/* ------------ 0 / 10V range ----------------------------------------------------------------------- */ +/* ------------ 0 / 10V range --------------------------------------------------------------------------------------------------------------------------- */ //#define IO_10V + +/* do not edit the stuff below (unless ... ) */ + #if defined(IO_10V) #define BUCHLA_4U #endif +#if defined(VOR) + #define IO_10V +#endif + #endif diff --git a/software/o_c_REV/OC_scale_edit.h b/software/o_c_REV/OC_scale_edit.h index 59544561..2e0f7242 100644 --- a/software/o_c_REV/OC_scale_edit.h +++ b/software/o_c_REV/OC_scale_edit.h @@ -628,11 +628,15 @@ template void ScaleEditor::BeginEditing(bool mode) { cursor_pos_ = 0; - num_notes_ = scale_->num_notes; - mask_ = owner_->get_scale_mask(DUMMY); + num_notes_ = scale_->num_notes; + if (mode) { // == meta-Q edit_this_scale_ = owner_->get_scale_select(); - OC::ui._preemptScreensaver(true); + mask_ = owner_->get_scale_mask(edit_this_scale_); + OC::ui._preemptScreensaver(true); + } + else { + mask_ = owner_->get_scale_mask(DUMMY); } } diff --git a/software/o_c_REV/OC_strings.cpp b/software/o_c_REV/OC_strings.cpp index e96f2c7b..37a01135 100644 --- a/software/o_c_REV/OC_strings.cpp +++ b/software/o_c_REV/OC_strings.cpp @@ -16,6 +16,8 @@ namespace OC { const char * const note_names_unpadded[12] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; + const char * const VOR_offsets[3] = { "-5V", "-3V", "0V"}; + const char * const trigger_input_names[4] = { "TR1", "TR2", "TR3", "TR4" }; const char * const trigger_input_names_none[5] = { " - ", "TR1", "TR2", "TR3", "TR4" }; diff --git a/software/o_c_REV/OC_strings.h b/software/o_c_REV/OC_strings.h index d69a7d9d..41bac207 100644 --- a/software/o_c_REV/OC_strings.h +++ b/software/o_c_REV/OC_strings.h @@ -17,6 +17,7 @@ namespace OC { extern const char * const channel_id[]; extern const char * const note_names[]; extern const char * const note_names_unpadded[]; + extern const char * const VOR_offsets[]; extern const char * const trigger_input_names[]; extern const char * const trigger_input_names_none[]; extern const char * const cv_input_names[]; diff --git a/software/o_c_REV/OC_ui.cpp b/software/o_c_REV/OC_ui.cpp index bb405fd1..b8b6ea08 100644 --- a/software/o_c_REV/OC_ui.cpp +++ b/software/o_c_REV/OC_ui.cpp @@ -14,6 +14,11 @@ #include "OC_options.h" #include "src/drivers/display.h" +#ifdef VOR +#include "VBiasManager.h" +VBiasManager *VBiasManager::instance = 0; +#endif + extern uint_fast8_t MENU_REDRAW; namespace OC { @@ -24,7 +29,12 @@ void Ui::Init() { ticks_ = 0; set_screensaver_timeout(SCREENSAVER_TIMEOUT_S); + #ifdef VOR + static const int button_pins[] = { but_top, but_bot, butL, butR, but_mid }; + #else static const int button_pins[] = { but_top, but_bot, butL, butR }; + #endif + for (size_t i = 0; i < CONTROL_BUTTON_LAST; ++i) { buttons_[i].Init(button_pins[i], OC_GPIO_BUTTON_PINMODE); } @@ -111,12 +121,31 @@ UiMode Ui::DispatchEvents(App *app) { switch (event.type) { case UI::EVENT_BUTTON_PRESS: + #ifdef VOR + #ifdef VOR_NO_RANGE_BUTTON + if (OC::CONTROL_BUTTON_UP == event.control) { + VBiasManager *vbias_m = vbias_m->get(); + if (vbias_m->IsEditing()) vbias_m->AdvanceBias(); + else app->HandleButtonEvent(event); + } else app->HandleButtonEvent(event); + #else + if (OC::CONTROL_BUTTON_M == event.control) { + VBiasManager *vbias_m = vbias_m->get(); + vbias_m->AdvanceBias(); + } else app->HandleButtonEvent(event); + #endif + #else app->HandleButtonEvent(event); + #endif break; case UI::EVENT_BUTTON_LONG_PRESS: if (OC::CONTROL_BUTTON_UP == event.control) { - if (!preempt_screensaver_) - screensaver_ = true; + #ifdef VOR_NO_RANGE_BUTTON + VBiasManager *vbias_m = vbias_m->get(); + vbias_m->AdvanceBias(); + #else + if (!preempt_screensaver_) screensaver_ = true; + #endif } else if (OC::CONTROL_BUTTON_R == event.control) return UI_MODE_APP_SETTINGS; @@ -169,6 +198,8 @@ UiMode Ui::Splashscreen(bool &reset_settings) { menu::DefaultTitleBar::Draw(); #ifdef BUCHLA_cOC graphics.print("NLM card O_C"); + #elif defined(VOR) + graphics.print("Plum Audio O_C+"); #else graphics.print("Ornaments & Crimes"); #endif diff --git a/software/o_c_REV/OC_ui.h b/software/o_c_REV/OC_ui.h index 77ad4405..cbc456c0 100644 --- a/software/o_c_REV/OC_ui.h +++ b/software/o_c_REV/OC_ui.h @@ -2,6 +2,7 @@ #define OC_UI_H_ #include "OC_config.h" +#include "OC_options.h" #include "OC_debug.h" #include "UI/ui_button.h" #include "UI/ui_encoder.h" @@ -19,13 +20,18 @@ enum UiControl { CONTROL_BUTTON_DOWN = 0x2, CONTROL_BUTTON_L = 0x4, CONTROL_BUTTON_R = 0x8, - CONTROL_BUTTON_MASK = 0xf, + CONTROL_BUTTON_M = 0x10, - CONTROL_ENCODER_L = 0x10, - CONTROL_ENCODER_R = 0x20, + CONTROL_ENCODER_L = 0x20, + CONTROL_ENCODER_R = 0x40, + #ifdef VOR + CONTROL_LAST = 6, + CONTROL_BUTTON_LAST = 5, + #else CONTROL_LAST = 5, CONTROL_BUTTON_LAST = 4, + #endif }; static inline uint16_t control_mask(unsigned i) { @@ -109,8 +115,8 @@ class Ui { uint32_t ticks_; uint32_t screensaver_timeout_; - UI::Button buttons_[4]; - uint32_t button_press_time_[4]; + UI::Button buttons_[CONTROL_BUTTON_LAST]; + uint32_t button_press_time_[CONTROL_BUTTON_LAST]; uint16_t button_state_; uint16_t button_ignore_mask_; bool screensaver_; diff --git a/software/o_c_REV/OC_version.h b/software/o_c_REV/OC_version.h index 80bd1c7c..f4017cf7 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.5" +#define OC_VERSION "v1.3.6" #endif diff --git a/software/o_c_REV/VBiasManager.h b/software/o_c_REV/VBiasManager.h new file mode 100644 index 00000000..9505f584 --- /dev/null +++ b/software/o_c_REV/VBiasManager.h @@ -0,0 +1,138 @@ +// Copyright (c) 2019, Jason Justian +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// This singleton class has a few jobs related to keeping track of the bias value +// selected by the user and/or the app: +// +// (1) It allows advancing bias through three settings, one at a time +// (2) It allows setting the bias directly with a state +// (3) It shows a popup indicator for one second when the setting is advanced + +#ifndef VBIAS_MANAGER_H +#define VBIAS_MANAGER_H + +#include "OC_options.h" + +#ifdef VOR + +#define BIAS_EDITOR_TIMEOUT 16666 + +class VBiasManager { + static VBiasManager *instance; + int bias_state; + uint32_t last_advance_tick; + + VBiasManager() { + bias_state = 0; + last_advance_tick = 0; + } + +public: + static const int UNI = 0; + static const int ASYM = 1; + static const int BI = 2; + + static VBiasManager *get() { + if (!instance) instance = new VBiasManager; + return instance; + } + + /* + * Advance to the next state, when the button is pushed + */ + void AdvanceBias() { + // Only advance the bias if it's been less than a second since the last button press. + // This is so that the first button press shows the popup without changing anything. + if (OC::CORE::ticks - last_advance_tick < BIAS_EDITOR_TIMEOUT) { + if (++bias_state > 2) bias_state = 0; + instance->ChangeBiasToState(bias_state); + } + last_advance_tick = OC::CORE::ticks; + } + + int IsEditing() { + return (OC::CORE::ticks - last_advance_tick < BIAS_EDITOR_TIMEOUT); + } + + /* + * Change to a specific state. This should replace a direct call to OC::DAC::set_Vbias(), because it + * allows VBiasManager to keep track of the current state so that the button advances the state as + * expected. For example: + * + * #ifdef VOR + * VBiasManager *vbias_m = vbias_m->get(); + * vbias_m->ChangeBiasToState(VBiasManager::UNI); + * #endif + * + */ + void ChangeBiasToState(int new_bias_state) { + int new_bias_value = OC::calibration_data.v_bias & 0xFFFF; // Bipolar = lower 2 bytes + if (new_bias_state == VBiasManager::UNI) new_bias_value = OC::DAC::VBiasUnipolar; + if (new_bias_state == VBiasManager::ASYM) new_bias_value = (OC::calibration_data.v_bias >> 16); // asym. = upper 2 bytes + OC::DAC::set_Vbias(new_bias_value); + bias_state = new_bias_state; + } + + void SetStateForApp(int app_index) { + int new_state = VBiasManager::ASYM; + switch (app_index) + { + case 0: new_state = VBiasManager::ASYM; break; // CopierMachine (or) ASR + case 1: new_state = VBiasManager::ASYM; break; // Harrington 1200 (or) Triads + case 2: new_state = VBiasManager::ASYM; break; // Automatonnetz (or) Vectors + case 3: new_state = VBiasManager::ASYM; break; // Quantermain (or) 4x Quantizer + case 4: new_state = VBiasManager::ASYM; break; // Meta-Q (or) 2x Quantizer + case 5: new_state = VBiasManager::BI; break; // Quadraturia (or) Quadrature LFO + case 6: new_state = VBiasManager::BI; break; // Low-rents (or) Lorenz + case 7: new_state = VBiasManager::UNI; break; // Piqued (or) 4x EG + case 8: new_state = VBiasManager::ASYM; break; // Sequins (or) 2x Sequencer + case 9: new_state = VBiasManager::UNI; break; // Dialectic Ping Pong (or) Balls + case 10: new_state = VBiasManager::UNI; break; // Viznutcracker sweet (or) Bytebeats + case 11: new_state = VBiasManager::ASYM; break; // Acid Curds (or) Chords + case 12: new_state = VBiasManager::UNI; break; // References (or) Voltages + } + instance->ChangeBiasToState(new_state); + } + + /* + * If the last state advance (with the button) was less than a second ago, draw the popup indicator + */ + void DrawPopupPerhaps() { + if (OC::CORE::ticks - last_advance_tick < BIAS_EDITOR_TIMEOUT) { + graphics.clearRect(17, 7, 82, 43); + graphics.drawFrame(18, 8, 80, 42); + + graphics.setPrintPos(20, 10); + graphics.print("VOR:"); + graphics.setPrintPos(30, 20); + graphics.print(" 0V -> 10V"); + graphics.setPrintPos(30, 30); + graphics.print("-3V -> 7V"); + graphics.setPrintPos(30, 40); + graphics.print("-5V -> 5V"); + + graphics.setPrintPos(20, 20 + (bias_state * 10)); + graphics.print("> "); + } + } +}; + +#endif // VBIAS_MANAGER_H +#endif diff --git a/software/o_c_REV/o_c_REV.ino b/software/o_c_REV/o_c_REV.ino index 7cd3e7b2..098bc866 100644 --- a/software/o_c_REV/o_c_REV.ino +++ b/software/o_c_REV/o_c_REV.ino @@ -40,6 +40,7 @@ #include "src/drivers/display.h" #include "src/drivers/ADC/OC_util_ADC.h" #include "util/util_debugpins.h" +#include "VBiasManager.h" unsigned long LAST_REDRAW_TIME = 0; uint_fast8_t MENU_REDRAW = true; @@ -166,6 +167,13 @@ void FASTRUN loop() { OC_DEBUG_PROFILE_SCOPE(OC::DEBUG::MENU_draw_cycles); OC::apps::current_app->DrawMenu(); ++menu_redraws; + + #ifdef VOR + // JEJ:On app screens, show the bias popup, if necessary + VBiasManager *vbias_m = vbias_m->get(); + vbias_m->DrawPopupPerhaps(); + #endif + } else { OC::apps::current_app->DrawScreensaver(); } diff --git a/software/o_c_REV/peaks_multistage_envelope.cpp b/software/o_c_REV/peaks_multistage_envelope.cpp index 022c9682..6d4de762 100644 --- a/software/o_c_REV/peaks_multistage_envelope.cpp +++ b/software/o_c_REV/peaks_multistage_envelope.cpp @@ -137,6 +137,8 @@ uint16_t MultistageEnvelope::ProcessSingleSample(uint8_t control) { } #ifdef BUCHLA_4U return(static_cast(scaled_value_ << 1)); + #elif defined(VOR) + return(static_cast(scaled_value_ << 1)); #else return(static_cast(scaled_value_)); #endif