Insanely, this also compiles.

Numerous changes updating modes, rig, config, everything... don't think
this ones gonna work first time through...
This commit is contained in:
Rob French 2020-06-14 00:11:18 -05:00
parent 2da162f7c2
commit 6581a5f2a4
12 changed files with 426 additions and 1287 deletions

View File

@ -97,41 +97,39 @@ enum MessageID {
* (e.g. USB, LSB, etc.) * (e.g. USB, LSB, etc.)
*/ */
enum rig_mode { enum struct rig_mode {
lsb = 0, ssb = 0,
usb,
cw, cw,
cwr, digi,
dig,
// add new items here // add new items here
num_rig_modes count
}; };
/* Keyer modes. /* Keyer modes.
*/ */
enum keyer_mode { enum struct keyer_mode {
straight = 0, straight = 0,
iambic_a, iambic_a,
iambic_b, iambic_b,
//ultimatic, //ultimatic,
//bug, //bug,
// add any new items here // add any new items here
num_keyer_modes count
}; };
enum rx_filter { enum struct rx_filter {
wide = 0, wide = 0,
medium, medium,
narrow, narrow,
num_rx_filters count
}; };
enum digi_mode { enum struct digi_submode {
rtty = 0, rtty = 0,
psk31, psk31,
user_defined, user_defined,
num_digi_modes count
}; };
//const unsigned char RIG_MODE_LETTER[num_rig_modes] = {'s', 'S', 'c', 'C', 'd', 'D', 't', 'T'}; //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. // Interface to a configuration object.
//====================================================================== //======================================================================
struct filter_config { struct bpf_config {
float lo; float lo_freq;
float hi; float hi_freq;
float gain; float gain;
}; };
struct mode_config { struct mode_config {
mode_config(bool usb, rx_filter f, const filter_config *fc) : is_usb(usb), filter(f) { mode_config(bool usb, rx_filter f, const bpf_config *fc) : is_usb(usb), filter(f) {
for (int i = 0; i < num_rx_filters; i++) { for (int i = 0; i < static_cast<int>(rx_filter::count); i++) {
filtercfg[i] = fc[i]; filter_cfg[i] = fc[i];
} }
} }
bool is_usb; bool is_usb;
rx_filter filter; rx_filter filter;
filter_config filtercfg[num_rx_filters]; bpf_config filter_cfg[static_cast<size_t>(rx_filter::count)];
}; };
//====================================================================== //======================================================================
// SSB CONFIGURATION // SSB CONFIGURATION
//====================================================================== //======================================================================
const filter_config ssb_filter_config[num_rx_filters] = const bpf_config ssb_filter_config[] =
{filter_config{ 300.0, 3100.0, 1.0}, {bpf_config{ 300.0, 3100.0, 1.0},
filter_config{ 500.0, 2900.0, 1.0}, bpf_config{ 500.0, 2900.0, 1.0},
filter_config{ 700.0, 2500.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 { struct ssb_config : public mode_config {
ssb_config() : mode_config(true, wide, ssb_filter_config) {} ssb_config() : mode_config(true, rx_filter::wide, ssb_filter_config) {}
// speech compressor parameters comp_config comp;
bool comp_enable = false;
float comp_threshold = 0.1;
float comp_ratio = 20.0;
float comp_gain = 2.0;
}; };
//====================================================================== //======================================================================
// DIG CONFIGURATION // DIGI CONFIGURATION
//====================================================================== //======================================================================
const filter_config dig_filter_config[num_rx_filters] = const bpf_config digi_filter_config[] =
{filter_config{ 300.0, 3100.0, 1.0}, {bpf_config{ 300.0, 3100.0, 1.0},
filter_config{ 500.0, 2900.0, 1.0}, bpf_config{ 500.0, 2900.0, 1.0},
filter_config{1250.0, 1750.0, 1.0}}; bpf_config{1250.0, 1750.0, 1.0}};
struct dig_config : public mode_config { struct digi_config : public mode_config {
dig_config() : mode_config(true, wide, dig_filter_config) {} digi_config() : mode_config(true, rx_filter::wide, digi_filter_config) {}
digi_mode submode = user_defined; digi_submode submode = digi_submode::user_defined;
}; };
//====================================================================== //======================================================================
// CW CONFIGURATION // CW CONFIGURATION
//====================================================================== //======================================================================
const filter_config cw_filter_config[num_rx_filters] = const bpf_config cw_filter_config[] =
{filter_config{ 300.0, 1300.0, 1.0}, {bpf_config{ 300.0, 1300.0, 1.0},
filter_config{ 450.0, 950.0, 1.0}, bpf_config{ 450.0, 950.0, 1.0},
filter_config{ 575.0, 825.0, 1.0}}; bpf_config{ 575.0, 825.0, 1.0}};
struct cw_config : public mode_config { struct cw_config : public mode_config {
cw_config() : mode_config(true, wide, cw_filter_config) {} cw_config() : mode_config(true, rx_filter::wide, cw_filter_config) {}
keyer_mode mode = iambic_a; keyer_mode mode = keyer_mode::iambic_a;
// flags // flags
bool reversed = false; bool reversed = false;
// parameters // parameters

View File

@ -7,147 +7,160 @@
#include "audio.h" #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: public:
IMode(mode_config& c, RigAudio& a, IFilter& f): basic_mode(mode_config& c, RigAudio& a, bp_filter& f) :
_config(c), _audio(a), _filter(f), _active(false), _transmitting(false) 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 // 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 // "clean", i.e. that it still needs to enable anything it needs for
// use in the mode. // use in the mode.
virtual void onEntry() = 0; virtual void on_entry() = 0;
// Called upon mode exit. Should clean everything up that it used, // Called upon mode exit. Should clean everything up that it used,
// and not make assumptions about which mode is being entered next. // and not make assumptions about which mode is being entered next.
virtual void onExit() = 0; virtual void on_exit() = 0;
// Called when transmitting. // Called when transmitting.
virtual void onTx() = 0; virtual void on_tx() = 0;
// Called when receiving. // Called when receiving.
virtual void onRx() = 0; virtual void on_rx() = 0;
inline void enter() { inline void enter() {
if (_active) { if (active_) {
// Do nothing. Exceptions not active (for Arduino, I assume?). // Do nothing. Exceptions not active (for Arduino, I assume?).
//throw MODE_ALREADY_ACTIVE; //throw MODE_ALREADY_ACTIVE;
USBDEBUG("ERROR - tried to enter mode, but it's already active"); USBDEBUG("ERROR - tried to enter mode, but it's already active");
} else { } else {
_active = true; active_ = true;
onEntry(); on_entry();
} }
} }
inline void exit() { inline void exit() {
if (_transmitting) { if (transmitting_) {
// Do nothing. Exceptions not active (for Arduino, I assume?). // Do nothing. Exceptions not active (for Arduino, I assume?).
//throw MODE_STILL_TRANSMITTING; //throw MODE_STILL_TRANSMITTING;
USBDEBUG("ERROR - tried to exit mode, but it's transmitting"); USBDEBUG("ERROR - tried to exit mode, but it's transmitting");
} else { } else {
_active = false; active_ = false;
onExit(); on_exit();
} }
} }
inline bool isActive() { return _active; } inline bool is_active() { return active_; }
inline bool isInactive() { return !_active; } inline bool is_inactive() { return !active_; }
inline void tx() { inline void tx() {
if (_transmitting) { if (transmitting_) {
// Do nothing. Exceptions not active (for Arduino, I assume?). // Do nothing. Exceptions not active (for Arduino, I assume?).
//throw MODE_ALREADY_TRANSMITTING; //throw MODE_ALREADY_TRANSMITTING;
USBDEBUG("ERROR - tried to start transmitting, but mode already is transmitting"); USBDEBUG("ERROR - tried to start transmitting, but mode already is transmitting");
} else { } else {
_transmitting = true; transmitting_ = true;
onTx(); on_tx();
} }
} }
inline void rx() { inline void rx() {
if (!_transmitting) { if (!transmitting_) {
// Do nothing. Exceptions not active (for Arduino, I assume?). // Do nothing. Exceptions not active (for Arduino, I assume?).
//throw MODE_NOT_TRANSMITTING; //throw MODE_NOT_TRANSMITTING;
USBDEBUG("ERROR - tried to start receiving, but mode already is receiving"); USBDEBUG("ERROR - tried to start receiving, but mode already is receiving");
} else { } else {
_transmitting = false; transmitting_ = false;
onRx(); on_rx();
} }
} }
inline bool isTx() const { return _transmitting; } inline bool is_tx() const { return transmitting_; }
inline bool isRx() 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<int>(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: private:
mode_config& _config; mode_config& config_;
RigAudio& _audio; RigAudio& audio_;
IFilter& _filter; bp_filter& filter_;
bool _active; bool active_;
bool _transmitting; bool transmitting_;
}; };
//====================================================================== //======================================================================
// SSBMode // ssb_mode
//====================================================================== //======================================================================
class SSBMode : public IMode class ssb_mode : public basic_mode
{ {
public: public:
SSBMode(mode_config& c, RigAudio& a, IFilter& f, bool default_mic=true): ssb_mode(ssb_config& c, RigAudio& a, bp_filter& f, speech_comp& s, bool default_mic=true) :
IMode(c, a, f), _use_mic(default_mic) 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().unmuteRx();
audio().muteAllTx(); audio().muteAllTx();
USBDEBUG("SSB mode entered"); USBDEBUG("SSB mode entered");
} }
virtual void onExit() { virtual void on_exit() {
audio().muteAllTx(); audio().muteAllTx();
audio().muteRx(); audio().muteRx();
disable_comp();
USBDEBUG("SSB mode exited"); USBDEBUG("SSB mode exited");
} }
virtual void onTx() virtual void on_tx()
{ {
audio().muteRx(); audio().muteRx();
if (_use_mic) { if (use_mic_) {
audio().unmuteMicIn(); audio().unmuteMicIn();
} else { } else {
audio().unmuteLineIn(); audio().unmuteLineIn();
@ -155,9 +168,9 @@ class SSBMode : public IMode
USBDEBUG("SSB mode transmitting"); USBDEBUG("SSB mode transmitting");
} }
virtual void onRx() virtual void on_rx()
{ {
if (_use_mic) { if (use_mic_) {
audio().muteMicIn(); audio().muteMicIn();
} else { } else {
audio().muteLineIn(); audio().muteLineIn();
@ -166,137 +179,100 @@ class SSBMode : public IMode
USBDEBUG("SSB mode receiving"); USBDEBUG("SSB mode receiving");
} }
void setMicIn() void set_mic_in()
{ {
if (isRx()) { if (is_rx()) {
// can't switch inputs while already transmitting // can't switch inputs while already transmitting
_use_mic = true; use_mic_ = true;
} }
USBDEBUG("SSB mode - Mic In set"); USBDEBUG("SSB mode - Mic In set");
} }
void setLineIn() void set_line_in()
{ {
if (isRx()) { if (is_rx()) {
// can't switch inputs while already transmitting // can't switch inputs while already transmitting
_use_mic = false; use_mic_ = false;
} }
USBDEBUG("SSB mode - Line In set"); USBDEBUG("SSB mode - Line In set");
} }
virtual void setWideRxFilter() { inline void enable_comp() { comp_.enable(); }
((BPFilter&)filter()).setBand(300.0, 3100.0); inline void disable_comp() { comp_.disable(); }
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");
}
private: private:
bool _use_mic; bool use_mic_;
speech_comp& comp_;
}; };
//====================================================================== //======================================================================
// DGTMode // digi_mode
//====================================================================== //======================================================================
class DGTMode : public IMode class digi_mode : public basic_mode
{ {
public: public:
DGTMode(mode_config& c, RigAudio& a, IFilter& f): digi_mode(digi_config& c, RigAudio& a, bp_filter& f) :
IMode(c, a, f) basic_mode(c, a, f) {}
{
}
virtual void onEntry() virtual void on_entry()
{ {
setWideRxFilter(); set_rx_filter(config().filter);
audio().unmuteRx(); audio().unmuteRx();
audio().muteAllTx(); audio().muteAllTx();
USBDEBUG("DGT mode entered"); USBDEBUG("Digi mode entered");
} }
virtual void onExit() { virtual void on_exit() {
audio().muteAllTx(); audio().muteAllTx();
audio().muteRx(); audio().muteRx();
USBDEBUG("DGT mode exited"); USBDEBUG("Digi mode exited");
} }
virtual void onTx() virtual void on_tx()
{ {
audio().muteRx(); audio().muteRx();
audio().unmuteUSBIn(); audio().unmuteUSBIn();
USBDEBUG("DGT mode transmitting"); USBDEBUG("Digi mode transmitting");
} }
virtual void onRx() virtual void on_rx()
{ {
audio().muteUSBIn(); audio().muteUSBIn();
audio().unmuteRx(); 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: public:
CWMode(mode_config& c, RigAudio& a, IFilter& f): cw_mode(cw_config& c, RigAudio& a, bp_filter& f):
IMode(c, a, f) basic_mode(c, a, f) {}
{
}
virtual void onEntry() virtual void on_entry()
{ {
setWideRxFilter(); set_rx_filter(config().filter);
audio().unmuteRx(); audio().unmuteRx();
audio().muteAllTx(); audio().muteAllTx();
USBDEBUG("CW mode entered"); USBDEBUG("CW mode entered");
} }
virtual void onExit() { virtual void on_exit() {
audio().muteAllTx(); audio().muteAllTx();
audio().muteRx(); audio().muteRx();
USBDEBUG("CW mode exited"); USBDEBUG("CW mode exited");
} }
virtual void onTx() virtual void on_tx()
{ {
// Currently not muting Rx, since the uBITX produces it's own // Currently not muting Rx, since the uBITX produces it's own
// sidetone... but I'm probably going to replace that with a S/W- // 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"); USBDEBUG("CW mode transmitting");
} }
virtual void onRx() virtual void on_rx()
{ {
USBDEBUG("CW mode receiving"); 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 #endif

View File

@ -29,12 +29,12 @@ class ITxSwitch
virtual ~ITxSwitch() {} virtual ~ITxSwitch() {}
// Called before beginning transmit; if false, transmit aborts before starting. // 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. // 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)) { if (onPress(m)) {
USBDEBUG("PTT pressed"); USBDEBUG("PTT pressed");
m->tx(); 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)) { if (onRelease(m)) {
USBDEBUG("PTT released"); USBDEBUG("PTT released");
if (output_enable) { if (output_enable) {
@ -68,10 +68,10 @@ class CATSwitch : public ITxSwitch
public: public:
CATSwitch(): _transmitting(false) {} CATSwitch(): _transmitting(false) {}
virtual bool onPress(IMode* m) { virtual bool onPress(basic_mode* m) {
// If another transmission is already occuring, abort... CAT can't // If another transmission is already occuring, abort... CAT can't
// interrupt transmissions already ongoing. // interrupt transmissions already ongoing.
if (m->isRx()) { if (m->is_rx()) {
USBDEBUG("CAT PTT pressed"); USBDEBUG("CAT PTT pressed");
_transmitting = true; _transmitting = true;
return 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 // If CAT transmission is not occurring, abort... CAT can't stop
// transmissions initiated by other sources. We don't check if // transmissions initiated by other sources. We don't check if
// the mode is already transmitting, because it could be // the mode is already transmitting, because it could be
@ -98,90 +98,6 @@ class CATSwitch : public ITxSwitch
bool _transmitting; // CAT-specific transmission 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 // GPIOSwitch
// //
@ -201,15 +117,15 @@ class GPIOSwitch : public ITxSwitch
inline void setSSBMode(bool flag) { _ssb_mode = flag; } inline void setSSBMode(bool flag) { _ssb_mode = flag; }
virtual bool onPress(IMode* m) { virtual bool onPress(basic_mode* m) {
if (m->isRx()) { if (m->is_rx()) {
if (_ssb_mode) { if (_ssb_mode) {
if (_is_mic) { if (_is_mic) {
USBDEBUG("Mic PTT pressed"); USBDEBUG("Mic PTT pressed");
((SSBMode*)m)->setMicIn(); ((ssb_mode*)m)->set_mic_in();
} else { } else {
USBDEBUG("Line PTT pressed"); USBDEBUG("Line PTT pressed");
((SSBMode*)m)->setLineIn(); ((ssb_mode*)m)->set_line_in();
} }
} }
return true; return true;
@ -218,15 +134,15 @@ class GPIOSwitch : public ITxSwitch
} }
} }
virtual bool onRelease(IMode* m) { virtual bool onRelease(basic_mode* m) {
if (m->isTx()) { if (m->is_tx()) {
return true; return true;
} else { } else {
return false; return false;
} }
} }
void update(IMode* m, bool output_enable=true) { void update(basic_mode* m, bool output_enable=true) {
_bounce.update(); _bounce.update();
if (_bounce.fell()) { if (_bounce.fell()) {

View File

@ -8,6 +8,8 @@
#define __iop_audio_h__ #define __iop_audio_h__
#include <Audio.h> #include <Audio.h>
#include <dynamicFilters.h>
#include <effect_compressor_fb.h>
#include "config.h" #include "config.h"
class RigAudio class RigAudio
@ -49,38 +51,57 @@ class RigAudio
//====================================================================== //======================================================================
class IFilter { class bp_filter {
public:
virtual ~IFilter() {}
virtual void enable() = 0;
virtual void disable() = 0;
};
class BPFilter : public IFilter {
public: public:
//bp_filter(double f1, double f2, bool use_center, short int window=-1, short int coeff=-1);
BPFilter(double f1, double f2, bool use_center, short int window=-1, short int coeff=-1); bp_filter();
void init(AudioFilterFIR* filter=NULL, short* coefficients=NULL); bp_filter(AudioFilterFIR& f, AudioAmplifier& a);
void setFreqLo(double f); void init(const bpf_config& cfg);
void setFreqHi(double f); //void init(AudioFilterFIR* filter=NULL, short* coefficients=NULL);
void setBand(double f1, double f2); void set_band(double f1, double f2);
void setCenter(double c); void set_freq_lo(double f);
void setWidth(double w); void set_freq_hi(double f);
void setCenterAndWidth(double c, double w); void set_center_and_width(double c, double w);
virtual void enable(); void set_center(double c);
virtual void disable(); void set_width(double w);
void set_gain(double g);
void enable();
void disable();
private: private:
double _freq_lo; double freq_lo;
double _freq_hi; double freq_hi;
short int _window; short int window;
short int _coeff; short int coeff;
float _recovery; // recovery amplifier value float recovery; // recovery amplifier value
AudioFilterFIR* _filter; // = &filterRX; AudioFilterFIR& filter; // = &filterRX;
short* _coefficients; 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;
}; };
//====================================================================== //======================================================================

View File

@ -8,10 +8,7 @@
#include <dynamicFilters.h> #include <dynamicFilters.h>
#include <effect_compressor_fb.h> #include <effect_compressor_fb.h>
#include "audio.h" #include "audio.h"
#include "tx_audio_proc.h"
//short firActive[NUM_COEFFICIENTS]; //short firActive[NUM_COEFFICIENTS];
@ -266,471 +263,91 @@ TxInput audioTxInput;
TxOutput audioTxOutput; 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): bp_filter::bp_filter(AudioFilterFIR& f, AudioAmplifier& a): filter(f), amp(a) {}
_window(window), _coeff(coeff)
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) { config_->enabled = true;
_window = W_HAMMING; comp_.begin(1, config_->threshold, config_->ratio); // Need to make configurable
} amp_.gain(config_->gain);
if (coeff == -1) { }
_coeff = NUM_COEFFICIENTS;
} void speech_comp::disable()
if (use_center) { // treat f1 as center frequency, f2 as filter width {
_freq_lo = f1 - (0.5 * f2); config_->enabled = false;
_freq_hi = f1 + (0.5 * f2); comp_.disable();
} else { amp_.gain(1.0);
_freq_lo = f1; }
_freq_hi = f2;
// 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]; int eqFilter1[5];
void audioEqualizer() void audioEqualizer()

View File

@ -10,7 +10,7 @@ IOPMessage inBuf; // input message buffer
IOPMessage outBuf; // output message buffer IOPMessage outBuf; // output message buffer
extern CATSwitch catPTT; extern CATSwitch catPTT;
extern Rig rig; extern basic_rig rig;
int received_mode = 0; int received_mode = 0;
@ -57,27 +57,21 @@ void processIOPCommand(IOPMessage const& m)
if (m.len < 1) { if (m.len < 1) {
return; return;
} else { } else {
rig.switchMode(rig_mode(m.data[0])); rig.set_rig_mode(static_cast<rig_mode>(m.data[0]));
#if defined(DEBUG) #if defined(DEBUG)
switch(rig.modeNum()) { switch(rig.get_rig_mode()) {
case cwr: case rig_mode::cw:
USBDEBUG("new mode - CWR");
break;
case cw:
USBDEBUG("new mode - CW"); USBDEBUG("new mode - CW");
break; break;
case lsb: case rig_mode::ssb:
USBDEBUG("new mode - LSB"); USBDEBUG("new mode - SSB");
break; break;
case usb: case rig_mode::digi:
USBDEBUG("new mode - USB");
break;
case dig:
USBDEBUG("new mode - DIG"); USBDEBUG("new mode - DIG");
break; break;
default: default:
char errormessage[32]; 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"); USBDEBUG("mode command not recognized");
} }
#endif #endif

View File

@ -120,13 +120,12 @@ class RigConfig {
AudioConfig audio; AudioConfig audio;
// mode configuration // mode configuration
ssb_config ssb; ssb_config ssb;
dig_config dig; digi_config digi;
cw_config cw; cw_config cw;
// General rig configuration entries. // General rig configuration entries.
rig_mode numModes = num_rig_modes; rig_mode mode = rig_mode::ssb;
rig_mode startMode = lsb;
}; };
extern RigConfig rigConfig; extern RigConfig rigConfig;

View File

@ -13,9 +13,6 @@
//#include <vector> //#include <vector>
#include <initializer_list> #include <initializer_list>
#include "rig.h" #include "rig.h"
#include "tx_audio_proc.h"
extern SpeechCompressor speechCompressor; // This should be somewhere else.
// 16 characters on display // 16 characters on display
const int MAX_TEXT_LEN = 16; const int MAX_TEXT_LEN = 16;
@ -211,11 +208,9 @@ class Parm_float : public Config_parm<float> {
//====================================================================== //======================================================================
const char modeID[] = {'s', 'S', 'c', 'C', 'd', 'D', 't', 'T'}; const char modeID[] = {'s', 'S', 'c', 'C', 'd', 'D', 't', 'T'};
const char* const filterID[num_rig_modes][num_rx_filters] = { const char* const filterID[static_cast<int>(rig_mode::count)][static_cast<int>(rx_filter::count)] = {
{"2.8", "2.4", "1.8"}, // LSB {"2.8", "2.4", "1.8"}, // SSB
{"2.8", "2.4", "1.8"}, // USB
{"1.0", "500", "250"}, // CW {"1.0", "500", "250"}, // CW
{"1.0", "500", "250"}, // CWR
{"2.8", "2.4", "500"}, // DIG {"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 { class Main_menu : public Menu_item {
public: 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 { virtual const Menu_string& title() const {
return menu_title; return menu_title;
@ -240,33 +235,12 @@ class Main_menu : public Menu_item {
char text[max_text_len+1]; char text[max_text_len+1];
sprintf(text, "%1cR:%3s %1cT:%3s ", sprintf(text, "%1cR:%3s %1cT:%3s ",
adjust_tx ? ' ' : menu_selection_char, adjust_tx ? ' ' : menu_selection_char,
filterID[rig.modeNum()][rig.filterNum()], filterID[static_cast<size_t>(rig_.get_rig_mode())][static_cast<size_t>(rig_.get_rx_filter())],
adjust_tx ? menu_selection_char : ' ', adjust_tx ? menu_selection_char : ' ',
rig.isSSBMode() && comp_on ? "CMP" : " "); rig_.is_ssb_mode() && rig_.config().ssb.comp.enabled ? "CMP" : " ");
outstr.assign(text); 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() { virtual Menu_item* select() {
adjust_tx = !adjust_tx; adjust_tx = !adjust_tx;
return this; return this;
@ -282,79 +256,40 @@ class Main_menu : public Menu_item {
virtual Menu_item* prev() { virtual Menu_item* prev() {
if (adjust_tx) { if (adjust_tx) {
if (rig.isSSBMode()) { if (rig_.is_ssb_mode()) {
comp_on = !comp_on; rig_.config().ssb.comp.enabled = !rig_.config().ssb.comp.enabled;
if (comp_on) if (rig_.config().ssb.comp.enabled)
speechCompressor.enable(); rig_.enable_comp();
else else
speechCompressor.disable(); rig_.disable_comp();
} }
} else { } else {
rig.switchRxFilter(true); rig_.prev_rx_filter();
} }
return this; return this;
} }
virtual Menu_item* next() { virtual Menu_item* next() {
if (adjust_tx) { if (adjust_tx) {
if (rig.isSSBMode()) { if (rig_.is_ssb_mode()) {
comp_on = !comp_on; rig_.config().ssb.comp.enabled = !rig_.config().ssb.comp.enabled;
if (comp_on) if (rig_.config().ssb.comp.enabled)
speechCompressor.enable(); rig_.enable_comp();
else else
speechCompressor.disable(); rig_.disable_comp();
} }
} else { } else {
rig.switchRxFilter(); rig_.next_rx_filter();
} }
return this; return this;
} }
private: private:
Menu_string menu_title; Menu_string menu_title;
Rig& rig; basic_rig& rig_;
bool adjust_tx; 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; extern const Menu_item* audio_config_menu;
#endif #endif

View File

@ -8,143 +8,80 @@
#include <iopcomm.h> #include <iopcomm.h>
#include "audio.h" #include "audio.h"
#include "RigMode.h" #include "RigMode.h"
//#include "menu.h"
//====================================================================== //======================================================================
// Rig class // basic_rig
//====================================================================== //======================================================================
class Rig { class basic_rig {
public: public:
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// Constructor/destructor. // Constructor/destructor.
//-------------------------------------------------------------------- //--------------------------------------------------------------------
Rig(RigConfig& c, RigAudio& a): _config(c), _audio(a), _filter(wide) basic_rig(RigConfig& c, RigAudio& a) :
{ config_(c), audio_(a),
_modes = new IMode*[c.numModes]; bpf_(),
_modesLen = c.numModes; comp_(&config_.ssb.comp),
_modesIndex = c.startMode; 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] = ' '; } void init() {}
// _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);
}
RigConfig& config() { return config_; }
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// Mode control. // 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. inline bool is_ssb_mode() const { return (config_.mode == rig_mode::ssb ); }
bool addNewMode(rig_mode i, IMode* mode) { inline bool is_digi_mode() const { return (config_.mode == rig_mode::digi); }
if (i > _modesLen) { inline bool is_cw_mode() const { return (config_.mode == rig_mode::cw ); }
return false;
} else {
_modes[i] = mode;
return true;
}
}
// Returns a pointer to the current mode.
inline IMode* mode() const {
return _modes[_modesIndex];
}
// Returns the array index of the current mode. // Switch to the specified mode. Returns a pointer to the new mode.
inline rig_mode modeNum() const { basic_mode* set_rig_mode(rig_mode m) {
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) {
// exit the previous mode // 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 // 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 //enter the new mode
mode()->enter(); current_mode_->enter();
// return a pointer to the new mode // return a pointer to the new mode
return mode(); return current_mode_;
} }
// Advance to the next (or previous) mode. Returns a pointer to the // Returns the rig_mode (enum) of the current mode object.
// new mode. inline rig_mode get_rig_mode() const { return config_.mode; }
IMode* switchMode(bool prev=false) {
// exit the previous mode
mode()->exit();
// select the new mode // Returns a pointer to the current mode object.
if (prev) { inline basic_mode* mode() const { return current_mode_; }
_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();
}
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// Transmit/Receive (T/R) control. // Transmit/Receive (T/R) control.
//-------------------------------------------------------------------- //--------------------------------------------------------------------
inline bool isTx() const { return mode()->isTx(); } inline bool is_tx() const { return mode()->is_tx(); }
inline bool isRx() const { return mode()->isRx(); } inline bool is_rx() const { return mode()->is_rx(); }
// Enter the transmit state. This is delegated to the mode. // Enter the transmit state. This is delegated to the mode.
inline void tx() { mode()->tx(); } inline void tx() { mode()->tx(); }
@ -156,178 +93,144 @@ class Rig {
// Transmit processor control. // 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. // RX filter control.
//-------------------------------------------------------------------- //--------------------------------------------------------------------
inline void setWideRxFilter() { // Set the RX filter. This is delegated to the mode.
_filter = wide; inline void set_rx_filter(rx_filter f) { mode()->set_rx_filter(f); }
mode()->setWideRxFilter();
USBDEBUG("selected wide RX filter");
}
inline void setMediumRxFilter() { // Returns the rx_filter (enum) of the RX filter currently being used.
_filter = medium; inline rx_filter get_rx_filter() const { return mode()->config().filter; }
mode()->setMediumRxFilter();
USBDEBUG("selected medium RX filter");
}
inline void setNarrowRxFilter() { void next_rx_filter() {
_filter = narrow; switch(mode()->config().filter) {
mode()->setNarrowRxFilter(); case rx_filter::wide:
USBDEBUG("selected narrow RX filter"); set_rx_filter(rx_filter::medium);
}
void switchRxFilter(rx_filter f) {
switch(f) {
case wide:
setWideRxFilter();
break; break;
case medium: case rx_filter::medium:
setMediumRxFilter(); set_rx_filter(rx_filter::narrow);
break; break;
case narrow: case rx_filter::narrow:
setNarrowRxFilter(); set_rx_filter(rx_filter::wide);
break; break;
} }
} }
void switchRxFilter(bool prev=false) { void prev_rx_filter() {
rx_filter f; switch(mode()->config().filter) {
if (prev) { case rx_filter::wide:
f = rx_filter(_filter > 0 ? _filter - 1 : num_rx_filters - 1); set_rx_filter(rx_filter::narrow);
} else { break;
f = rx_filter((_filter + 1) % num_rx_filters);
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. // Audio output control.
//--------------------------------------------------------------------
inline void muteSpkrOut() const { inline void muteSpkrOut() const {
_audio.muteSpkrOut(); audio_.muteSpkrOut();
} }
inline void unmuteSpkrOut() const { inline void unmuteSpkrOut() const {
_audio.unmuteSpkrOut(); audio_.unmuteSpkrOut();
} }
inline void muteLineOut() const { inline void muteLineOut() const {
_audio.muteLineOut(); audio_.muteLineOut();
} }
inline void unmuteLineOut() const { inline void unmuteLineOut() const {
_audio.unmuteLineOut(); audio_.unmuteLineOut();
} }
inline void muteUSBOut() const { inline void muteUSBOut() const {
_audio.muteUSBOut(); audio_.muteUSBOut();
} }
inline void unmuteUSBOut() const { inline void unmuteUSBOut() const {
_audio.unmuteUSBOut(); audio_.unmuteUSBOut();
} }
//--------------------------------------------------------------------
// Audio input control. // Audio input control.
//--------------------------------------------------------------------
inline void muteAllTx() const { inline void muteAllTx() const {
_audio.muteAllTx(); audio_.muteAllTx();
} }
inline void muteMicIn() const { inline void muteMicIn() const {
_audio.muteMicIn(); audio_.muteMicIn();
} }
inline void unmuteMicIn() const { inline void unmuteMicIn() const {
_audio.unmuteMicIn(); audio_.unmuteMicIn();
} }
inline void muteLineIn() const { inline void muteLineIn() const {
_audio.muteLineIn(); audio_.muteLineIn();
} }
inline void unmuteLineIn() const { inline void unmuteLineIn() const {
_audio.unmuteLineIn(); audio_.unmuteLineIn();
} }
inline void muteUSBIn() const { inline void muteUSBIn() const {
_audio.muteUSBIn(); audio_.muteUSBIn();
} }
inline void unmuteUSBIn() const { inline void unmuteUSBIn() const {
_audio.unmuteUSBOut(); audio_.unmuteUSBOut();
} }
inline void muteTTIn() const { inline void muteTTIn() const {
_audio.muteTTIn(); audio_.muteTTIn();
} }
inline void unmuteTTIn() const { inline void unmuteTTIn() const {
_audio.unmuteTTIn(); audio_.unmuteTTIn();
} }
// Update the rig state. This should be called once each time through // Update the rig state. This should be called once each time through
// the main loop. // the main loop.
void update() void update()
{ {
comp_.update(); // It checks if it's enabled on its own.
} }
private: private:
RigConfig& _config; RigConfig& config_;
RigAudio& _audio; RigAudio& audio_;
IMode** _modes; bp_filter bpf_;
rig_mode _modesLen; speech_comp comp_;
rig_mode _modesIndex;
rx_filter _filter; ssb_mode ssb_;
cw_mode cw_;
digi_mode digi_;
// char _modeText[17]; basic_mode* current_mode_;
/*
IFilter** _rxFilters;
uint8_t _rxFiltersLen;
uint8_t _rxFiltersIndex;
*/
}; };
#endif #endif

View File

@ -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 <Audio.h>
#include <effect_compressor_fb.h>
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
//======================================================================

View File

@ -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
//======================================================================

View File

@ -16,13 +16,7 @@ Keyer keyer{15, 3.0}; // NOTE: make configurable
RigConfig rigConfig; RigConfig rigConfig;
RigAudio rigAudio{rigConfig.audio}; RigAudio rigAudio{rigConfig.audio};
Rig rig{rigConfig, rigAudio}; basic_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};
CATSwitch catPTT; CATSwitch catPTT;
//MicSwitch micPTTHelper; //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. 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(); initKeyLine();
rigAudio.init(); rigAudio.init();
@ -78,14 +62,6 @@ void setup() {
rig.init(); rig.init();
USBDEBUG("setup completed"); 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++; frameCounter++;
if (rig.isCWMode()) { if (rig.is_cw_mode()) {
if (keyer.do_paddles()) { if (keyer.do_paddles()) {
// Checking for T/R separately from the paddle loop, because it's // Checking for T/R separately from the paddle loop, because it's
// possible we're already transmitting (PTT/Key being held), and // 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. // 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"); USBDEBUG("entered TX via paddles");
rig.tx(); rig.tx();
} }
@ -154,21 +130,21 @@ void loop()
rig.update(); 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 // 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 // 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 // need to make it inactive if we're in DGT mode, since only CAT will be
// used to start transmitting in that case. // used to start transmitting in that case.
micPTT.setSSBMode(rig.isSSBMode()); micPTT.setSSBMode(rig.is_ssb_mode());
micPTT.update(rig.mode(), !rig.isDIGMode()); 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 // 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 // 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 // need to make it inactive if we're in DGT mode, since only CAT will be
// used to start transmitting in that case. // used to start transmitting in that case.
linePTT.setSSBMode(rig.isSSBMode()); linePTT.setSSBMode(rig.is_ssb_mode());
linePTT.update(rig.mode(), !rig.isDIGMode()); linePTT.update(rig.mode(), !rig.is_digi_mode());
serviceCAT(); serviceCAT();
@ -237,9 +213,7 @@ void loop()
USBDEBUG("updated main menu"); USBDEBUG("updated main menu");
} }
// update the speech compressor. Really should do this elsewhere. rig.update();
if (speechCompressor.isEnabled())
speechCompressor.update();
if (frameMillis > 5000) { if (frameMillis > 5000) {
#if defined(DEBUG) #if defined(DEBUG)