commit 8d88437702078d818eb53d5879e6959c00a0cf68 Author: Rob French Date: Thu Oct 29 18:08:42 2020 -0500 Initial commit. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/digibox/cat_serial.h b/digibox/cat_serial.h new file mode 100644 index 0000000..6eb051a --- /dev/null +++ b/digibox/cat_serial.h @@ -0,0 +1,20 @@ +//====================================================================== +// cat_serial.h +//====================================================================== + +#ifndef __cat_serial_h__ +#define __cat_serial_h__ + +namespace cat_serial +{ + + void init(cat_serial_cfg& c); + void update(int msec); + +}; + +#endif + +//====================================================================== +// EOF +//====================================================================== diff --git a/digibox/dsp_audio.cpp b/digibox/dsp_audio.cpp new file mode 100644 index 0000000..a503941 --- /dev/null +++ b/digibox/dsp_audio.cpp @@ -0,0 +1,368 @@ +//====================================================================== +// dsp_audio.cpp +//====================================================================== + +#include +#include +#include "dsp_audio.h" + +#define RX_RIG_IN 0 +#define RX_USB_IN 1 +#define RX_ST_IN 2 // sidetone + +#define TX_MIC_IN 0 +#define TX_LINE_IN 0 +#define TX_USB_IN 1 +#define TX_TEST_IN 2 + +#define RX_BPF_ONLY 0 +#define RX_NOTCH_ON 1 + +#include +#include +#include +#include +#include + +namespace dsp_audio +{ + // GUItool: begin automatically generated code + AudioInputI2S line_in; //xy=148.9999771118164,131 + AudioInputUSB usb_in; //xy=148.9999771118164,303 + AudioSynthWaveformSine sidetone; //xy=150.9999771118164,214 + AudioSynthWaveformSine sine2; //xy=337.9999771118164,482 + AudioSynthWaveformSine sine1; //xy=338.9999771118164,428 + AudioAnalyzeFFT256 rx_fft; //xy=370.0127944946289,103.02459716796875 + AudioAnalyzeRMS rx_rms; //xy=376.9999771118164,20 + AudioAnalyzePeak rx_peak; //xy=376.9999771118164,65 + AudioEffectFade tx_comp; //xy=400.99999237060547,260.99999809265137 + AudioAnalyzeRMS tx_comp_rms; //xy=402.9999771118164,224 + AudioMixer4 rx_in_mix; //xy=458.9999771118164,163 + AudioFilterFIR rx_fir_filter; //xy=628.0000839233398,135.00000476837158 + AudioMixer4 tx_mix; //xy=666.9999771118164,321 + AudioFilterBiquad rx_biquad_filter; //xy=765.7827301025391,183.02459716796875 + AudioAnalyzeRMS tx_rms; //xy=855.9999771118164,449 + AudioAnalyzePeak tx_peak; //xy=857.9999771118164,393 + AudioAmplifier tx_line_out_cal; //xy=906.9999771118164,255 + AudioAmplifier tx_usb_out_cal; //xy=907.9999771118164,312 + AudioMixer4 rx_out_mix; //xy=933.78271484375,119.02459144592285 + AudioAmplifier rx_usb_out_cal; //xy=1155,180.99999904632568 + AudioAmplifier rx_line_out_cal; //xy=1156.9999771118164,109.00000381469727 + AudioAmplifier rx_spkr_out_cal; //xy=1167.0000076293945,50 + AudioOutputAnalog spkr_out; //xy=1307.000015258789,53 + AudioOutputUSB usb_out; //xy=1332.999984741211,291.0000114440918 + AudioOutputI2S line_out; //xy=1374.9999618530273,207.0000057220459 + AudioConnection patchCord1(line_in, 0, rx_rms, 0); + AudioConnection patchCord2(line_in, 0, rx_peak, 0); + AudioConnection patchCord3(line_in, 0, rx_in_mix, 0); + AudioConnection patchCord4(line_in, 0, rx_fft, 0); + AudioConnection patchCord5(line_in, 1, tx_comp, 0); + AudioConnection patchCord6(line_in, 1, tx_comp_rms, 0); + AudioConnection patchCord7(usb_in, 0, rx_in_mix, 1); + AudioConnection patchCord8(usb_in, 1, tx_mix, 1); + AudioConnection patchCord9(sidetone, 0, rx_in_mix, 2); + AudioConnection patchCord10(sine2, 0, tx_mix, 3); + AudioConnection patchCord11(sine1, 0, tx_mix, 2); + AudioConnection patchCord12(tx_comp, 0, tx_mix, 0); + AudioConnection patchCord13(rx_in_mix, rx_fir_filter); + AudioConnection patchCord14(rx_fir_filter, rx_biquad_filter); + AudioConnection patchCord15(rx_fir_filter, 0, rx_out_mix, 0); + AudioConnection patchCord16(tx_mix, tx_line_out_cal); + AudioConnection patchCord17(tx_mix, tx_usb_out_cal); + AudioConnection patchCord18(tx_mix, tx_peak); + AudioConnection patchCord19(tx_mix, tx_rms); + AudioConnection patchCord20(rx_biquad_filter, 0, rx_out_mix, 1); + AudioConnection patchCord21(tx_line_out_cal, 0, line_out, 1); + AudioConnection patchCord22(tx_usb_out_cal, 0, usb_out, 1); + AudioConnection patchCord23(rx_out_mix, spkr_out_cal); + AudioConnection patchCord24(rx_out_mix, rx_line_out_cal); + AudioConnection patchCord25(rx_out_mix, rx_usb_out_cal); + AudioConnection patchCord26(rx_usb_out_cal, 0, usb_out, 0); + AudioConnection patchCord27(rx_line_out_cal, 0, line_out, 0); + AudioConnection patchCord28(spkr_out_cal, spkr_out); + AudioControlSGTL5000 audioCtrl; //xy=648,517 + // GUItool: end automatically generated code + + class configurator + { + public: + configurator(dsp_audio_cfg& c): data(c) {} + dsp_audio_cfg& data; + } *cfg = nullptr; +}; + +void dsp_audio::init(dsp_audio_cfg& c) { + USBDEBUG("audio initialization started"); + + if (cfg != nullptr) { + delete cfg; + } + cfg = new configurator(c); + + audio_ctrl.enable(); + audio_ctrl.adcHighPassFilterEnable(); // default + audio_ctrl.dacVolume(1.0); // default + audio_ctrl.dacVolumeRampDisable(); // not default; just trying to cull out culprits for my high freq hiss + audio_ctrl.audioProcessorDisable(); + audio_ctrl.autoVolumeDisable(); + audio_ctrl.surroundSoundDisable(); + audio_ctrl.enhanceBassDisable(); + audio_ctrl.eqSelect(FLAT_FREQUENCY); // eventually, use this to smooth out the normal uBITX passband + + audio_ctrl.muteHeadphone(); // not using the headphone output + audio_ctrl.volume(0.0); // not using the headphone output + audio_ctrl.inputSelect(AUDIO_INPUT_LINEIN); // required for RX audio + audio_ctrl.unmuteLineout(); // required for RX audio + + audio_ctrl.lineInLevel(cfg.data.rx_rig_in_level, cfg.data.tx_line_in_level); // NOTE: need to see if this persists through input changes (see mic gain...) + audio_ctrl.lineOutLevel(cfg.data.rx_line_out_level, cfg.data.tx_rig_out_level); // NOTE: need to see if this persists through input changes (see mic gain...) + audio_ctrl.micGain(cfg.data.tx_mic_in_gain); // superfluous, as I have to do this anytime I switch to mic for some reason + + // configure line input + audio_ctrl.lineInLevel(cfg.data.rx_rig_in_level, cfg.data.tx_line_in_level); + + // configure line output + tx_rig_out_cal.gain(cfg.data.tx_rig_out_cal); + audio_ctrl.lineOutLevel(cfg.data.rx_line_out_level, cfg.data.tx_rig_out_level); + + // configure "receive" of USB audio input (debug only) + if (cfg.data.rx_usb_in_enable) { + rx_in_mix.gain(RX_USB_IN, cfg.data.rx_usb_in_vol * cfg.data.rx_usb_in_cal); + } else { + rx_in_mix.gain(RX_USB_IN, 0.0); + } + + // configure USB audio output of transmit audio (useful for debug) + if (cfg.data.tx_usb_out_enable) { + tx_usb_out_cal.gain(cfg.data.tx_usb_out_cal); + } else { + tx_usb_out_cal.gain(0.0); + } + + // setup the two-tone generator + sine1.frequency(700); + sine2.frequency(1900); + sine1.amplitude(0); + sine2.amplitude(0); + + // no separate filter amp; just need to appropriately set the rx_out_mix values + rx_out_mix.gain(RX_BPF_ONLY, 1.0); + rx_out_mix.gain(RX_NOTCH_ON, 0.0); + + // for now, just pass through the compressor + tx_comp.disable(); + + // Hardware should be all setup... now we're going to mute everything + // and let the modes take care of enabling/disabling what they should. + for (int i = 0; i < 4; i++) { + rx_in_mix.gain(i, 0.0); + tx_mix.gain(i, 0.0); + } + + audio_equalizer(); + + USBDEBUG("audio initialization completed"); +} + +void dsp_audio::mute_rx() { + rx_in_mix.gain(RX_RIG_IN, 0.0); + USBDEBUG("RX audio muted"); +} + +void dsp_audio::unmute_rx() { + audio_ctrl.inputSelect(AUDIO_INPUT_LINEIN); + rx_in_mix.gain(RX_RIG_IN, cfg.data.rx_rig_in_vol * cfg.data.rx_rig_in_cal); + USBDEBUG("RX audio unmuted"); +} + +void dsp_audio::mute_all_tx() { + mute_mic_in(); + mute_line_in(); + mute_usb_in(); + mute_twotone_in(); + USBDEBUG("all TX audio muted"); +} + +void dsp_audio::mute_mic_in() { + tx_mix.gain(TX_LINE_IN, 0.0); + USBDEBUG("Mic In audio muted"); +} + +void dsp_audio::unmute_mic_in() { + audio_ctrl.inputSelect(AUDIO_INPUT_MIC); + audio_ctrl.micGain(cfg.data.tx_mic_in_gain); + tx_mix.gain(TX_LINE_IN, cfg.data.tx_mic_in_vol * cfg.data.tx_mic_in_cal); + USBDEBUG("Mic In audio unmuted"); +} + +void dsp_audio::mute_line_in() { + tx_mix.gain(TX_LINE_IN, 0.0); + USBDEBUG("Line In audio muted"); +} + +void dsp_audio::unmute_line_in() { + audio_ctrl.inputSelect(AUDIO_INPUT_LINEIN); + tx_mix.gain(TX_LINE_IN, cfg.data.tx_line_in_vol * cfg.data.tx_line_in_cal); + USBDEBUG("Line In audio unmuted"); +} + +void dsp_audio::mute_usb_in() { + tx_mix.gain(TX_USB_IN, 0.0); + USBDEBUG("USB In audio muted"); +} +void dsp_audio::unmuteUSBIn() { + tx_mix.gain(TX_USB_IN, cfg.data.tx_usb_in_vol * cfg.data.tx_usb_in_cal); + USBDEBUG("USB In audio unmuted"); +} + +void dsp_audio::mute_twotone_in() { + tx_mix.gain(TX_TEST_IN, 0.0); + tx_mix.gain(TX_TEST_IN + 1, 0.0); + sine1.amplitude(0.0); + sine2.amplitude(0.0); + USBDEBUG("Two Tone audio muted"); +} + +void dsp_audio::unmute_twotone_in() { + sine1.amplitude(0.5); + sine2.amplitude(0.5); + tx_mix.gain(TX_TEST_IN, cfg.data.tx_sine1_vol); + tx_mix.gain(TX_TEST_IN + 1, cfg.data.tx_sine2_vol); + USBDEBUG("Two Tone audio unmuted"); +} + +void dsp_audio::mute_spkr_out() { + rx_spkr_out_cal.gain(0.0); + USBDEBUG("Speaker Out audio muted"); +} + +void dsp_audio::unmute_spkr_out() { + rx_spkr_out_cal.gain(cfg.data.rx_spkr_out_cal); + USBDEBUG("Speaker Out audio unmuted"); +} + +void dsp_audio::mute_line_out() { + rx_line_out_cal.gain(0.0); + USBDEBUG("Line Out audio muted"); +} + +void dsp_audio::unmute_line_out() { + rx_line_out_cal.gain(cfg.data.rx_line_out_cal); + USBDEBUG("Line Out audio unmuted"); +} + +void dsp_audio::mute_usb_out() { + rx_usb_out_cal.gain(0.0); + USBDEBUG("USB Out audio muted"); +} + +void dsp_audio::unmute_usb_out() { + rx_usb_out_cal.gain(cfg.data.rx_usb_out_cal); + USBDEBUG("USB Out audio unmuted"); +} + +//====================================================================== +// bp_filter +// +// Band Pass Filter methods. +//====================================================================== + +bp_filter::bp_filter(): filter(filterRX), amp(filterAmp) {} + +bp_filter::bp_filter(AudioFilterFIR& f, AudioAmplifier& a): filter(f), amp(a) {} + +void bp_filter::init(const bpf_config& cfg) { + set_band(cfg.lo_freq, cfg.hi_freq); + set_gain(cfg.gain); +} + +void bp_filter::set_band(double f1, double f2) { + freq_lo = f1; + freq_hi = f2; +} + +void bp_filter::set_freq_lo(double f) { freq_lo = f; } + +void bp_filter::set_freq_hi(double f) { freq_hi = f; } + +void bp_filter::set_center_and_width(double c, double w) { + freq_lo = c - (0.5 * w); + freq_hi = c + (0.5 * w); +} + +void bp_filter::set_center(double c) { + double w = freq_hi - freq_lo; + set_center_and_width(c, w); +} + +void bp_filter::set_width(double w) { + double c = (freq_lo + freq_hi) * 0.5; + set_center_and_width(c, w); +} + +void bp_filter::set_gain(double g) { recovery = g; } + +void bp_filter::enable() { + audioFilter(coefficients, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, freq_lo, freq_hi); + filter.begin(coefficients, NUM_COEFFICIENTS); + amp.gain(recovery); +} + +void bp_filter::disable() { + filter.begin(FIR_PASSTHRU, NUM_COEFFICIENTS); + amp.gain(1.0); +} + +//====================================================================== + +speech_comp::speech_comp(comp_config* cfg) : + config_(cfg), comp_(compTX), amp_(compAmp), rms_(compRMS) {} + +void speech_comp::enable() +{ + config_->enabled = true; + comp_.begin(1, config_->threshold, config_->ratio); // Need to make configurable + amp_.gain(config_->gain); +} + +void speech_comp::disable() +{ + config_->enabled = false; + comp_.disable(); + amp_.gain(1.0); +} + +// Speech compressor code based on post by 'hyperdyne': https://forum.pjrc.com/threads/36245-Changing-Pitch-of-Voice + +void speech_comp::update() +{ + float rms_cur; + if (config_->enabled && rms_.available()) { + rms_cur = rms_.read(); + env_ = rms_cur + (alpha_ * (env_ - rms_cur)); + comp_.update_pwr(env_); + } +} + +//====================================================================== + +void dsp_audio::audio_equalizer() +{ + static int eqFilter1[5]; + + audioCtrl.audioPreProcessorEnable(); + audioCtrl.eqSelect(PARAMETRIC_EQUALIZER); + // calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*); + calcBiquad(FILTER_PARAEQ, 2700, 6, 0.707, 524288, 44100, eqFilter1); +// calcBiquad(FILTER_HIPASS, 100, 0, 0.707, 524288, 44100, hpFilter); + audioCtrl.eqFilter(0, eqFilter1); +// audioCtrl.eqFilter(1, hpFilter); +// audioCtrl.eqFilter(2, lpFilter); +// audioCtrl.eqFilter(3, hpFilter); +// audioCtrl.eqFilter(4, lpFilter); +// audioCtrl.eqFilter(5, hpFilter); +} + +//====================================================================== +// EOF +//====================================================================== diff --git a/digibox/dsp_audio.h b/digibox/dsp_audio.h new file mode 100644 index 0000000..d634410 --- /dev/null +++ b/digibox/dsp_audio.h @@ -0,0 +1,120 @@ +//====================================================================== +// dsp_audio.h +//====================================================================== + +#ifndef __dsp_audio_h__ +#define __dsp_audio_h__ + +#include +#include +#include +#include "config.h" + +namespace dsp_audio +{ + + void init(dsp_audio_cfg& c); + void update(int msec); + + void mute_rx(); + void unmute_rx(); + + void mute_all_tx(); + + void mute_mic_in(); + void unmute_mic_in(); + + void mute_line_in(); + void unmute_line_in(); + + void mute_usb_in(); + void unmute_usb_in(); + + void mute_twotone_in(); + void unmute_twotone_in(); + + void mute_spkr_out(); + void unmute_spkr_out(); + + void mute_line_out(); + void unmute_line_out(); + + void mute_usb_out(); + void unmute_usb_out(); + + //====================================================================== + + class bp_filter { + + public: + bp_filter(); + bp_filter(AudioFilterFIR& f, AudioAmplifier& a); + void init(const bpf_config& cfg); + void set_band(double f1, double f2); + void set_freq_lo(double f); + void set_freq_hi(double f); + void set_center_and_width(double c, double w); + void set_center(double c); + void set_width(double w); + void set_gain(double g); + void enable(); + void disable(); + + private: + + double freq_lo; + double freq_hi; + short int window; + short int coeff; + float recovery; // recovery amplifier value + + AudioFilterFIR& filter; // = &filterRX; + AudioAmplifier& amp; + short coefficients[NUM_COEFFICIENTS]; + bool setup_complete; + }; + + //====================================================================== + + class notch_filter + { + public: + notch_filter(notch_config& cfg); + void enable(); + void disable(); + inline bool is_enabled() const { return config_.enabled; } + + private: + + notch_config& config_; + double freq_; + double q_; + }; + + //====================================================================== + + class speech_comp + { + public: + speech_comp(comp_config& cfg); + void update(); + void enable(); + void disable(); + inline bool is_enabled() const { return config_.enabled; } + + private: + comp_config& config_; + AudioEffectCompressor& comp_; + AudioAmplifier& amp_; + AudioAnalyzeRMS& rms_; + float env_ = 1.0; + float alpha_ = 0.8; + }; + +}; + +#endif + +//====================================================================== +// EOF +//====================================================================== diff --git a/digibox/ubitx-dsp.h b/digibox/ubitx-dsp.h new file mode 100644 index 0000000..1d9ff8d --- /dev/null +++ b/digibox/ubitx-dsp.h @@ -0,0 +1,75 @@ +//====================================================================== +// ubitx_iop.h +//====================================================================== + +#ifndef __ubitx_iop_h__ +#define __ubitx_iop_h__ + +#include "config.h" +#include "audio.h" +#include "cat.h" +#include "eeprom.h" +#include "keyer.h" + +#define PTT_KEY_OUT_PIN 2 +#define ENCODER_A_PIN 5 +#define ENCODER_B_PIN 4 +#define ENCODER_SW_PIN 3 + +// comment this out to disable debugging code +#define DEBUG + +#if defined(DEBUG) +#define USBDEBUG(x) USBSERIAL.print("IOP: "); USBSERIAL.println(x); +#else +#define USBDEBUG(x) +#endif + +//enum RigMode { +// MODE_SSB = 0, +// MODE_DIGI = 1, +// MODE_CW = 2, +//}; + +enum TxState { + TX_OFF = 0, + TX_MIC, + TX_LINE, + TX_CAT, + TX_KEYER, +}; + +//extern RigMode rigMode; + +extern bool keyerKeyDown; + +//====================================================================== +// Keying functions. +// +// These are simple functions to assert the key line from the IOP to the +// Raduino. +//====================================================================== + +inline void initKeyLine() +{ + pinMode(PTT_KEY_OUT_PIN, OUTPUT); + digitalWrite(PTT_KEY_OUT_PIN, HIGH); +} + +inline void setKeyDown() +{ + digitalWrite(PTT_KEY_OUT_PIN, LOW); +} + +inline void setKeyUp() +{ + digitalWrite(PTT_KEY_OUT_PIN, HIGH); +} + +//====================================================================== + +#endif + +//====================================================================== +// EOF +//====================================================================== diff --git a/digibox/ubitx-dsp.ino b/digibox/ubitx-dsp.ino new file mode 100644 index 0000000..df9fe85 --- /dev/null +++ b/digibox/ubitx-dsp.ino @@ -0,0 +1,235 @@ +//====================================================================== +// ubitx_iop.ino +//====================================================================== + +#include +#include +#include "audio.h" +#include "config.h" +#include "ubitx_iop.h" +#include "keyer.h" +#include "menu.h" +#include "rig.h" +#include "TxSwitch.h" + +Keyer keyer{15, 3.0}; // NOTE: make configurable + +RigConfig rigConfig; +RigAudio rigAudio{rigConfig.audio}; +basic_rig rig{rigConfig, rigAudio}; + +CATSwitch catPTT; +//MicSwitch micPTTHelper; +GPIOSwitch micPTT(true, MIC_PTT_PIN); +//LineSwitch linePTTHelper; +GPIOSwitch linePTT(false, LINE_PTT_PIN); + +Encoder knob(ENCODER_A_PIN, ENCODER_B_PIN); +long knobPos = 0; + +Bounce btn; +elapsedMillis btnMillis; + +Main_menu main_menu(rig); +Menu_item* menu_item = &main_menu; + +elapsedMillis frameMillis; +unsigned frameTime; +unsigned frameCounter; +unsigned audioProcUsage; +unsigned audioMemUsage; + +//====================================================================== + +void setup() { + // put your setup code here, to run once: + initCAT(38400, SERIAL_8N1); + USBDEBUG("setup started"); + + AudioMemory(16); // NOTE: Need to fine tune this. Have had errors due to this being too low. + + initKeyLine(); + rigAudio.init(); + + frameCounter = 0; + frameMillis = 0; + + knob.write(0); + + btn.attach(ENCODER_SW_PIN, INPUT_PULLUP); + btn.interval(25); + + rig.init(); + + USBDEBUG("setup completed"); +} + +//====================================================================== + +void update_io_menu(Menu_item* item, bool is_active) +{ + Menu_string text; + + if (!is_active || (is_active && item == nullptr)) { + sendIOPMenuInactive(); + } else { + item->get_text(text); + sendIOPMenuDisplay(text.data()); + } +} + +//====================================================================== + +void loop() +{ + static bool menu_is_active = false; + static bool menu_updated = false; + + static char frame_status[100]; + static char old_mode_text[17] = " "; + static bool paddle_loop = false; +// long oldPos = knobPos; + + rig_mode oldRigMode; + + frameCounter++; + + if (rig.is_cw_mode()) { + if (keyer.do_paddles()) { + + // Checking for T/R separately from the paddle loop, because it's + // possible we're already transmitting (PTT/Key being held), and + // we don't want to run the tx() actions if we're already in TX. + if (rig.is_rx()) { + USBDEBUG("entered TX via paddles"); + rig.tx(); + } + + paddle_loop = true; + + if (keyer.is_down()) { + setKeyDown(); + } else { + setKeyUp(); + } + + return; // return early for paddle responsiveness + } else { + if (paddle_loop) { + // If we exit the paddle loop (i.e. keyer completes its keying + // sequence), then we'll go back to receive, even if one of the + // PTT/Key lines is still held separately. General principle is + // that if "something" stops transmitting, then the rig will + // stop transmitting. + paddle_loop = false; + rig.rx(); + USBDEBUG("exited TX from paddles"); + } + } + } + + rig.update(); + + oldRigMode = rig.get_rig_mode(); + + // Update the mic PTT. We need to tell it if we're in SSB mode, so that + // it knows if it should switch to the mic input if pressed. We also + // need to make it inactive if we're in DGT mode, since only CAT will be + // used to start transmitting in that case. + micPTT.setSSBMode(rig.is_ssb_mode()); + micPTT.update(rig.mode(), !rig.is_digi_mode()); + + // Update the line PTT. We need to tell it if we're in SSB mode, so that + // it knows if it should switch to the line input if pressed. We also + // need to make it inactive if we're in DGT mode, since only CAT will be + // used to start transmitting in that case. + linePTT.setSSBMode(rig.is_ssb_mode()); + linePTT.update(rig.mode(), !rig.is_digi_mode()); + + serviceCAT(); + + menu_updated = false; + btn.update(); + knobPos = knob.read(); + + if (btn.fell()) { + btnMillis = 0; + USBDEBUG("button pressed"); + // cancel out any knob rotation that occurred during in conjunction with press/release + knob.write(0); + + } else if (btn.rose()) { + menu_updated = true; + if (btnMillis > 1000) { + // long press - exit + menu_item = menu_item->exit(); + USBDEBUG("button released - long (exit)"); + } else if (btnMillis > 500) { + // medium press - altSelect + if (menu_is_active) { + menu_item = menu_item->altSelect(); + } else { + menu_item = audio_config_menu; + menu_is_active = true; + } + USBDEBUG("button released - medium (altSelect)"); + } else { + // short press - select + if (menu_is_active) { + menu_item = menu_item->select(); + } else { + menu_item = &main_menu; + menu_is_active = true; + } + USBDEBUG("button released - short (select)"); + } + // cancel out any knob rotation that occurred during in conjunction with press/release + knob.write(0); + + } else if (knobPos > 3 && menu_is_active) { + // left + menu_item = menu_item->prev(); + knob.write(0); + menu_updated = true; + USBDEBUG("knob turned left"); + + } else if (knobPos < -3 && menu_is_active) { + // right + menu_item = menu_item->next(); + knob.write(0); + menu_updated = true; + USBDEBUG("knob turned right"); + } + + if (menu_item == nullptr) { + menu_item = &main_menu; + menu_is_active = false; + menu_updated = true; + USBDEBUG("null menu - reset to main menu"); + } + + if (menu_updated) { + update_io_menu(menu_item, menu_is_active); + USBDEBUG("updated main menu"); + } + + rig.update(); + + if (frameMillis > 5000) { + #if defined(DEBUG) + frameTime = frameMillis; + audioProcUsage = AudioProcessorUsageMax(); + audioMemUsage = AudioMemoryUsageMax(); + sprintf(frame_status, "update: %u ms, %u frames, %d %% CPU max, %d %% mem max\n", frameTime, frameCounter, audioProcUsage, audioMemUsage); + USBDEBUG(frame_status); + #endif + frameMillis = 0; + frameCounter = 0; + } + + //audioUpdate(); // was used to update the speech compressor +} + +//====================================================================== +// EOF +//======================================================================