diff --git a/iopcomm/iopcomm.h b/iopcomm/iopcomm.h index 4b06874..ee66998 100644 --- a/iopcomm/iopcomm.h +++ b/iopcomm/iopcomm.h @@ -97,41 +97,39 @@ enum MessageID { * (e.g. USB, LSB, etc.) */ -enum rig_mode { - lsb = 0, - usb, +enum struct rig_mode { + ssb = 0, cw, - cwr, - dig, + digi, // add new items here - num_rig_modes + count }; /* Keyer modes. */ -enum keyer_mode { +enum struct keyer_mode { straight = 0, iambic_a, iambic_b, //ultimatic, //bug, // add any new items here - num_keyer_modes + count }; -enum rx_filter { +enum struct rx_filter { wide = 0, medium, narrow, - num_rx_filters + count }; -enum digi_mode { +enum struct digi_submode { rtty = 0, psk31, user_defined, - num_digi_modes + count }; //const unsigned char RIG_MODE_LETTER[num_rig_modes] = {'s', 'S', 'c', 'C', 'd', 'D', 't', 'T'}; @@ -154,67 +152,70 @@ struct IOPMessage { // Interface to a configuration object. //====================================================================== -struct filter_config { - float lo; - float hi; +struct bpf_config { + float lo_freq; + float hi_freq; float gain; }; struct mode_config { - mode_config(bool usb, rx_filter f, const filter_config *fc) : is_usb(usb), filter(f) { - for (int i = 0; i < num_rx_filters; i++) { - filtercfg[i] = fc[i]; + mode_config(bool usb, rx_filter f, const bpf_config *fc) : is_usb(usb), filter(f) { + for (int i = 0; i < static_cast(rx_filter::count); i++) { + filter_cfg[i] = fc[i]; } } - bool is_usb; - rx_filter filter; - filter_config filtercfg[num_rx_filters]; + bool is_usb; + rx_filter filter; + bpf_config filter_cfg[static_cast(rx_filter::count)]; }; //====================================================================== // SSB CONFIGURATION //====================================================================== -const filter_config ssb_filter_config[num_rx_filters] = - {filter_config{ 300.0, 3100.0, 1.0}, - filter_config{ 500.0, 2900.0, 1.0}, - filter_config{ 700.0, 2500.0, 1.0}}; - +const bpf_config ssb_filter_config[] = + {bpf_config{ 300.0, 3100.0, 1.0}, + bpf_config{ 500.0, 2900.0, 1.0}, + bpf_config{ 700.0, 2500.0, 1.0}}; + +struct comp_config { + bool enabled = false; + float threshold = 0.1; + float ratio = 20.0; + float gain = 2.0; +}; + struct ssb_config : public mode_config { - ssb_config() : mode_config(true, wide, ssb_filter_config) {} - // speech compressor parameters - bool comp_enable = false; - float comp_threshold = 0.1; - float comp_ratio = 20.0; - float comp_gain = 2.0; + ssb_config() : mode_config(true, rx_filter::wide, ssb_filter_config) {} + comp_config comp; }; //====================================================================== -// DIG CONFIGURATION +// DIGI CONFIGURATION //====================================================================== -const filter_config dig_filter_config[num_rx_filters] = - {filter_config{ 300.0, 3100.0, 1.0}, - filter_config{ 500.0, 2900.0, 1.0}, - filter_config{1250.0, 1750.0, 1.0}}; +const bpf_config digi_filter_config[] = + {bpf_config{ 300.0, 3100.0, 1.0}, + bpf_config{ 500.0, 2900.0, 1.0}, + bpf_config{1250.0, 1750.0, 1.0}}; -struct dig_config : public mode_config { - dig_config() : mode_config(true, wide, dig_filter_config) {} - digi_mode submode = user_defined; +struct digi_config : public mode_config { + digi_config() : mode_config(true, rx_filter::wide, digi_filter_config) {} + digi_submode submode = digi_submode::user_defined; }; //====================================================================== // CW CONFIGURATION //====================================================================== -const filter_config cw_filter_config[num_rx_filters] = - {filter_config{ 300.0, 1300.0, 1.0}, - filter_config{ 450.0, 950.0, 1.0}, - filter_config{ 575.0, 825.0, 1.0}}; +const bpf_config cw_filter_config[] = + {bpf_config{ 300.0, 1300.0, 1.0}, + bpf_config{ 450.0, 950.0, 1.0}, + bpf_config{ 575.0, 825.0, 1.0}}; struct cw_config : public mode_config { - cw_config() : mode_config(true, wide, cw_filter_config) {} - keyer_mode mode = iambic_a; + cw_config() : mode_config(true, rx_filter::wide, cw_filter_config) {} + keyer_mode mode = keyer_mode::iambic_a; // flags bool reversed = false; // parameters diff --git a/ubitx_iop/RigMode.h b/ubitx_iop/RigMode.h index 5c0f21b..e15a711 100644 --- a/ubitx_iop/RigMode.h +++ b/ubitx_iop/RigMode.h @@ -7,147 +7,160 @@ #include "audio.h" -// Exceptions not active (for Arduino, I assume?). -//enum IModeExceptions { -// MODE_ALREADY_ACTIVE = -1, -// MODE_STILL_TRANSMITTING = -2, -// MODE_ALREADY_TRANSMITTING = -3, -// MODE_NOT_TRANSMITTING = -4, -//}; - //====================================================================== -// IMode +// basic_mode // -// Interface to a rig mode (SSB, CW, etc.). +// A basic rig mode. It can perform actions on_entry() and on_exit(), +// as well as on_tx() and on_rx(). These actions are defined in an +// appropriate subclass. In addition, the basic mode support an audio +// audio band pass filter with wide, medium, and narrow modes. //====================================================================== -class IMode { +class basic_mode { public: - IMode(mode_config& c, RigAudio& a, IFilter& f): - _config(c), _audio(a), _filter(f), _active(false), _transmitting(false) + basic_mode(mode_config& c, RigAudio& a, bp_filter& f) : + config_(c), audio_(a), filter_(f), active_(false), transmitting_(false) { } - virtual ~IMode() {} + virtual ~basic_mode() {} - inline mode_config& config() { return _config; } + inline mode_config& config() { return config_; } - inline RigAudio& audio() { return _audio; } + inline RigAudio& audio() { return audio_; } - inline IFilter& filter() { return _filter; } + inline bp_filter& filter() { return filter_; } // Called upon mode entry. Should assume that the rig's state is // "clean", i.e. that it still needs to enable anything it needs for // use in the mode. - virtual void onEntry() = 0; + virtual void on_entry() = 0; // Called upon mode exit. Should clean everything up that it used, // and not make assumptions about which mode is being entered next. - virtual void onExit() = 0; + virtual void on_exit() = 0; // Called when transmitting. - virtual void onTx() = 0; + virtual void on_tx() = 0; // Called when receiving. - virtual void onRx() = 0; + virtual void on_rx() = 0; inline void enter() { - if (_active) { + if (active_) { // Do nothing. Exceptions not active (for Arduino, I assume?). //throw MODE_ALREADY_ACTIVE; USBDEBUG("ERROR - tried to enter mode, but it's already active"); } else { - _active = true; - onEntry(); + active_ = true; + on_entry(); } } inline void exit() { - if (_transmitting) { + if (transmitting_) { // Do nothing. Exceptions not active (for Arduino, I assume?). //throw MODE_STILL_TRANSMITTING; USBDEBUG("ERROR - tried to exit mode, but it's transmitting"); } else { - _active = false; - onExit(); + active_ = false; + on_exit(); } } - inline bool isActive() { return _active; } - inline bool isInactive() { return !_active; } + inline bool is_active() { return active_; } + inline bool is_inactive() { return !active_; } inline void tx() { - if (_transmitting) { + if (transmitting_) { // Do nothing. Exceptions not active (for Arduino, I assume?). //throw MODE_ALREADY_TRANSMITTING; USBDEBUG("ERROR - tried to start transmitting, but mode already is transmitting"); } else { - _transmitting = true; - onTx(); + transmitting_ = true; + on_tx(); } } inline void rx() { - if (!_transmitting) { + if (!transmitting_) { // Do nothing. Exceptions not active (for Arduino, I assume?). //throw MODE_NOT_TRANSMITTING; USBDEBUG("ERROR - tried to start receiving, but mode already is receiving"); } else { - _transmitting = false; - onRx(); + transmitting_ = false; + on_rx(); } } - inline bool isTx() const { return _transmitting; } - inline bool isRx() const { return !_transmitting; } + inline bool is_tx() const { return transmitting_; } + inline bool is_rx() const { return !transmitting_; } - virtual void setWideRxFilter() = 0; + inline void set_rx_filter(rx_filter f) { + filter_.disable(); + config_.filter = f; + filter_.init(config_.filter_cfg[static_cast(config_.filter)]); + filter_.enable(); + #if defined(DEBUG) + switch(config_.filter) { + case rx_filter::wide: + USBDEBUG("selected wide filter"); + break; - virtual void setMediumRxFilter() = 0; + case rx_filter::medium: + USBDEBUG("selected medium filter"); + break; - virtual void setNarrowRxFilter() = 0; + case rx_filter::narrow: + USBDEBUG("selected narrow filter"); + break; + } + #endif + } private: - mode_config& _config; - RigAudio& _audio; - IFilter& _filter; - bool _active; - bool _transmitting; + mode_config& config_; + RigAudio& audio_; + bp_filter& filter_; + bool active_; + bool transmitting_; }; //====================================================================== -// SSBMode +// ssb_mode //====================================================================== -class SSBMode : public IMode +class ssb_mode : public basic_mode { public: - SSBMode(mode_config& c, RigAudio& a, IFilter& f, bool default_mic=true): - IMode(c, a, f), _use_mic(default_mic) - { - } + ssb_mode(ssb_config& c, RigAudio& a, bp_filter& f, speech_comp& s, bool default_mic=true) : + basic_mode(c, a, f), use_mic_(default_mic), comp_(s) {} - virtual void onEntry() + virtual void on_entry() { - setWideRxFilter(); + set_rx_filter(config().filter); + if (comp_.is_enabled()) { + enable_comp(); + } audio().unmuteRx(); audio().muteAllTx(); USBDEBUG("SSB mode entered"); } - virtual void onExit() { + virtual void on_exit() { audio().muteAllTx(); audio().muteRx(); + disable_comp(); USBDEBUG("SSB mode exited"); } - virtual void onTx() + virtual void on_tx() { audio().muteRx(); - if (_use_mic) { + if (use_mic_) { audio().unmuteMicIn(); } else { audio().unmuteLineIn(); @@ -155,9 +168,9 @@ class SSBMode : public IMode USBDEBUG("SSB mode transmitting"); } - virtual void onRx() + virtual void on_rx() { - if (_use_mic) { + if (use_mic_) { audio().muteMicIn(); } else { audio().muteLineIn(); @@ -166,137 +179,100 @@ class SSBMode : public IMode USBDEBUG("SSB mode receiving"); } - void setMicIn() + void set_mic_in() { - if (isRx()) { + if (is_rx()) { // can't switch inputs while already transmitting - _use_mic = true; + use_mic_ = true; } USBDEBUG("SSB mode - Mic In set"); } - void setLineIn() + void set_line_in() { - if (isRx()) { + if (is_rx()) { // can't switch inputs while already transmitting - _use_mic = false; + use_mic_ = false; } USBDEBUG("SSB mode - Line In set"); } - virtual void setWideRxFilter() { - ((BPFilter&)filter()).setBand(300.0, 3100.0); - filter().enable(); - USBDEBUG("set wide RX SSB filter"); - } - - virtual void setMediumRxFilter() { - ((BPFilter&)filter()).setBand(500.0, 2900.0); - filter().enable(); - USBDEBUG("set medium RX SSB filter"); - } - - virtual void setNarrowRxFilter() { - ((BPFilter&)filter()).setBand(700.0, 2500.0); - filter().enable(); - USBDEBUG("set narrow RX SSB filter"); - } + inline void enable_comp() { comp_.enable(); } + inline void disable_comp() { comp_.disable(); } private: - bool _use_mic; + bool use_mic_; + speech_comp& comp_; }; //====================================================================== -// DGTMode +// digi_mode //====================================================================== -class DGTMode : public IMode +class digi_mode : public basic_mode { public: - DGTMode(mode_config& c, RigAudio& a, IFilter& f): - IMode(c, a, f) - { - } + digi_mode(digi_config& c, RigAudio& a, bp_filter& f) : + basic_mode(c, a, f) {} - virtual void onEntry() + virtual void on_entry() { - setWideRxFilter(); + set_rx_filter(config().filter); audio().unmuteRx(); audio().muteAllTx(); - USBDEBUG("DGT mode entered"); + USBDEBUG("Digi mode entered"); } - virtual void onExit() { + virtual void on_exit() { audio().muteAllTx(); audio().muteRx(); - USBDEBUG("DGT mode exited"); + USBDEBUG("Digi mode exited"); } - virtual void onTx() + virtual void on_tx() { audio().muteRx(); audio().unmuteUSBIn(); - USBDEBUG("DGT mode transmitting"); + USBDEBUG("Digi mode transmitting"); } - virtual void onRx() + virtual void on_rx() { audio().muteUSBIn(); audio().unmuteRx(); - USBDEBUG("DGT mode receiving"); + USBDEBUG("Digi mode receiving"); } - - virtual void setWideRxFilter(){ - ((BPFilter&)filter()).setBand(300.0, 3100.0); - filter().enable(); - USBDEBUG("set wide RX DGT filter"); - } - - virtual void setMediumRxFilter(){ - ((BPFilter&)filter()).setBand(500.0, 2900.0); - filter().enable(); - USBDEBUG("set medium RX DGT filter"); - } - - virtual void setNarrowRxFilter(){ - ((BPFilter&)filter()).setCenterAndWidth(1500.0, 500.0); - filter().enable(); - USBDEBUG("set narrow RX DGT filter"); - } - }; //====================================================================== -// CWMode +// cw_mode //====================================================================== -class CWMode : public IMode +class cw_mode : public basic_mode { public: - CWMode(mode_config& c, RigAudio& a, IFilter& f): - IMode(c, a, f) - { - } + cw_mode(cw_config& c, RigAudio& a, bp_filter& f): + basic_mode(c, a, f) {} - virtual void onEntry() + virtual void on_entry() { - setWideRxFilter(); + set_rx_filter(config().filter); audio().unmuteRx(); audio().muteAllTx(); USBDEBUG("CW mode entered"); } - virtual void onExit() { + virtual void on_exit() { audio().muteAllTx(); audio().muteRx(); USBDEBUG("CW mode exited"); } - virtual void onTx() + virtual void on_tx() { // Currently not muting Rx, since the uBITX produces it's own // sidetone... but I'm probably going to replace that with a S/W- @@ -304,108 +280,10 @@ class CWMode : public IMode USBDEBUG("CW mode transmitting"); } - virtual void onRx() + virtual void on_rx() { USBDEBUG("CW mode receiving"); } - - virtual void setWideRxFilter(){ - float st = float(((cw_config&)config()).sidetone); - float width = 1000.0; - float low = st - (width * 0.5); - if (low < 300.0) { - low = 300.0; - } - ((BPFilter&)filter()).setBand(low, low + width); - filter().enable(); - USBDEBUG("set wide RX CW filter"); - } - - virtual void setMediumRxFilter(){ - float st = float(((cw_config&)config()).sidetone); - float width = 500.0; - float low = st - (width * 0.5); - if (low < 300.0) { - low = 300.0; - } - ((BPFilter&)filter()).setBand(low, low + width); - filter().enable(); - USBDEBUG("set medium RX CW filter"); - } - - virtual void setNarrowRxFilter(){ - float st = float(((cw_config&)config()).sidetone); - float width = 250.0; - float low = st - (width * 0.5); - if (low < 300.0) { - low = 300.0; - } - ((BPFilter&)filter()).setBand(low, low + width); - filter().enable(); - USBDEBUG("set narrow RX CW filter"); - } - -}; - -//====================================================================== -// TTMode -//====================================================================== - -class TTMode : public IMode -{ - public: - - TTMode(mode_config& c, RigAudio& a, IFilter& f): - IMode(c, a, f) - { - } - - virtual void onEntry() - { - setWideRxFilter(); - audio().unmuteRx(); - audio().muteAllTx(); - USBDEBUG("Test (Two-Tone) mode entered"); - } - - virtual void onExit() { - audio().muteAllTx(); - audio().muteRx(); - USBDEBUG("Test (Two-Tone) mode exited"); - } - - virtual void onTx() - { - audio().muteRx(); - audio().unmuteTTIn(); - USBDEBUG("Test (Two-Tone) mode transmitting"); - } - - virtual void onRx() - { - audio().muteTTIn(); - audio().unmuteRx(); - USBDEBUG("Test (Two-Tone) mode receiving"); - } - - virtual void setWideRxFilter(){ - ((BPFilter&)filter()).setBand(300.0, 3100.0); - filter().enable(); - USBDEBUG("set wide RX TT filter"); - } - - virtual void setMediumRxFilter(){ - ((BPFilter&)filter()).setBand(500.0, 2900.0); - filter().enable(); - USBDEBUG("set medium RX TT filter"); - } - - virtual void setNarrowRxFilter(){ - ((BPFilter&)filter()).setBand(700.0, 2500.0); - filter().enable(); - USBDEBUG("set narrow RX TT filter"); - } - }; #endif diff --git a/ubitx_iop/TxSwitch.h b/ubitx_iop/TxSwitch.h index 57c2693..4202e54 100644 --- a/ubitx_iop/TxSwitch.h +++ b/ubitx_iop/TxSwitch.h @@ -29,12 +29,12 @@ class ITxSwitch virtual ~ITxSwitch() {} // Called before beginning transmit; if false, transmit aborts before starting. - virtual bool onPress(IMode* m) = 0; + virtual bool onPress(basic_mode* m) = 0; // Called before stopping tranmit; if false, transmit continues. - virtual bool onRelease(IMode* m) = 0; + virtual bool onRelease(basic_mode* m) = 0; - void press(IMode* m, bool output_enable=true) { + void press(basic_mode* m, bool output_enable=true) { if (onPress(m)) { USBDEBUG("PTT pressed"); m->tx(); @@ -44,7 +44,7 @@ class ITxSwitch } } - void release(IMode* m, bool output_enable=true) { + void release(basic_mode* m, bool output_enable=true) { if (onRelease(m)) { USBDEBUG("PTT released"); if (output_enable) { @@ -68,10 +68,10 @@ class CATSwitch : public ITxSwitch public: CATSwitch(): _transmitting(false) {} - virtual bool onPress(IMode* m) { + virtual bool onPress(basic_mode* m) { // If another transmission is already occuring, abort... CAT can't // interrupt transmissions already ongoing. - if (m->isRx()) { + if (m->is_rx()) { USBDEBUG("CAT PTT pressed"); _transmitting = true; return true; @@ -80,7 +80,7 @@ class CATSwitch : public ITxSwitch } } - virtual bool onRelease(IMode* m) { + virtual bool onRelease(basic_mode* m) { // If CAT transmission is not occurring, abort... CAT can't stop // transmissions initiated by other sources. We don't check if // the mode is already transmitting, because it could be @@ -98,90 +98,6 @@ class CATSwitch : public ITxSwitch bool _transmitting; // CAT-specific transmission }; -/* -//---------------------------------------------------------------------- -// MicSwitch -// -// Implementation of the ITxSwitch interface for the Mic (front panel) -// switch. Features: -// - In SSB, it will automatically select the Mic (front panel) input. -// - If already transmitting, press will have no effect. -// - If already transmitting (any mode, source), release will stop -// the transmission... a failsafe. -//---------------------------------------------------------------------- - -class MicSwitch : public ITxSwitch -{ - public: - MicSwitch(): _ssb_mode(false) {} - - inline void setSSBMode(bool flag) { _ssb_mode = flag; } - - virtual bool onPress(IMode* m) { - if (m->isRx()) { - if (_ssb_mode) { - ((SSBMode*)m)->setMicIn(); - } - return true; - } else { - return false; - } - } - - virtual bool onRelease(IMode* m) { - if (m->isTx()) { - return true; - } else { - return false; - } - } - - private: - bool _ssb_mode; -}; - -//---------------------------------------------------------------------- -// LineSwitch -// -// Implementation of the ITxSwitch interface for the Line (rear panel) -// switch. Features: -// - In SSB, it will automatically select the Line (rear panel) input. -// - If already transmitting, press will have no effect. -// - If already transmitting (any mode, source), release will stop -// the transmission... a failsafe. -//---------------------------------------------------------------------- - -class LineSwitch : public ITxSwitch -{ - public: - LineSwitch(): _ssb_mode(false) {} - - inline void setSSBMode(bool flag) { _ssb_mode = flag; } - - virtual bool onPress(IMode* m) { - if (m->isRx()) { - if (_ssb_mode) { - ((SSBMode*)m)->setLineIn(); - } - return true; - } else { - return false; - } - } - - virtual bool onRelease(IMode* m) { - if (m->isTx()) { - return true; - } else { - return false; - } - } - - private: - bool _ssb_mode; -}; -*/ - //---------------------------------------------------------------------- // GPIOSwitch // @@ -201,15 +117,15 @@ class GPIOSwitch : public ITxSwitch inline void setSSBMode(bool flag) { _ssb_mode = flag; } - virtual bool onPress(IMode* m) { - if (m->isRx()) { + virtual bool onPress(basic_mode* m) { + if (m->is_rx()) { if (_ssb_mode) { if (_is_mic) { USBDEBUG("Mic PTT pressed"); - ((SSBMode*)m)->setMicIn(); + ((ssb_mode*)m)->set_mic_in(); } else { USBDEBUG("Line PTT pressed"); - ((SSBMode*)m)->setLineIn(); + ((ssb_mode*)m)->set_line_in(); } } return true; @@ -218,15 +134,15 @@ class GPIOSwitch : public ITxSwitch } } - virtual bool onRelease(IMode* m) { - if (m->isTx()) { + virtual bool onRelease(basic_mode* m) { + if (m->is_tx()) { return true; } else { return false; } } - void update(IMode* m, bool output_enable=true) { + void update(basic_mode* m, bool output_enable=true) { _bounce.update(); if (_bounce.fell()) { diff --git a/ubitx_iop/audio.h b/ubitx_iop/audio.h index 0829159..4e110e3 100644 --- a/ubitx_iop/audio.h +++ b/ubitx_iop/audio.h @@ -8,6 +8,8 @@ #define __iop_audio_h__ #include +#include +#include #include "config.h" class RigAudio @@ -49,38 +51,57 @@ class RigAudio //====================================================================== -class IFilter { - public: - virtual ~IFilter() {} - virtual void enable() = 0; - virtual void disable() = 0; -}; - -class BPFilter : public IFilter { +class bp_filter { public: - - BPFilter(double f1, double f2, bool use_center, short int window=-1, short int coeff=-1); - void init(AudioFilterFIR* filter=NULL, short* coefficients=NULL); - void setFreqLo(double f); - void setFreqHi(double f); - void setBand(double f1, double f2); - void setCenter(double c); - void setWidth(double w); - void setCenterAndWidth(double c, double w); - virtual void enable(); - virtual void disable(); + //bp_filter(double f1, double f2, bool use_center, short int window=-1, short int coeff=-1); + bp_filter(); + bp_filter(AudioFilterFIR& f, AudioAmplifier& a); + void init(const bpf_config& cfg); + //void init(AudioFilterFIR* filter=NULL, short* coefficients=NULL); + 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 + double freq_lo; + double freq_hi; + short int window; + short int coeff; + float recovery; // recovery amplifier value - AudioFilterFIR* _filter; // = &filterRX; - short* _coefficients; + AudioFilterFIR& filter; // = &filterRX; + AudioAmplifier& amp; + short coefficients[NUM_COEFFICIENTS]; + bool setup_complete; +}; + +//====================================================================== + +class speech_comp +{ + public: + speech_comp(comp_config* cfg); +// speech_comp(AudioEffectCompressor&, AudioAmplifier&, AudioAnalyzeRMS&); + 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; }; //====================================================================== diff --git a/ubitx_iop/audio.ino b/ubitx_iop/audio.ino index 8de1ad0..9015485 100644 --- a/ubitx_iop/audio.ino +++ b/ubitx_iop/audio.ino @@ -8,10 +8,7 @@ #include #include - - #include "audio.h" -#include "tx_audio_proc.h" //short firActive[NUM_COEFFICIENTS]; @@ -266,471 +263,91 @@ TxInput audioTxInput; TxOutput audioTxOutput; */ +//====================================================================== +// bp_filter +// +// Band Pass Filter methods. //====================================================================== -short _internal_coefficients[NUM_COEFFICIENTS]; +bp_filter::bp_filter(): filter(filterRX), amp(filterAmp) {} -BPFilter::BPFilter(double f1, double f2, bool use_center=false, short int window, short int coeff): -_window(window), _coeff(coeff) +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() { - if (window == -1) { - _window = W_HAMMING; - } - if (coeff == -1) { - _coeff = NUM_COEFFICIENTS; - } - if (use_center) { // treat f1 as center frequency, f2 as filter width - _freq_lo = f1 - (0.5 * f2); - _freq_hi = f1 + (0.5 * f2); - } else { - _freq_lo = f1; - _freq_hi = f2; + 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 BPFilter::init(AudioFilterFIR* filter, short* coefficients) { - if (filter == NULL) { - _filter = &filterRX; - } else { - _filter = filter; - } - if (coefficients == NULL) { - _coefficients = _internal_coefficients; - } else { - _coefficients = coefficients; - } - //audioFilter(coefficients, NUM_COEFFICIENTS, ID_BANDPASS, _window, _freq_lo, _freq_hi); - //filter->begin(coefficients, NUM_COEFFICIENTS); -} - -void BPFilter::setFreqLo(double f) { _freq_lo = f; } - -void BPFilter::setFreqHi(double f) { _freq_hi = f; } - -void BPFilter::setBand(double f1, double f2) { - _freq_lo = f1; - _freq_hi = f2; -} - -void BPFilter::setCenter(double c) { - double w = _freq_hi - _freq_lo; - setCenterAndWidth(c, w); -} - -void BPFilter::setWidth(double w) { - double c = (_freq_lo + _freq_hi) * 0.5; - setCenterAndWidth(c, w); -} - -void BPFilter::setCenterAndWidth(double c, double w) { - _freq_lo = c - (0.5 * w); - _freq_hi = c + (0.5 * w); -} - -void BPFilter::enable() { - audioFilter(_coefficients, NUM_COEFFICIENTS, ID_BANDPASS, _window, _freq_lo, _freq_hi); - _filter->begin(_coefficients, NUM_COEFFICIENTS); -} - -void BPFilter::disable() { - _filter->begin(FIR_PASSTHRU, NUM_COEFFICIENTS); -} - //====================================================================== -SpeechCompressor speechCompressor(compTX, compAmp, compRMS); - -//====================================================================== - -/* -// array based on mode right now -BPFilter *rxFilter[NUM_RIG_MODES][NUM_RX_FILTERS]; - -//====================================================================== - -void audioSetupFilters() -{ - rxFilter[RIG_MODE_SSB][FILTER_WIDE] = new BPFilter( 300.0, 3100.0); - rxFilter[RIG_MODE_SSB][FILTER_NORMAL] = new BPFilter( 500.0, 2900.0); - rxFilter[RIG_MODE_SSB][FILTER_NARROW] = new BPFilter( 700.0, 2500.0); - - // Need to make the NARROW filter center frequency configurable. - rxFilter[RIG_MODE_DIGI][FILTER_WIDE] = new BPFilter( 300.0, 3100.0); - rxFilter[RIG_MODE_DIGI][FILTER_NORMAL] = new BPFilter( 500.0, 2900.0); - rxFilter[RIG_MODE_DIGI][FILTER_NARROW] = new BPFilter(1500.0, 500.0, true); - - // Need to use the sidetone frequency for the NORMAL and NARROW filters. - rxFilter[RIG_MODE_CW][FILTER_WIDE] = new BPFilter( 300.0, 1300.0); - rxFilter[RIG_MODE_CW][FILTER_NORMAL] = new BPFilter( 700.0, 500.0, true); - rxFilter[RIG_MODE_CW][FILTER_NARROW] = new BPFilter( 700.0, 250.0, true); -} - -//====================================================================== - -SpeechCompressor speechCompressor(compTX, compAmp, compRMS); - -//====================================================================== - -// audioInit() -// Setup the audio subsystem. -void audioInit() -{ - audioCtrl.enable(); - audioCtrl.muteHeadphone(); // not using the headphone output - audioCtrl.volume(0.0); // not using the headphone output - audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); // required for RX audio - audioCtrl.unmuteLineout(); // required for RX audio - audioCtrl.lineInLevel(rigConfig.rxRigInLevel, rigConfig.txLineInLevel); // NOTE: need to see if this persists through input changes (see mic gain...) - audioCtrl.lineOutLevel(rigConfig.rxLineOutLevel, rigConfig.txRigOutLevel); // NOTE: need to see if this persists through input changes (see mic gain...) - audioCtrl.micGain(rigConfig.txMicInGain); // superfluous, as I have to do this anytime I switch to mic for some reason - //audioCtrl.dacVolumeRamp(); // if this seems too slow, might try dacVolumeRampLinear(). - //audioCtrl.dacVolume(1.0, 0.0); // we're going to mute TX audio via the DAC unless we're transmitting - - updateRxRigIn(); - updateRxSpkrOut(); - updateRxLineOut(); - updateRxUSBOut(); - - // Note - these really just need to be init functions; keep things muted while setting them up. - updateTxMicIn(); - updateTxLineIn(); - updateTxUSBIn(); - updateTxTwoToneIn(); - - updateTxRigOut(); - - audioSelectRxInput(RX_RIG_IN); - audioSelectTxInput(TX_MIC_IN); // superfluous I think - - //audioCtrl.adcHighPassFilterDisable(); - //audioCtrl.audioPreProcessorEnable(); - - // setup the two-tone generator - sine1.frequency(700); - sine2.frequency(1900); - sine1.amplitude(0); - sine2.amplitude(0); - - //audioFilter(firActive, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, 300.0, 3100.0); // 2.8 kHz filter - //filterRX.begin(firActive, NUM_COEFFICIENTS); - filterAmp.gain(1.0); - - // for now, just pass through the compressor - //compTX.disable(); - //compAmp.gain(1.0); - speechCompressor.enable(); -} - - - -//====================================================================== - - -//====================================================================== - -void audioCalibrate(AudioConfig* c, char cmd, char subcmd, char parm, float value, bool set_value=true) -{ - switch(cmd) { - case 'r': - case 'R': - // RX audio parameters - switch(subcmd) { - case 'r': - case 'R': - // Rig input - switch(parm) { - case 'l': - case 'L': - // level - if (set_value) { - c->rxRigInLevel = int(value); - updateRxRigIn(); - } - USBSERIAL.print("rxRigInLevel: "); - USBSERIAL.println(c->rxRigInLevel); - break; - - case 'v': - case 'V': - // volume - if (set_value) { - c->rxRigInVol = value; - updateRxRigIn(); - } - USBSERIAL.print("rxRigInVol: "); - USBSERIAL.println(c->rxRigInVol); - break; - - case 'c': - case 'C': - // calibration - if (set_value) { - c->rxRigInCal = value; - updateRxRigIn(); - } - USBSERIAL.print("rxRigInCal: "); - USBSERIAL.println(c->rxRigInCal); - break; - } - break; - - case 's': - case 'S': - // Speaker output - switch(parm) { - case 'c': - case 'C': - // calibration - if (set_value) { - c->rxSpkrOutCal = value; - updateRxSpkrOut(); - } - USBSERIAL.print("rxSpkrOutCal: "); - USBSERIAL.println(c->rxSpkrOutCal); - break; - } - break; - - case 'l': - case 'L': - // Line output - switch(parm) { - case 'l': - case 'L': - // level - if (set_value) { - c->rxLineOutLevel = int(value); - updateRxLineOut(); - } - USBSERIAL.print("rxLineOutLevel: "); - USBSERIAL.println(c->rxLineOutLevel); - break; - - case 'c': - case 'C': - // calibration - if (set_value) { - c->rxLineOutCal = value; - updateRxLineOut(); - } - USBSERIAL.print("rxLineOutCal: "); - USBSERIAL.println(c->rxLineOutCal); - break; - } - break; - - case 'u': - case 'U': - // USB output - switch(parm) { - case 'c': - case 'C': - // calibration - if (set_value) { - c->rxUSBOutCal = value; - updateRxUSBOut(); - } - USBSERIAL.print("rxUSBOutCal: "); - USBSERIAL.println(c->rxUSBOutCal); - break; - } - break; - } - break; - - case 't': - case 'T': - //TX audio parameters - switch(subcmd) { - case 'm': - case 'M': - // Mic input - switch(parm) { - case 'g': - case 'G': - // mic gain - if (set_value) { - c->txMicInGain = int(value); - updateTxMicIn(); - } - USBSERIAL.print("txMicInGain: "); - USBSERIAL.println(c->txMicInGain); - break; - - case 'v': - case 'V': - // volume - if (set_value) { - c->txMicInVol = value; - updateTxMicIn(); - } - USBSERIAL.print("txMicInVol: "); - USBSERIAL.println(c->txMicInVol); - break; - - case 'c': - case 'C': - // calibration - if (set_value) { - c->txMicInCal = value; - updateTxMicIn(); - } - USBSERIAL.print("txMicInCal: "); - USBSERIAL.println(c->txMicInCal); - break; - } - break; - - case 'l': - case 'L': - // Line input - switch(parm) { - case 'l': - case 'L': - // level - if (set_value) { - c->txLineInLevel = int(value); - updateTxLineIn(); - } - USBSERIAL.print("txLineInLevel: "); - USBSERIAL.println(c->txLineInLevel); - break; - - case 'v': - case 'V': - // volume - if (set_value) { - c->txLineInVol = value; - updateTxLineIn(); - } - USBSERIAL.print("txLineInVol: "); - USBSERIAL.println(c->txLineInVol); - break; - - case 'c': - case 'C': - // calibration - if (set_value) { - c->txLineInCal = value; - updateTxLineIn(); - } - USBSERIAL.print("txLineInCal: "); - USBSERIAL.println(c->txLineInCal); - break; - } - break; - - case 'u': - case 'U': - // USB input - switch(parm) { - case 'v': - case 'V': - // volume - if (set_value) { - c->txUSBInVol = value; - updateTxUSBIn(); - } - USBSERIAL.print("txUSBInVol: "); - USBSERIAL.println(c->txUSBInVol); - break; - - case 'c': - case 'C': - // calibration - if (set_value) { - c->txUSBInCal = value; - updateTxUSBIn(); - } - USBSERIAL.print("txUSBInCal: "); - USBSERIAL.println(c->txUSBInCal); - break; - } - break; - - case 'r': - case 'R': - // Rig output - switch(parm) { - case 'l': - case 'L': - // level - if (set_value) { - c->txRigOutLevel = int(value); - updateTxRigOut(); - } - USBSERIAL.print("txRigOutLevel: "); - USBSERIAL.println(c->txRigOutLevel); - break; - - case 'c': - case 'C': - // calibration - if (set_value) { - c->txRigOutCal = value; - updateTxRigOut(); - } - USBSERIAL.print("txRigOutCal: "); - USBSERIAL.println(c->txRigOutCal); - break; - } - break; - } - break; - } -} - -int lpFilter[5]; -int hpFilter[5]; - -void audioSSBFilter() -{ - // calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*); - calcBiquad(FILTER_LOPASS, 3300, 0, 0.707, 524288, 44100, lpFilter); - calcBiquad(FILTER_HIPASS, 100, 0, 0.707, 524288, 44100, hpFilter); - audioCtrl.eqFilter(0, lpFilter); - audioCtrl.eqFilter(1, hpFilter); - audioCtrl.eqFilter(2, lpFilter); - audioCtrl.eqFilter(3, hpFilter); - audioCtrl.eqFilter(4, lpFilter); - audioCtrl.eqFilter(5, hpFilter); -} - -void audioCWFilter() -{ - // calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*); - calcBiquad(FILTER_LOPASS, 1300, 0, 0.707, 524288, 44100, lpFilter); - calcBiquad(FILTER_HIPASS, 100, 0, 0.707, 524288, 44100, hpFilter); - audioCtrl.eqFilter(0, lpFilter); - audioCtrl.eqFilter(1, hpFilter); - audioCtrl.eqFilter(2, lpFilter); - audioCtrl.eqFilter(3, hpFilter); - audioCtrl.eqFilter(4, lpFilter); - audioCtrl.eqFilter(5, hpFilter); -} - -//====================================================================== -// audioDigiFilter() -// Create a very wide filter for digital modes... wider than the uBITX -// needs, but just want to make sure we leave the full audio bandwidth -// open for digimodes, while ensuring we've cut down any extraneous -// noise outside the normal band. -//====================================================================== - -void audioDigiFilter() -{ - // calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*); - calcBiquad(FILTER_LOPASS, 5000, 0, 0.707, 524288, 44100, lpFilter); - calcBiquad(FILTER_HIPASS, 100, 0, 0.707, 524288, 44100, hpFilter); - audioCtrl.eqFilter(0, lpFilter); - audioCtrl.eqFilter(1, hpFilter); - audioCtrl.eqFilter(2, lpFilter); - audioCtrl.eqFilter(3, hpFilter); - audioCtrl.eqFilter(4, lpFilter); - audioCtrl.eqFilter(5, hpFilter); -} -*/ - int eqFilter1[5]; void audioEqualizer() diff --git a/ubitx_iop/cat.ino b/ubitx_iop/cat.ino index 11a2216..6b5944d 100644 --- a/ubitx_iop/cat.ino +++ b/ubitx_iop/cat.ino @@ -10,7 +10,7 @@ IOPMessage inBuf; // input message buffer IOPMessage outBuf; // output message buffer extern CATSwitch catPTT; -extern Rig rig; +extern basic_rig rig; int received_mode = 0; @@ -57,27 +57,21 @@ void processIOPCommand(IOPMessage const& m) if (m.len < 1) { return; } else { - rig.switchMode(rig_mode(m.data[0])); + rig.set_rig_mode(static_cast(m.data[0])); #if defined(DEBUG) - switch(rig.modeNum()) { - case cwr: - USBDEBUG("new mode - CWR"); - break; - case cw: + switch(rig.get_rig_mode()) { + case rig_mode::cw: USBDEBUG("new mode - CW"); break; - case lsb: - USBDEBUG("new mode - LSB"); + case rig_mode::ssb: + USBDEBUG("new mode - SSB"); break; - case usb: - USBDEBUG("new mode - USB"); - break; - case dig: + case rig_mode::digi: USBDEBUG("new mode - DIG"); break; default: char errormessage[32]; - sprintf(errormessage, "unknown mode command - %3d", rig.modeNum()); + sprintf(errormessage, "unknown mode command - %3d", rig.get_rig_mode()); USBDEBUG("mode command not recognized"); } #endif diff --git a/ubitx_iop/config.h b/ubitx_iop/config.h index a9a7f6f..38b619f 100644 --- a/ubitx_iop/config.h +++ b/ubitx_iop/config.h @@ -120,13 +120,12 @@ class RigConfig { AudioConfig audio; // mode configuration - ssb_config ssb; - dig_config dig; - cw_config cw; + ssb_config ssb; + digi_config digi; + cw_config cw; // General rig configuration entries. - rig_mode numModes = num_rig_modes; - rig_mode startMode = lsb; + rig_mode mode = rig_mode::ssb; }; extern RigConfig rigConfig; diff --git a/ubitx_iop/menu.h b/ubitx_iop/menu.h index 43e0eb5..ffc8ad6 100644 --- a/ubitx_iop/menu.h +++ b/ubitx_iop/menu.h @@ -13,9 +13,6 @@ //#include #include #include "rig.h" -#include "tx_audio_proc.h" - -extern SpeechCompressor speechCompressor; // This should be somewhere else. // 16 characters on display const int MAX_TEXT_LEN = 16; @@ -211,11 +208,9 @@ class Parm_float : public Config_parm { //====================================================================== const char modeID[] = {'s', 'S', 'c', 'C', 'd', 'D', 't', 'T'}; -const char* const filterID[num_rig_modes][num_rx_filters] = { - {"2.8", "2.4", "1.8"}, // LSB - {"2.8", "2.4", "1.8"}, // USB +const char* const filterID[static_cast(rig_mode::count)][static_cast(rx_filter::count)] = { + {"2.8", "2.4", "1.8"}, // SSB {"1.0", "500", "250"}, // CW - {"1.0", "500", "250"}, // CWR {"2.8", "2.4", "500"}, // DIG }; @@ -226,7 +221,7 @@ const char* const filterID[num_rig_modes][num_rx_filters] = { class Main_menu : public Menu_item { public: - Main_menu(Rig& rig): menu_title("Main Menu"), rig(rig), adjust_tx(false), comp_on(false) {} + Main_menu(basic_rig& rig): menu_title("Main Menu"), rig_(rig), adjust_tx(false) {} virtual const Menu_string& title() const { return menu_title; @@ -240,33 +235,12 @@ class Main_menu : public Menu_item { char text[max_text_len+1]; sprintf(text, "%1cR:%3s %1cT:%3s ", adjust_tx ? ' ' : menu_selection_char, - filterID[rig.modeNum()][rig.filterNum()], + filterID[static_cast(rig_.get_rig_mode())][static_cast(rig_.get_rx_filter())], adjust_tx ? menu_selection_char : ' ', - rig.isSSBMode() && comp_on ? "CMP" : " "); + rig_.is_ssb_mode() && rig_.config().ssb.comp.enabled ? "CMP" : " "); outstr.assign(text); } -/* - virtual void update() { - sprintf(_text0, "%1cR:%3s %1cT:%3s ", - _adjust_tx ? ' ' : MENU_SELECTED_CHAR, - filterID[_rig.modeNum()][_rig.filterNum()], - _adjust_tx ? MENU_SELECTED_CHAR : ' ', - _rig.isSSBMode() && _comp_on ? "CMP" : " "); - if ((strcmp(_text0, _text1) != 0) || _dirty) { - if (_visible) { - sendIOPMenuDisplay(_text0); - USBDEBUG("updating menu:"); - USBDEBUG(_text0); - } else { - sendIOPMenuInactive(); - USBDEBUG("deactivating menu"); - } - _dirty = false; - strncpy(_text1, _text0, MAX_TEXT_LEN); - } - } -*/ virtual Menu_item* select() { adjust_tx = !adjust_tx; return this; @@ -282,79 +256,40 @@ class Main_menu : public Menu_item { virtual Menu_item* prev() { if (adjust_tx) { - if (rig.isSSBMode()) { - comp_on = !comp_on; - if (comp_on) - speechCompressor.enable(); + if (rig_.is_ssb_mode()) { + rig_.config().ssb.comp.enabled = !rig_.config().ssb.comp.enabled; + if (rig_.config().ssb.comp.enabled) + rig_.enable_comp(); else - speechCompressor.disable(); + rig_.disable_comp(); } } else { - rig.switchRxFilter(true); + rig_.prev_rx_filter(); } return this; } virtual Menu_item* next() { if (adjust_tx) { - if (rig.isSSBMode()) { - comp_on = !comp_on; - if (comp_on) - speechCompressor.enable(); + if (rig_.is_ssb_mode()) { + rig_.config().ssb.comp.enabled = !rig_.config().ssb.comp.enabled; + if (rig_.config().ssb.comp.enabled) + rig_.enable_comp(); else - speechCompressor.disable(); + rig_.disable_comp(); } } else { - rig.switchRxFilter(); + rig_.next_rx_filter(); } return this; } private: Menu_string menu_title; - Rig& rig; + basic_rig& rig_; bool adjust_tx; - bool comp_on; }; -/* -public class MenuItem { - public: - MenuItem(bool active = true, int timeout = 0): _active(active), _timeout(timeout), _elapsed(0) {} - void update() { - if ((_timeout > 0) && (_elapsed > _timeout)) { - _active = false; - } - } - inline void activate() { _active = true; _elapsed = 0; } - inline void deactivate() { _active = false; } - virtual MenuItem* accept(); - virtual MenuItem* reject(); - virtual MenuItem* next(); - virtual MenuItem* prev(); - - private: - bool _active; - int _timeout; - elapsedMillis _elapsed; -}; - -public class SSBMenu { - public: - private: -}; - -public class DigiMenu { - public: - private: -} - -public class CWMenu { - public: - private: -}; -*/ - extern const Menu_item* audio_config_menu; #endif diff --git a/ubitx_iop/rig.h b/ubitx_iop/rig.h index d1a71d0..31d416f 100644 --- a/ubitx_iop/rig.h +++ b/ubitx_iop/rig.h @@ -8,143 +8,80 @@ #include #include "audio.h" #include "RigMode.h" -//#include "menu.h" //====================================================================== -// Rig class +// basic_rig //====================================================================== -class Rig { +class basic_rig { public: //-------------------------------------------------------------------- // Constructor/destructor. //-------------------------------------------------------------------- - Rig(RigConfig& c, RigAudio& a): _config(c), _audio(a), _filter(wide) - { - _modes = new IMode*[c.numModes]; - _modesLen = c.numModes; - _modesIndex = c.startMode; + basic_rig(RigConfig& c, RigAudio& a) : + config_(c), audio_(a), + bpf_(), + comp_(&config_.ssb.comp), + ssb_ (config_.ssb, audio_, bpf_, comp_), + cw_ (config_.cw, audio_, bpf_), + digi_(config_.digi, audio_, bpf_) { set_rig_mode(config_.mode); } -// for (int i = 0; i < 16; i++) { _modeText[i] = ' '; } -// _modeText[16] = '\0'; -/* _modes[RIG_MODE_LSB] = new SSBMode(c.lsb, a); - _modes[RIG_MODE_USB] = new SSBMode(c.usb, a); - _modes[RIG_MODE_CWL] = new CWMode(c.cwl, a); - _modes[RIG_MODE_CWU] = new CWMode(c.cwu, a); - _modes[RIG_MODE_DGL] = new DGTMode(c.dgl, a); - _modes[RIG_MODE_DGU] = new DGTMode(c.dgu, a); - _modes[RIG_MODE_TTL] = new TTMode(c.ttl, a); - _modes[RIG_MODE_TTU] = new TTMode(c.ttu, a);*/ -/* - _rxFilters = new (IFilter*)[num_rx_filters]; - _rxFiltersLen = num_rx_filters; - _rxFiltersIndex = 0; // need to get default filter from current mode... - _rxFilters[wide] = mode()->filterWide(); - _rxFilters[medium] = mode()->filterMedium(); - _rxFilters[narrow] = mode()->filterNarrow(); -*/ - } - - ~Rig() - { - for (unsigned i = 0; i < _modesLen; i++) { - delete _modes[i]; - } - delete _modes; - } - - void init() { - switchRxFilter(_filter); - } + void init() {} + RigConfig& config() { return config_; } + //-------------------------------------------------------------------- // Mode control. //-------------------------------------------------------------------- -/* - const char* modeText() { - sprintf(_modeText, "%1c- %6s %6s", modeID[_modesIndex], - mode()->rxInfo(), mode()->txInfo()); - return _modeText; - } -*/ - inline bool isSSBMode() const { return (_modesIndex == usb || _modesIndex == lsb); } -// inline bool isUSBMode() const { return (_modesIndex == usb); } -// inline bool isLSBMode() const { return (_modesIndex == lsb); } - inline bool isDIGMode() const { return (_modesIndex == dig); } - inline bool isCWMode() const { return (_modesIndex == cw || _modesIndex == cwr); } -// inline bool isCWUMode() const { return (_modesIndex == RIG_MODE_CWU); } -// inline bool isCWLMode() const { return (_modesIndex == RIG_MODE_CWL); } - // Assign a pointer to a mode object. Returns true if successful, false otherwise. - bool addNewMode(rig_mode i, IMode* mode) { - if (i > _modesLen) { - return false; - } else { - _modes[i] = mode; - return true; - } - } - - // Returns a pointer to the current mode. - inline IMode* mode() const { - return _modes[_modesIndex]; - } + inline bool is_ssb_mode() const { return (config_.mode == rig_mode::ssb ); } + inline bool is_digi_mode() const { return (config_.mode == rig_mode::digi); } + inline bool is_cw_mode() const { return (config_.mode == rig_mode::cw ); } - // Returns the array index of the current mode. - inline rig_mode modeNum() const { - return _modesIndex; - } - -/* // Returns a pointer to the specified mode. - inline IMode* mode(RigMode m) const { - return _modes[m]; - }*/ - - // Switch to the mode specified by the provided index. Returns a - // pointer to the new mode. - IMode* switchMode(rig_mode i) { + // Switch to the specified mode. Returns a pointer to the new mode. + basic_mode* set_rig_mode(rig_mode m) { // exit the previous mode - mode()->exit(); // NOTE: This could currently occur during TX, which is NOT desirable. + current_mode_->exit(); // NOTE: This could currently occur during TX, which is NOT desirable. // select the new mode - _modesIndex = rig_mode(i % _modesLen); + config_.mode = m; + + switch(config_.mode) { + case rig_mode::ssb: + current_mode_ = &ssb_; + break; + + case rig_mode::cw: + current_mode_ = &cw_; + break; + + case rig_mode::digi: + current_mode_ = &digi_; + break; + } //enter the new mode - mode()->enter(); + current_mode_->enter(); // return a pointer to the new mode - return mode(); + return current_mode_; } - // Advance to the next (or previous) mode. Returns a pointer to the - // new mode. - IMode* switchMode(bool prev=false) { + // Returns the rig_mode (enum) of the current mode object. + inline rig_mode get_rig_mode() const { return config_.mode; } - // exit the previous mode - mode()->exit(); - // select the new mode - if (prev) { - _modesIndex = rig_mode(_modesIndex > 0 ? _modesIndex - 1 : _modesLen - 1); - } else { - _modesIndex = rig_mode((_modesIndex + 1) % _modesLen); - } - - // enter the new mode - mode()->enter(); - - // return a pointer to the new mode - return mode(); - } + // Returns a pointer to the current mode object. + inline basic_mode* mode() const { return current_mode_; } //-------------------------------------------------------------------- // Transmit/Receive (T/R) control. //-------------------------------------------------------------------- - inline bool isTx() const { return mode()->isTx(); } - inline bool isRx() const { return mode()->isRx(); } + inline bool is_tx() const { return mode()->is_tx(); } + inline bool is_rx() const { return mode()->is_rx(); } // Enter the transmit state. This is delegated to the mode. inline void tx() { mode()->tx(); } @@ -156,178 +93,144 @@ class Rig { // Transmit processor control. //-------------------------------------------------------------------- - void switchProcessor(bool prev=false) { - + inline void enable_comp() { + if (is_ssb_mode()) ((ssb_mode*)mode())->enable_comp(); + } + + inline void disable_comp() { + if (is_ssb_mode()) ((ssb_mode*)mode())->disable_comp(); } //-------------------------------------------------------------------- // RX filter control. //-------------------------------------------------------------------- - inline void setWideRxFilter() { - _filter = wide; - mode()->setWideRxFilter(); - USBDEBUG("selected wide RX filter"); - } + // Set the RX filter. This is delegated to the mode. + inline void set_rx_filter(rx_filter f) { mode()->set_rx_filter(f); } - inline void setMediumRxFilter() { - _filter = medium; - mode()->setMediumRxFilter(); - USBDEBUG("selected medium RX filter"); - } + // Returns the rx_filter (enum) of the RX filter currently being used. + inline rx_filter get_rx_filter() const { return mode()->config().filter; } - inline void setNarrowRxFilter() { - _filter = narrow; - mode()->setNarrowRxFilter(); - USBDEBUG("selected narrow RX filter"); - } - - void switchRxFilter(rx_filter f) { - switch(f) { - case wide: - setWideRxFilter(); + void next_rx_filter() { + switch(mode()->config().filter) { + case rx_filter::wide: + set_rx_filter(rx_filter::medium); break; - case medium: - setMediumRxFilter(); + case rx_filter::medium: + set_rx_filter(rx_filter::narrow); break; - case narrow: - setNarrowRxFilter(); + case rx_filter::narrow: + set_rx_filter(rx_filter::wide); break; } } - void switchRxFilter(bool prev=false) { - rx_filter f; - if (prev) { - f = rx_filter(_filter > 0 ? _filter - 1 : num_rx_filters - 1); - } else { - f = rx_filter((_filter + 1) % num_rx_filters); + void prev_rx_filter() { + switch(mode()->config().filter) { + case rx_filter::wide: + set_rx_filter(rx_filter::narrow); + break; + + case rx_filter::medium: + set_rx_filter(rx_filter::wide); + break; + + case rx_filter::narrow: + set_rx_filter(rx_filter::medium); + break; } - switchRxFilter(f); } - // Returns the array index of the current mode. - inline rx_filter filterNum() const { - return _filter; - } - -/* - // Returns a pointer to the current RX filter. - IFilter* rxFilter() { - return _rxFilters[_rxFiltersIndex]; - } - - IFilter* switchRxFilter(bool prev=false) { - if (prev) { - _rxFiltersIndex--; - } else { - _rxFiltersIndex++; - } - _rxFiltersIndex %= _rxFiltersLen; - return _rxFiltersList[_rxFiltersIndex]; - } - - IFilter* switchRxFilterWide() { - } - - IFilter* switchFilterMedium() { - - } - - IFilter* switchFilterNarrow() { - - } -*/ + //-------------------------------------------------------------------- // Audio output control. + //-------------------------------------------------------------------- inline void muteSpkrOut() const { - _audio.muteSpkrOut(); + audio_.muteSpkrOut(); } inline void unmuteSpkrOut() const { - _audio.unmuteSpkrOut(); + audio_.unmuteSpkrOut(); } inline void muteLineOut() const { - _audio.muteLineOut(); + audio_.muteLineOut(); } inline void unmuteLineOut() const { - _audio.unmuteLineOut(); + audio_.unmuteLineOut(); } inline void muteUSBOut() const { - _audio.muteUSBOut(); + audio_.muteUSBOut(); } inline void unmuteUSBOut() const { - _audio.unmuteUSBOut(); + audio_.unmuteUSBOut(); } + //-------------------------------------------------------------------- // Audio input control. + //-------------------------------------------------------------------- inline void muteAllTx() const { - _audio.muteAllTx(); + audio_.muteAllTx(); } inline void muteMicIn() const { - _audio.muteMicIn(); + audio_.muteMicIn(); } inline void unmuteMicIn() const { - _audio.unmuteMicIn(); + audio_.unmuteMicIn(); } inline void muteLineIn() const { - _audio.muteLineIn(); + audio_.muteLineIn(); } inline void unmuteLineIn() const { - _audio.unmuteLineIn(); + audio_.unmuteLineIn(); } inline void muteUSBIn() const { - _audio.muteUSBIn(); + audio_.muteUSBIn(); } inline void unmuteUSBIn() const { - _audio.unmuteUSBOut(); + audio_.unmuteUSBOut(); } inline void muteTTIn() const { - _audio.muteTTIn(); + audio_.muteTTIn(); } inline void unmuteTTIn() const { - _audio.unmuteTTIn(); + audio_.unmuteTTIn(); } // Update the rig state. This should be called once each time through // the main loop. void update() { + comp_.update(); // It checks if it's enabled on its own. } private: - RigConfig& _config; - RigAudio& _audio; + RigConfig& config_; + RigAudio& audio_; - IMode** _modes; - rig_mode _modesLen; - rig_mode _modesIndex; + bp_filter bpf_; + speech_comp comp_; - rx_filter _filter; + ssb_mode ssb_; + cw_mode cw_; + digi_mode digi_; -// char _modeText[17]; - -/* - IFilter** _rxFilters; - uint8_t _rxFiltersLen; - uint8_t _rxFiltersIndex; -*/ + basic_mode* current_mode_; }; #endif diff --git a/ubitx_iop/tx_audio_proc.h b/ubitx_iop/tx_audio_proc.h deleted file mode 100644 index 9df9834..0000000 --- a/ubitx_iop/tx_audio_proc.h +++ /dev/null @@ -1,46 +0,0 @@ -//====================================================================== -// tx_audio_proc.h -// -// Classes/functions for processing transmit audio. -//====================================================================== - -#ifndef __tx_audio_proc_h__ -#define __tx_audio_proc_h__ - -#include -#include - -class IAudioProcessor -{ - public: - virtual ~IAudioProcessor() {} - virtual bool isEnabled() const = 0; - virtual void enable() = 0; - virtual void disable() = 0; - virtual void update() = 0; -}; - -class SpeechCompressor : public IAudioProcessor -{ - public: - SpeechCompressor(AudioEffectCompressor&, AudioAmplifier&, AudioAnalyzeRMS&); - //void config(AudioEffectCompressor*, AudioAnalyzeRMS*); - virtual bool isEnabled() const; - virtual void enable(); - virtual void disable(); - virtual void update(); - - private: - AudioEffectCompressor& _compress; - AudioAmplifier& _amp; - AudioAnalyzeRMS& _rms; - float _env = 0.0; - float _alpha = 0.8; - bool _enabled = false; -}; - -#endif - -//====================================================================== -// EOF -//====================================================================== diff --git a/ubitx_iop/tx_audio_proc.ino b/ubitx_iop/tx_audio_proc.ino deleted file mode 100644 index 218915e..0000000 --- a/ubitx_iop/tx_audio_proc.ino +++ /dev/null @@ -1,53 +0,0 @@ -//====================================================================== -// tx_audio_proc.ino -// -// Classes/functions for processing transmit audio. -//====================================================================== - -#include "tx_audio_proc.h" - -SpeechCompressor::SpeechCompressor(AudioEffectCompressor& comp, AudioAmplifier& amp, AudioAnalyzeRMS& rms): -_compress(comp), _amp(amp), _rms(rms) -{ -} - -//void SpeechCompressor::config(AudioEffectCompressor* comp, AudioAnalyzeRMS* rms) -//{ -// _compress = comp; -// _rms = rms; -//} - -bool SpeechCompressor::isEnabled() const -{ - return _enabled; -} - -void SpeechCompressor::enable() -{ - _enabled = true; - _compress.begin(1, 0.1, 20); // Need to make configurable - _amp.gain(2.0); -} - -void SpeechCompressor::disable() -{ - _enabled = false; - _compress.disable(); - _amp.gain(1.0); -} - -// Speech compressor code based on post by 'hyperdyne': https://forum.pjrc.com/threads/36245-Changing-Pitch-of-Voice - -void SpeechCompressor::update() -{ - float rms_cur; - if (_enabled && _rms.available()) { - rms_cur = _rms.read(); - _env = rms_cur + (_alpha * (_env - rms_cur)); - _compress.update_pwr(_env); - } -} - -//====================================================================== -// EOF -//====================================================================== diff --git a/ubitx_iop/ubitx_iop.ino b/ubitx_iop/ubitx_iop.ino index 25b531e..f4e29f3 100644 --- a/ubitx_iop/ubitx_iop.ino +++ b/ubitx_iop/ubitx_iop.ino @@ -16,13 +16,7 @@ Keyer keyer{15, 3.0}; // NOTE: make configurable RigConfig rigConfig; RigAudio rigAudio{rigConfig.audio}; -Rig rig{rigConfig, rigAudio}; - -BPFilter rxFilter{300, 3100, false}; - -SSBMode ssbMode{rigConfig.ssb, rigAudio, rxFilter}; -DGTMode digMode{rigConfig.dig, rigAudio, rxFilter}; -CWMode cwMode {rigConfig.cw, rigAudio, rxFilter}; +basic_rig rig{rigConfig, rigAudio}; CATSwitch catPTT; //MicSwitch micPTTHelper; @@ -54,16 +48,6 @@ void setup() { AudioMemory(16); // NOTE: Need to fine tune this. Have had errors due to this being too low. - // initialize the filter(s) - rxFilter.init(); - - // adding all of the modes to the rig - rig.addNewMode(lsb, &ssbMode); - rig.addNewMode(usb, &ssbMode); - rig.addNewMode(cw, &cwMode); - rig.addNewMode(cwr, &cwMode); - rig.addNewMode(dig, &digMode); - initKeyLine(); rigAudio.init(); @@ -78,14 +62,6 @@ void setup() { rig.init(); USBDEBUG("setup completed"); -// audioInit(); -/* -#if defined(FACTORY_CALIBRATION) - setRigMode(RIG_MODE_TEST); -#else - setRigMode(RIG_MODE_SSB); -#endif -*/ } //====================================================================== @@ -118,13 +94,13 @@ void loop() frameCounter++; - if (rig.isCWMode()) { + 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.isRx()) { + if (rig.is_rx()) { USBDEBUG("entered TX via paddles"); rig.tx(); } @@ -154,21 +130,21 @@ void loop() rig.update(); - oldRigMode = rig.modeNum(); + 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.isSSBMode()); - micPTT.update(rig.mode(), !rig.isDIGMode()); + 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.isSSBMode()); - linePTT.update(rig.mode(), !rig.isDIGMode()); + linePTT.setSSBMode(rig.is_ssb_mode()); + linePTT.update(rig.mode(), !rig.is_digi_mode()); serviceCAT(); @@ -237,9 +213,7 @@ void loop() USBDEBUG("updated main menu"); } - // update the speech compressor. Really should do this elsewhere. - if (speechCompressor.isEnabled()) - speechCompressor.update(); + rig.update(); if (frameMillis > 5000) { #if defined(DEBUG)