diff --git a/TeensyDSP/DSP.cpp b/TeensyDSP/DSP.cpp index f1689c9..21ce890 100644 --- a/TeensyDSP/DSP.cpp +++ b/TeensyDSP/DSP.cpp @@ -10,64 +10,59 @@ //#include //#include -#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 diff --git a/TeensyDSP/DSP.h b/TeensyDSP/DSP.h index fe293a8..fb707b2 100644 --- a/TeensyDSP/DSP.h +++ b/TeensyDSP/DSP.h @@ -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;