409 lines
11 KiB
C++
409 lines
11 KiB
C++
//======================================================================
|
|
// DSP.cpp
|
|
//======================================================================
|
|
|
|
#include "DSP.h"
|
|
|
|
#include <i2c_t3.h>
|
|
//#include <Wire.h>
|
|
//#include <SPI.h>
|
|
//#include <SD.h>
|
|
//#include <SerialFlash.h>
|
|
|
|
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;
|
|
|
|
UBitxDSP DSP;
|
|
|
|
//static struct {
|
|
|
|
// GUItool: begin automatically generated code
|
|
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(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);
|
|
AudioConnection patchCord15(txOutAmp, 0, lineOut, 1);
|
|
AudioControlSGTL5000 audioCtrl; //xy=435,448
|
|
// GUItool: end automatically generated code
|
|
|
|
//} audio;
|
|
|
|
UBitxDSP::UBitxDSP() {
|
|
}
|
|
|
|
void UBitxDSP::begin() {
|
|
|
|
// Basic audio setup
|
|
AudioMemory(16); // TODO: optimize this
|
|
audioCtrl.enable();
|
|
audioCtrl.volume(0.0); // headphone volume...
|
|
audioCtrl.muteHeadphone(); // ...not used by UBitxDSP
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
if (i == RX_AUDIO_CH)
|
|
rxAudio.gain(i, 1.0);
|
|
else
|
|
rxAudio.gain(i, 0.0);
|
|
}
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
txAudio.gain(i, 0.0);
|
|
}
|
|
|
|
// SETUP THE AUDIO INPUTS
|
|
|
|
// Rig (Line) Input (RX)
|
|
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
|
audioCtrl.unmuteLineout();
|
|
audioCtrl.lineInLevel(9, 5); // RX, TX
|
|
audioCtrl.lineOutLevel(29, 31); // RX, TX
|
|
|
|
// Mic Input (TX)
|
|
audioCtrl.micGain(0); // TODO: set value
|
|
|
|
// Line Input (TX)
|
|
|
|
// USB Input (TX)
|
|
|
|
// SETUP THE AUDIO OUTPUTS
|
|
|
|
// Line Output (RX)
|
|
lineOutAmp.gain(1.0);
|
|
|
|
// USB Output (RX)
|
|
usbOutAmp.gain(1.0);
|
|
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 - TBD
|
|
|
|
// Setup the RX Filter.
|
|
setRxFilter(300, 3000);
|
|
|
|
sinceLastUpdate = 0;
|
|
}
|
|
|
|
void UBitxDSP::update() {
|
|
// Only going to adjust the USB volume periodically.
|
|
if (sinceLastUpdate > DSP_MILLIS_PER_UPDATE) {
|
|
float vol = usbIn.volume();
|
|
setTxInLevel(TX_USB, vol);
|
|
sinceLastUpdate = 0;
|
|
}
|
|
|
|
// Update the VOX switches.
|
|
// TODO: Move the enable logic in here, so we don't process unnecessarily.
|
|
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() {
|
|
if (isTx) {
|
|
muteTxIn();
|
|
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
|
unmuteRxIn(RX_AUDIO);
|
|
isTx = false;
|
|
}
|
|
}
|
|
|
|
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::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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**********************************************************************/
|
|
// RX filter settings
|
|
|
|
const int minRxFilterLo = MIN_RX_FILTER_LO;
|
|
const int maxRxFilterHi = MAX_RX_FILTER_HI;
|
|
const int minRxFilterWidth = MIN_RX_FILTER_WIDTH;
|
|
const int maxRxFilterWidth = MAX_RX_FILTER_WIDTH;
|
|
const int minRxFilterCenter = MIN_RX_FILTER_CENTER;
|
|
const int maxRxFilterCenter = MAX_RX_FILTER_CENTER;
|
|
|
|
/*!
|
|
@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.
|
|
*/
|
|
void UBitxDSP::updateRxFilter() {
|
|
audioFilter(coefficients, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, double(state.rxFilterLo), double(state.rxFilterHi));
|
|
rxFilter.begin(coefficients, NUM_COEFFICIENTS);
|
|
}
|
|
|
|
void UBitxDSP::setRxFilter(int lo, int hi) {
|
|
if (hi < lo + minRxFilterWidth) {
|
|
hi = lo + minRxFilterWidth;
|
|
}
|
|
if (hi > maxRxFilterHi) {
|
|
hi = maxRxFilterHi;
|
|
}
|
|
if (lo > hi - minRxFilterWidth) {
|
|
lo = hi - minRxFilterWidth;
|
|
}
|
|
if (lo < minRxFilterLo) {
|
|
lo = minRxFilterLo;
|
|
}
|
|
state.rxFilterHi = hi;
|
|
state.rxFilterLo = lo;
|
|
updateRxFilter();
|
|
}
|
|
|
|
void UBitxDSP::setRxFilterLo(int lo) {
|
|
if (lo > state.rxFilterHi - minRxFilterWidth) {
|
|
lo = state.rxFilterHi - minRxFilterWidth;
|
|
}
|
|
if (lo < minRxFilterLo) {
|
|
lo = minRxFilterLo;
|
|
}
|
|
state.rxFilterLo = lo;
|
|
updateRxFilter();
|
|
}
|
|
|
|
void UBitxDSP::setRxFilterHi(int hi) {
|
|
if (hi < state.rxFilterLo + minRxFilterWidth) {
|
|
hi = state.rxFilterLo + minRxFilterWidth;
|
|
}
|
|
if (hi > maxRxFilterHi) {
|
|
hi = maxRxFilterHi;
|
|
}
|
|
state.rxFilterHi = hi;
|
|
updateRxFilter();
|
|
}
|
|
|
|
void UBitxDSP::setRxFilterWidth(int width) {
|
|
if (width < minRxFilterWidth) {
|
|
width = minRxFilterWidth;
|
|
} else if (width > maxRxFilterWidth) {
|
|
width = maxRxFilterWidth;
|
|
}
|
|
int center = (state.rxFilterHi + state.rxFilterLo) / 2;
|
|
int lo = center - (width / 2);
|
|
int hi = center + (width / 2);
|
|
setRxFilter(lo, hi);
|
|
}
|
|
|
|
void UBitxDSP::setRxFilterCenter(int center) {
|
|
if (center < minRxFilterCenter) {
|
|
center = minRxFilterCenter;
|
|
} else if (center > maxRxFilterCenter) {
|
|
center = maxRxFilterCenter;
|
|
}
|
|
int width = state.rxFilterHi - state.rxFilterLo;
|
|
int lo = center - (width / 2);
|
|
int hi = center + (width / 2);
|
|
setRxFilter(lo, hi);
|
|
}
|
|
|
|
|
|
/**********************************************************************/
|
|
// TX audio input settings
|
|
|
|
void UBitxDSP::setTxInputLevel(int ch, float lvl) {
|
|
if ((ch > -1) && (ch < txNumChannels)) {
|
|
state.txInLvl[ch] = lvl;
|
|
float vol = lvl * float(state.txInEnable[ch] * state.txInTx[ch]);
|
|
txAudio.gain(ch, vol);
|
|
}
|
|
}
|
|
|
|
void UBitxDSP::enableTxInput(int ch) {
|
|
if ((ch > -1) && (ch < txNumChannels)) {
|
|
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) {
|
|
if ((ch > -1) && (ch < txNumChannels)) {
|
|
state.txInEnable[ch] = 0;
|
|
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
|
|
txAudio.gain(ch, vol);
|
|
}
|
|
}
|
|
|
|
void UBitxDSP::startTxInput(int ch) {
|
|
if ((ch > -1) && (ch < txNumChannels)) {
|
|
state.txInTx[ch] = 1;
|
|
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
|
|
txAudio.gain(ch, vol);
|
|
}
|
|
}
|
|
|
|
void UBitxDSP::stopTxInput(int ch) {
|
|
if ((ch > -1) && (ch < txNumChannels)) {
|
|
state.txInTx[ch] = 0;
|
|
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
|
|
txAudio.gain(ch, vol);
|
|
}
|
|
}
|
|
|
|
/*
|
|
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
|
|
//======================================================================
|