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 <SerialFlash.h>
#define RX_AUDIO_CH 0
const int rxRigInChannel = RX_RIG_IN_CH;
const int txMicInChannel = TX_MIC_IN_CH;
const int txLineInChannel = TX_LINE_IN_CH;
const int txUSBInChannel = TX_USB_IN_CH;
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;
//static struct {
// GUItool: begin automatically generated code
AudioInputUSB usbIn; //xy=153,341
AudioInputI2S lineIn; //xy=161,233
AudioAnalyzeRMS usbInRMS_R; //xy=276,431
AudioAnalyzeRMS usbInRMS_L; //xy=335,392
AudioAnalyzeRMS lineInRMS; //xy=387,273
AudioMixer4 rxAudio; //xy=418,147
AudioMixer4 txAudio; //xy=422,335
AudioFilterFIR rxFilter; //xy=583,139
AudioAmplifier usbOutAmp; //xy=748,135
AudioAmplifier lineOutAmp; //xy=749,198
AudioAmplifier usbBypassAmp; //xy=756,261
AudioOutputI2S lineOut; //xy=966,330
AudioOutputUSB usbOut; //xy=968,291
AudioInputUSB usbIn; //xy=161,313
AudioInputI2S lineIn; //xy=169,205
AudioSynthWaveformSine tone1; //xy=234,386
AudioSynthWaveformSine tone2; //xy=234,422
AudioMixer4 rxAudio; //xy=426,119
AudioMixer4 txAudio; //xy=430,307
AudioAnalyzeRMS txVoxLevel; //xy=588,348
AudioFilterFIR rxFilter; //xy=591,111
AudioAmplifier usbOutAmp; //xy=756,107
AudioAmplifier lineOutAmp; //xy=757,170
AudioAmplifier usbBypassAmp; //xy=764,233
AudioAmplifier txOutAmp; //xy=811,309
AudioOutputI2S lineOut; //xy=974,302
AudioOutputUSB usbOut; //xy=976,263
AudioConnection patchCord1(usbIn, 0, txAudio, 1);
AudioConnection patchCord2(usbIn, 0, usbInRMS_L, 0);
AudioConnection patchCord3(usbIn, 1, usbInRMS_R, 0);
AudioConnection patchCord4(lineIn, 0, rxAudio, 0);
AudioConnection patchCord5(lineIn, 1, txAudio, 0);
AudioConnection patchCord6(lineIn, 1, lineInRMS, 0);
AudioConnection patchCord7(rxAudio, rxFilter);
AudioConnection patchCord8(rxAudio, usbBypassAmp);
AudioConnection patchCord9(txAudio, 0, lineOut, 1);
AudioConnection patchCord2(lineIn, 0, rxAudio, 0);
AudioConnection patchCord3(lineIn, 1, txAudio, 0);
AudioConnection patchCord4(tone1, 0, txAudio, 2);
AudioConnection patchCord5(tone2, 0, txAudio, 3);
AudioConnection patchCord6(rxAudio, rxFilter);
AudioConnection patchCord7(rxAudio, usbBypassAmp);
AudioConnection patchCord8(txAudio, txVoxLevel);
AudioConnection patchCord9(txAudio, txOutAmp);
AudioConnection patchCord10(rxFilter, usbOutAmp);
AudioConnection patchCord11(rxFilter, lineOutAmp);
AudioConnection patchCord12(usbOutAmp, 0, usbOut, 0);
AudioConnection patchCord13(lineOutAmp, 0, lineOut, 0);
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
//} audio;
UBitxDSP::UBitxDSP() {
voxRMS[txLineInVOX] = &lineInRMS;
voxRMS[txUSBInLVOX] = &usbInRMS_L;
voxRMS[txUSBInRVOX] = &usbInRMS_R;
}
void UBitxDSP::begin() {
AudioMemory(16);
// Basic audio setup
AudioMemory(16); // TODO: optimize this
audioCtrl.enable();
audioCtrl.volume(0.0); // headphone volume...
audioCtrl.muteHeadphone(); // ...not used by UBitxDSP
@ -89,7 +84,7 @@ void UBitxDSP::begin() {
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
audioCtrl.unmuteLineout();
audioCtrl.lineInLevel(9, 5); // RX, TX
audioCtrl.lineOutLevel(29, 31); //RX, TX
audioCtrl.lineOutLevel(29, 31); // RX, TX
// Mic Input (TX)
audioCtrl.micGain(0); // TODO: set value
@ -108,23 +103,15 @@ void UBitxDSP::begin() {
usbBypassAmp.gain(1.0);
// Rig (Line) Output (TX)
txOutAmp.gain(1.0);
// Default to RX.
muteRxIn();
muteTxIn();
isTx = true; // so that rx() call works
rx();
// Setup the VOX - clean this up
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 VOX - TBD
// Setup the RX Filter.
setRxFilter(300, 3000);
@ -136,78 +123,135 @@ void UBitxDSP::update() {
// Only going to adjust the USB volume periodically.
if (sinceLastUpdate > DSP_MILLIS_PER_UPDATE) {
float vol = usbIn.volume();
setTxInputLevel(txUSBInChannel, vol);
setTxInLevel(TX_USB, vol);
sinceLastUpdate = 0;
}
// Update the VOX switches.
// TODO: Move the enable logic in here, so we don't process unnecessarily.
for (int i = 0; i < txNumVOX; i++) {
if (voxRMS[i]->available()) {
float lvl = voxRMS[i]->read();
if (lvl > state.voxThresh[i]) {
state.voxTimeout[i] = millis() + state.voxDelay[i];
state.voxActive[i] = true;
}
}
if (millis() > state.voxTimeout[i]) {
state.voxActive[i] = false;
if (txVoxLevel.available()) {
if (txVoxLevel.read() > state.vox.threshold) {
state.vox.timeout = millis() + state.vox.delay;
state.vox.active = true;
}
}
if (millis() > state.vox.timeout) {
state.vox.active = false;
}
}
void UBitxDSP::end() {
}
void UBitxDSP::rx() {
// mute all tx audio
audioCtrl.micGain(0);
for (int i = 0; i < 4; i++) {
txAudio.gain(i, 0.0);
}
// 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);
if (isTx) {
muteTxIn();
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
unmuteRxIn(RX_AUDIO);
isTx = false;
}
}
void UBitxDSP::txLineIn() {
// mute the rx audio
rxAudio.gain(RX_AUDIO_CH, 0.0);
// restore the tx line in audio
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::setRxInLevel(RxAudioCh ch, float level) {
if (ch < NUM_RX_AUDIO_CH) {
state.rx[ch].level = level;
rxAudio.gain(ch, state.rx[ch].mute ? 0.0 : state.rx[ch].level);
}
}
void UBitxDSP::txUSBIn() {
// mute the rx audio
rxAudio.gain(RX_AUDIO_CH, 0.0);
// restore the tx usb in audio
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
for (int i = 0; i < 4; i++) {
if (i == TX_USB_IN_CH)
txAudio.gain(i, 0.1);
else
txAudio.gain(i, 0.0);
void UBitxDSP::muteRxIn() {
for (RxAudioCh i = RX_AUDIO; i < NUM_RX_AUDIO_CH; i++) {
state.rx[ch].mute = true;
rxAudio.gain(ch, 0.0);
}
}
void UBitxDSP::muteRxIn(RxAudioCh ch) {
if (ch < NUM_RX_AUDIO_CH) {
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;
/*!
* @brief Bypass the RX audio filter.
*/
@brief Bypass the RX audio filter.
*/
void UBitxDSP::bypassRxFilter() {
rxFilter.begin(FIR_PASSTHRU, NUM_COEFFICIENTS);
}
/*!
* @brief Update the RX audio filter using the currently set low and
* high frequencies. This is called by each of the public
* filter methods to update the filter with new frequencies.
*/
@brief Update the RX audio filter using the currently set low and
high frequencies. This is called by each of the public
filter methods to update the filter with new frequencies.
*/
void UBitxDSP::updateRxFilter() {
audioFilter(coefficients, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, double(state.rxFilterLo), double(state.rxFilterHi));
rxFilter.begin(coefficients, NUM_COEFFICIENTS);
@ -247,7 +291,7 @@ void UBitxDSP::setRxFilter(int lo, int hi) {
}
if (lo > hi - minRxFilterWidth) {
lo = hi - minRxFilterWidth;
}
}
if (lo < minRxFilterLo) {
lo = minRxFilterLo;
}
@ -319,7 +363,7 @@ void UBitxDSP::enableTxInput(int ch) {
state.txInEnable[ch] = 1;
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
txAudio.gain(ch, vol);
}
}
}
void UBitxDSP::disableTxInput(int ch) {
@ -346,14 +390,18 @@ void UBitxDSP::stopTxInput(int ch) {
}
}
// VOX settings
bool UBitxDSP::isVoxActive(int vox) {
if ((vox > -1) && (vox < 3)) {
return state.voxActive[vox];
} else {
return false;
}
}
/*
NOTES
Major functions:
- tx() - start transmitting / pause receiving
- 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

View File

@ -18,23 +18,16 @@
#define DSP_MILLIS_PER_UPDATE 100
#define RX_RIG_IN_CH 0
#define TX_MIC_IN_CH 0
#define TX_LINE_IN_CH 0
#define TX_USB_IN_CH 1
#define TX_NUM_CHANNELS 2
#define TX_LINE_IN_VOX 0
#define TX_USB_IN_L_VOX 1
#define TX_USB_IN_R_VOX 2
#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
#define TX_VOX_USB_THRESH 0.25
#define TX_VOX_LINE_THRESH 0.25
#define TX_VOX_DELAY 500
struct DSPState {
@ -49,10 +42,23 @@ struct DSPState {
int txInEnable[4] = {1, 1, 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
bool voxActive[3];
float voxThresh[3];
unsigned voxDelay[3];
/* struct {
bool isActive = false;
bool isUSB = false;
float usbThresh = TX_VOX_USB_THRESH;
float lineLevel = TX_VOX_LINE_THRESH;
unsigned delay = TX_VOX_DELAY;*/
unsigned voxTimeout[3];
};
@ -62,13 +68,33 @@ enum TRState {
};
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 {
MIC_IN,
MIC_IN = 0,
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 {
@ -78,9 +104,11 @@ class UBitxDSP {
void update();
void end();
void rx();
void txMicIn();
void txLineIn();
void txUSBIn();
inline void tx() { tx(txSrc); }
void tx(TxAudioIn src);
inline void setTxAudioIn(TxAudioIn src) { txSrc = src; }
TxAudionIn getTxAudioIn() const { return txSrc; }
// RX audio output settings
@ -124,16 +152,32 @@ class UBitxDSP {
void stopTxInput(int ch);
// 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:
bool isTx = false;
void updateRxFilter();
DSPState state;
short coefficients[NUM_COEFFICIENTS];
elapsedMillis sinceLastUpdate;
AudioAnalyzeRMS* voxRMS[3];
TxAudioIn txSrc;
unsigned voxTimeout;
};
extern UBitxDSP DSP;