Updates to the DSP. One issue that needs to be resolved: in order to use the VOX the way it is currently setup, muting of the overall TX chain needs to be at the END, not the beginning; whatever is setup as the default TX audio source, needs to be unmuted even during RX.

This commit is contained in:
Rob French 2021-03-04 23:12:41 -06:00
parent 962a3ce80f
commit 20b475dace
2 changed files with 232 additions and 140 deletions

View File

@ -10,64 +10,59 @@
//#include <SD.h> //#include <SD.h>
//#include <SerialFlash.h> //#include <SerialFlash.h>
#define RX_AUDIO_CH 0 const int rxRigInChannel = RX_RIG_IN_CH;
const int txMicInChannel = TX_MIC_IN_CH; const int txMicInChannel = TX_MIC_IN_CH;
const int txLineInChannel = TX_LINE_IN_CH; const int txLineInChannel = TX_LINE_IN_CH;
const int txUSBInChannel = TX_USB_IN_CH; const int txUSBInChannel = TX_USB_IN_CH;
const int txNumChannels = TX_NUM_CHANNELS; const int txNumChannels = TX_NUM_CHANNELS;
const int txLineInVOX = TX_LINE_IN_VOX;
const int txUSBInLVOX = TX_USB_IN_L_VOX;
const int txUSBInRVOX = TX_USB_IN_R_VOX;
const int txNumVOX = TX_NUM_VOX;
UBitxDSP DSP; UBitxDSP DSP;
//static struct { //static struct {
// GUItool: begin automatically generated code // GUItool: begin automatically generated code
AudioInputUSB usbIn; //xy=153,341 AudioInputUSB usbIn; //xy=161,313
AudioInputI2S lineIn; //xy=161,233 AudioInputI2S lineIn; //xy=169,205
AudioAnalyzeRMS usbInRMS_R; //xy=276,431 AudioSynthWaveformSine tone1; //xy=234,386
AudioAnalyzeRMS usbInRMS_L; //xy=335,392 AudioSynthWaveformSine tone2; //xy=234,422
AudioAnalyzeRMS lineInRMS; //xy=387,273 AudioMixer4 rxAudio; //xy=426,119
AudioMixer4 rxAudio; //xy=418,147 AudioMixer4 txAudio; //xy=430,307
AudioMixer4 txAudio; //xy=422,335 AudioAnalyzeRMS txVoxLevel; //xy=588,348
AudioFilterFIR rxFilter; //xy=583,139 AudioFilterFIR rxFilter; //xy=591,111
AudioAmplifier usbOutAmp; //xy=748,135 AudioAmplifier usbOutAmp; //xy=756,107
AudioAmplifier lineOutAmp; //xy=749,198 AudioAmplifier lineOutAmp; //xy=757,170
AudioAmplifier usbBypassAmp; //xy=756,261 AudioAmplifier usbBypassAmp; //xy=764,233
AudioOutputI2S lineOut; //xy=966,330 AudioAmplifier txOutAmp; //xy=811,309
AudioOutputUSB usbOut; //xy=968,291 AudioOutputI2S lineOut; //xy=974,302
AudioOutputUSB usbOut; //xy=976,263
AudioConnection patchCord1(usbIn, 0, txAudio, 1); AudioConnection patchCord1(usbIn, 0, txAudio, 1);
AudioConnection patchCord2(usbIn, 0, usbInRMS_L, 0); AudioConnection patchCord2(lineIn, 0, rxAudio, 0);
AudioConnection patchCord3(usbIn, 1, usbInRMS_R, 0); AudioConnection patchCord3(lineIn, 1, txAudio, 0);
AudioConnection patchCord4(lineIn, 0, rxAudio, 0); AudioConnection patchCord4(tone1, 0, txAudio, 2);
AudioConnection patchCord5(lineIn, 1, txAudio, 0); AudioConnection patchCord5(tone2, 0, txAudio, 3);
AudioConnection patchCord6(lineIn, 1, lineInRMS, 0); AudioConnection patchCord6(rxAudio, rxFilter);
AudioConnection patchCord7(rxAudio, rxFilter); AudioConnection patchCord7(rxAudio, usbBypassAmp);
AudioConnection patchCord8(rxAudio, usbBypassAmp); AudioConnection patchCord8(txAudio, txVoxLevel);
AudioConnection patchCord9(txAudio, 0, lineOut, 1); AudioConnection patchCord9(txAudio, txOutAmp);
AudioConnection patchCord10(rxFilter, usbOutAmp); AudioConnection patchCord10(rxFilter, usbOutAmp);
AudioConnection patchCord11(rxFilter, lineOutAmp); AudioConnection patchCord11(rxFilter, lineOutAmp);
AudioConnection patchCord12(usbOutAmp, 0, usbOut, 0); AudioConnection patchCord12(usbOutAmp, 0, usbOut, 0);
AudioConnection patchCord13(lineOutAmp, 0, lineOut, 0); AudioConnection patchCord13(lineOutAmp, 0, lineOut, 0);
AudioConnection patchCord14(usbBypassAmp, 0, usbOut, 1); AudioConnection patchCord14(usbBypassAmp, 0, usbOut, 1);
AudioControlSGTL5000 audioCtrl; //xy=427,476 AudioConnection patchCord15(txOutAmp, 0, lineOut, 1);
AudioControlSGTL5000 audioCtrl; //xy=435,448
// GUItool: end automatically generated code // GUItool: end automatically generated code
//} audio; //} audio;
UBitxDSP::UBitxDSP() { UBitxDSP::UBitxDSP() {
voxRMS[txLineInVOX] = &lineInRMS;
voxRMS[txUSBInLVOX] = &usbInRMS_L;
voxRMS[txUSBInRVOX] = &usbInRMS_R;
} }
void UBitxDSP::begin() { void UBitxDSP::begin() {
AudioMemory(16);
// Basic audio setup
AudioMemory(16); // TODO: optimize this
audioCtrl.enable(); audioCtrl.enable();
audioCtrl.volume(0.0); // headphone volume... audioCtrl.volume(0.0); // headphone volume...
audioCtrl.muteHeadphone(); // ...not used by UBitxDSP audioCtrl.muteHeadphone(); // ...not used by UBitxDSP
@ -89,7 +84,7 @@ void UBitxDSP::begin() {
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
audioCtrl.unmuteLineout(); audioCtrl.unmuteLineout();
audioCtrl.lineInLevel(9, 5); // RX, TX audioCtrl.lineInLevel(9, 5); // RX, TX
audioCtrl.lineOutLevel(29, 31); //RX, TX audioCtrl.lineOutLevel(29, 31); // RX, TX
// Mic Input (TX) // Mic Input (TX)
audioCtrl.micGain(0); // TODO: set value audioCtrl.micGain(0); // TODO: set value
@ -108,23 +103,15 @@ void UBitxDSP::begin() {
usbBypassAmp.gain(1.0); usbBypassAmp.gain(1.0);
// Rig (Line) Output (TX) // Rig (Line) Output (TX)
txOutAmp.gain(1.0);
// Default to RX. // Default to RX.
muteRxIn();
muteTxIn();
isTx = true; // so that rx() call works
rx(); rx();
// Setup the VOX - clean this up // Setup the VOX - TBD
state.voxActive[TX_LINE_IN_VOX] = false;
state.voxThresh[TX_LINE_IN_VOX] = TX_LINE_IN_VOX_THRESH;
state.voxDelay[TX_LINE_IN_VOX] = TX_LINE_IN_VOX_DELAY;
state.voxTimeout[TX_LINE_IN_VOX] = 0;
state.voxActive[TX_USB_IN_L_VOX] = false;
state.voxThresh[TX_USB_IN_L_VOX] = TX_USB_IN_L_VOX_THRESH;
state.voxDelay[TX_USB_IN_L_VOX] = TX_USB_IN_L_VOX_DELAY;
state.voxTimeout[TX_USB_IN_L_VOX] = 0;
state.voxActive[TX_USB_IN_R_VOX] = false;
state.voxThresh[TX_USB_IN_R_VOX] = TX_USB_IN_R_VOX_THRESH;
state.voxDelay[TX_USB_IN_R_VOX] = TX_USB_IN_R_VOX_DELAY;
state.voxTimeout[TX_USB_IN_R_VOX] = 0;
// Setup the RX Filter. // Setup the RX Filter.
setRxFilter(300, 3000); setRxFilter(300, 3000);
@ -136,78 +123,135 @@ void UBitxDSP::update() {
// Only going to adjust the USB volume periodically. // Only going to adjust the USB volume periodically.
if (sinceLastUpdate > DSP_MILLIS_PER_UPDATE) { if (sinceLastUpdate > DSP_MILLIS_PER_UPDATE) {
float vol = usbIn.volume(); float vol = usbIn.volume();
setTxInputLevel(txUSBInChannel, vol); setTxInLevel(TX_USB, vol);
sinceLastUpdate = 0; sinceLastUpdate = 0;
} }
// Update the VOX switches. // Update the VOX switches.
// TODO: Move the enable logic in here, so we don't process unnecessarily. // TODO: Move the enable logic in here, so we don't process unnecessarily.
for (int i = 0; i < txNumVOX; i++) { if (txVoxLevel.available()) {
if (voxRMS[i]->available()) { if (txVoxLevel.read() > state.vox.threshold) {
float lvl = voxRMS[i]->read(); state.vox.timeout = millis() + state.vox.delay;
if (lvl > state.voxThresh[i]) { state.vox.active = true;
state.voxTimeout[i] = millis() + state.voxDelay[i];
state.voxActive[i] = true;
}
}
if (millis() > state.voxTimeout[i]) {
state.voxActive[i] = false;
} }
} }
if (millis() > state.vox.timeout) {
state.vox.active = false;
}
} }
void UBitxDSP::end() { void UBitxDSP::end() {
} }
void UBitxDSP::rx() { void UBitxDSP::rx() {
// mute all tx audio if (isTx) {
audioCtrl.micGain(0); muteTxIn();
for (int i = 0; i < 4; i++) { audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
txAudio.gain(i, 0.0); unmuteRxIn(RX_AUDIO);
} isTx = false;
// select line in for rx
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
// restore rx audio
rxAudio.gain(RX_AUDIO_CH, 1.0); // restore the RX audio
}
void UBitxDSP::txMicIn() {
// mute the rx audio
rxAudio.gain(RX_AUDIO_CH, 0.0);
// restore the tx mic audio
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
audioCtrl.micGain(12);
for (int i = 0; i < 4; i++) {
if (i == TX_MIC_IN_CH)
txAudio.gain(i, 0.1);
else
txAudio.gain(i, 0.0);
} }
} }
void UBitxDSP::txLineIn() { void UBitxDSP::setRxInLevel(RxAudioCh ch, float level) {
// mute the rx audio if (ch < NUM_RX_AUDIO_CH) {
rxAudio.gain(RX_AUDIO_CH, 0.0); state.rx[ch].level = level;
// restore the tx line in audio rxAudio.gain(ch, state.rx[ch].mute ? 0.0 : state.rx[ch].level);
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
for (int i = 0; i < 4; i++) {
if (i == TX_LINE_IN_CH)
txAudio.gain(i, 0.1);
else
txAudio.gain(i, 0.0);
} }
} }
void UBitxDSP::txUSBIn() { void UBitxDSP::muteRxIn() {
// mute the rx audio for (RxAudioCh i = RX_AUDIO; i < NUM_RX_AUDIO_CH; i++) {
rxAudio.gain(RX_AUDIO_CH, 0.0); state.rx[ch].mute = true;
// restore the tx usb in audio rxAudio.gain(ch, 0.0);
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); }
for (int i = 0; i < 4; i++) { }
if (i == TX_USB_IN_CH)
txAudio.gain(i, 0.1); void UBitxDSP::muteRxIn(RxAudioCh ch) {
else if (ch < NUM_RX_AUDIO_CH) {
txAudio.gain(i, 0.0); if (!state.rx[ch].mute) {
state.rx[ch].mute = true;
rxAudio.gain(ch, 0.0);
}
}
}
void UBitxDSP::unmuteRxIn(RxAudioCh ch) {
if (ch < NUM_RX_AUDIO_CH) {
if (state.rx[ch].mute) {
state.rx[ch].mute = false;
rxAudio.gain(ch, state.rx[ch].level);
}
}
}
void UBitxDSP::tx(TxAudioIn src) {
if (!isTx) {
muteRxIn(RX_AUDIO);
switch (src) {
case MIC_IN:
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
audioCtrl.micGain(12); // TODO: Make this dynamic
unmuteTxIn(TX_LINE);
case LINE_IN:
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
unmuteTxIn(TX_LINE);
break;
case USB_IN:
unmuteTxIn(TX_USB);
break;
case TUNE_IN:
tone1.amplitude(1.0); // TODO - just do this once.
tone1.frequency(1500); // TODO: Make this dynamic based on CW (sidetone freq) versus data (1500 Hz)
unmuteTxIn(TX_TONE1);
break;
case TWO_TONE_IN:
tone1.amplitude(1.0); // TODO - just do this once.
tone1.amplitude(1.0); // TODO - just do this once.
tone1.frequency(700);
tone2.frequency(1900);
unmuteTxIn(TX_TONE1);
unmuteTxIn(TX_TONE2);
break;
}
isTx = true;
}
}
void UBitxDSP::setTxInLevel(TxAudioCh ch, float level) {
if (ch < NUM_TX_AUDIO_CH) {
state.tx[ch].level = level;
txAudio.gain(ch, state.tx[ch].mute ? 0.0 : state.tx[ch].level);
}
}
void UBitxDSP::muteTxIn() {
for (TxAudioCh i = TX_LINE; i < NUM_TX_AUDIO_CH; i++) {
state.tx[ch].mute = true;
txAudio.gain(ch, 0.0);
}
}
void UBitxDSP::muteTxIn(TxAudioCh ch) {
if (ch < NUM_TX_AUDIO_CH) {
if (!state.tx[ch].mute) {
state.tx[ch].mute = true;
txAudio.gain(ch, 0.0);
}
}
}
void UBitxDSP::unmuteTxIn(TxAudioCh ch) {
if (ch < NUM_TX_AUDIO_CH) {
if (state.tx[ch].mute) {
state.tx[ch].mute = false;
rxAudio.gain(ch, state.tx[ch].level);
}
} }
} }
@ -222,17 +266,17 @@ const int minRxFilterCenter = MIN_RX_FILTER_CENTER;
const int maxRxFilterCenter = MAX_RX_FILTER_CENTER; const int maxRxFilterCenter = MAX_RX_FILTER_CENTER;
/*! /*!
* @brief Bypass the RX audio filter. @brief Bypass the RX audio filter.
*/ */
void UBitxDSP::bypassRxFilter() { void UBitxDSP::bypassRxFilter() {
rxFilter.begin(FIR_PASSTHRU, NUM_COEFFICIENTS); rxFilter.begin(FIR_PASSTHRU, NUM_COEFFICIENTS);
} }
/*! /*!
* @brief Update the RX audio filter using the currently set low and @brief Update the RX audio filter using the currently set low and
* high frequencies. This is called by each of the public high frequencies. This is called by each of the public
* filter methods to update the filter with new frequencies. filter methods to update the filter with new frequencies.
*/ */
void UBitxDSP::updateRxFilter() { void UBitxDSP::updateRxFilter() {
audioFilter(coefficients, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, double(state.rxFilterLo), double(state.rxFilterHi)); audioFilter(coefficients, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, double(state.rxFilterLo), double(state.rxFilterHi));
rxFilter.begin(coefficients, NUM_COEFFICIENTS); rxFilter.begin(coefficients, NUM_COEFFICIENTS);
@ -247,7 +291,7 @@ void UBitxDSP::setRxFilter(int lo, int hi) {
} }
if (lo > hi - minRxFilterWidth) { if (lo > hi - minRxFilterWidth) {
lo = hi - minRxFilterWidth; lo = hi - minRxFilterWidth;
} }
if (lo < minRxFilterLo) { if (lo < minRxFilterLo) {
lo = minRxFilterLo; lo = minRxFilterLo;
} }
@ -319,7 +363,7 @@ void UBitxDSP::enableTxInput(int ch) {
state.txInEnable[ch] = 1; state.txInEnable[ch] = 1;
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]); float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
txAudio.gain(ch, vol); txAudio.gain(ch, vol);
} }
} }
void UBitxDSP::disableTxInput(int ch) { void UBitxDSP::disableTxInput(int ch) {
@ -346,14 +390,18 @@ void UBitxDSP::stopTxInput(int ch) {
} }
} }
// VOX settings /*
bool UBitxDSP::isVoxActive(int vox) { NOTES
if ((vox > -1) && (vox < 3)) {
return state.voxActive[vox]; Major functions:
} else { - tx() - start transmitting / pause receiving
return false; - rx() - stop transmitting / resume receiving
} - setTxSource() - set the TX audio source to MIC_IN, LINE_IN, or USB_IN
} - also sets the relevant VOX source/parameters (as applicable)
Receive audio chain:
-
*/
//====================================================================== //======================================================================
// EOF // EOF

View File

@ -18,23 +18,16 @@
#define DSP_MILLIS_PER_UPDATE 100 #define DSP_MILLIS_PER_UPDATE 100
#define RX_RIG_IN_CH 0
#define TX_MIC_IN_CH 0 #define TX_MIC_IN_CH 0
#define TX_LINE_IN_CH 0 #define TX_LINE_IN_CH 0
#define TX_USB_IN_CH 1 #define TX_USB_IN_CH 1
#define TX_NUM_CHANNELS 2 #define TX_NUM_CHANNELS 2
#define TX_LINE_IN_VOX 0 #define TX_VOX_USB_THRESH 0.25
#define TX_USB_IN_L_VOX 1 #define TX_VOX_LINE_THRESH 0.25
#define TX_USB_IN_R_VOX 2 #define TX_VOX_DELAY 500
#define TX_NUM_VOX 3
#define TX_LINE_IN_VOX_THRESH 0.25
#define TX_USB_IN_L_VOX_THRESH 0.25
#define TX_USB_IN_R_VOX_THRESH 0.25
#define TX_LINE_IN_VOX_DELAY 500
#define TX_USB_IN_L_VOX_DELAY 500
#define TX_USB_IN_R_VOX_DELAY 500
struct DSPState { struct DSPState {
@ -49,10 +42,23 @@ struct DSPState {
int txInEnable[4] = {1, 1, 0, 0}; int txInEnable[4] = {1, 1, 0, 0};
int txInTx[4] = {0, 0, 0, 0}; int txInTx[4] = {0, 0, 0, 0};
struct {
bool mute = true;
float level = 0.1;
} tx[NUM_TX_AUDIO_CH];
struct {
bool mute = true;
float level = 1.0;
} rx[NUM_RX_AUDIO_CH];
// VOX settings // VOX settings
bool voxActive[3]; /* struct {
float voxThresh[3]; bool isActive = false;
unsigned voxDelay[3]; bool isUSB = false;
float usbThresh = TX_VOX_USB_THRESH;
float lineLevel = TX_VOX_LINE_THRESH;
unsigned delay = TX_VOX_DELAY;*/
unsigned voxTimeout[3]; unsigned voxTimeout[3];
}; };
@ -62,13 +68,33 @@ enum TRState {
}; };
enum RxAudioIn { enum RxAudioIn {
RIG_AUDIO RIG_IN = 0,
NUM_RX_AUDIO_IN
};
enum RxAudioCh {
RX_AUDIO = 0,
RX_SPARE1,
RX_SPARE2,
RX_SPARE3,
NUM_RX_AUDIO_CH
}; };
enum TxAudioIn { enum TxAudioIn {
MIC_IN, MIC_IN = 0,
LINE_IN, LINE_IN,
USB_IN USB_IN,
TUNE_IN,
TWO_TONE_IN,
NUM_TX_AUDIO_IN
};
enum TxAudioCh {
TX_LINE = 0,
TX_USB,
TX_TONE1,
TX_TONE2,
NUM_TX_AUDIO_CH
}; };
class UBitxDSP { class UBitxDSP {
@ -78,9 +104,11 @@ class UBitxDSP {
void update(); void update();
void end(); void end();
void rx(); void rx();
void txMicIn(); inline void tx() { tx(txSrc); }
void txLineIn(); void tx(TxAudioIn src);
void txUSBIn();
inline void setTxAudioIn(TxAudioIn src) { txSrc = src; }
TxAudionIn getTxAudioIn() const { return txSrc; }
// RX audio output settings // RX audio output settings
@ -124,16 +152,32 @@ class UBitxDSP {
void stopTxInput(int ch); void stopTxInput(int ch);
// VOX settings // VOX settings
bool isVoxActive(int vox); inline void setDataVoxOn() { state.vox.isActive = true; }
inline void setDataVoxOff() { state.vox.isActive = false; }
inline void setDataVoxThreshold(float val) {
}
inline void setDataVoxThreshold(float val, bool isUSB) {
if (isUSB) {
state.vox.usbThresh = val;
} else {
state.vox.lineThresh = val;
}
}
private: private:
bool isTx = false;
void updateRxFilter(); void updateRxFilter();
DSPState state; DSPState state;
short coefficients[NUM_COEFFICIENTS]; short coefficients[NUM_COEFFICIENTS];
elapsedMillis sinceLastUpdate; elapsedMillis sinceLastUpdate;
AudioAnalyzeRMS* voxRMS[3]; TxAudioIn txSrc;
unsigned voxTimeout;
}; };
extern UBitxDSP DSP; extern UBitxDSP DSP;