//====================================================================== // audio.ino //====================================================================== #include "audio.h" extern IOPConfig iopConfig; #define DEFAULT_RX_INPUT RIG #define DEFAULT_RX_OUTPUT SPKR #define DEFAULT_TX_INPUT MIC #define DEFAULT_TX_OUTPUT RIG #include #include #include #include #include // GUItool: begin automatically generated code AudioInputI2S inLine; //xy=224,194 AudioInputUSB inUSB; //xy=224,303 AudioAnalyzeRMS rmsRX; //xy=399,71 AudioAnalyzePeak peakRX; //xy=403,122 AudioMixer4 mixRX; //xy=460,187 AudioMixer4 mixTX; //xy=460,303 AudioAmplifier calRxUSB; //xy=650,189 AudioAmplifier calRxSpkr; //xy=654,79 AudioAmplifier calRxLine; //xy=657,136 AudioAmplifier calTxLine; //xy=669,272 AudioAmplifier calTxUSB; //xy=670,329 AudioAnalyzePeak peakTX; //xy=685,402 AudioAnalyzeRMS rmsTX; //xy=699,457 AudioOutputAnalog outSpkr; //xy=830,79 AudioOutputUSB outUSB; //xy=839,279 AudioOutputI2S outLine; //xy=842,228 AudioConnection patchCord1(inLine, 0, rmsRX, 0); AudioConnection patchCord2(inLine, 0, peakRX, 0); AudioConnection patchCord3(inLine, 0, mixRX, 0); AudioConnection patchCord4(inLine, 1, mixTX, 0); AudioConnection patchCord5(inUSB, 0, mixRX, 1); AudioConnection patchCord6(inUSB, 1, mixTX, 1); AudioConnection patchCord7(mixRX, calRxSpkr); AudioConnection patchCord8(mixRX, calRxLine); AudioConnection patchCord9(mixRX, calRxUSB); AudioConnection patchCord10(mixTX, calTxLine); AudioConnection patchCord11(mixTX, calTxUSB); AudioConnection patchCord12(mixTX, peakTX); AudioConnection patchCord13(mixTX, rmsTX); AudioConnection patchCord14(calRxUSB, 0, outUSB, 0); AudioConnection patchCord15(calRxSpkr, outSpkr); AudioConnection patchCord16(calRxLine, 0, outLine, 0); AudioConnection patchCord17(calTxLine, 0, outLine, 1); AudioConnection patchCord18(calTxUSB, 0, outUSB, 1); AudioControlSGTL5000 audioCtrl; //xy=407,467 // GUItool: end automatically generated code RxInput audioRxInput; RxOutput audioRxOutput; TxInput audioTxInput; TxOutput audioTxOutput; // 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(iopConfig.rxRigInLevel, iopConfig.txLineInLevel); // NOTE: need to see if this persists through input changes (see mic gain...) audioCtrl.lineOutLevel(iopConfig.rxLineOutLevel, iopConfig.txRigOutLevel); // NOTE: need to see if this persists through input changes (see mic gain...) audioCtrl.micGain(iopConfig.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 audioSelectTxInput(TX_MIC_IN); // superfluous I think audioCWFilterNarrow(); // test } inline void updateRxRigIn() { audioCtrl.lineInLevel(iopConfig.rxRigInLevel, iopConfig.txLineInLevel); mixRX.gain(RX_RIG_IN, iopConfig.rxRigInVol * iopConfig.rxRigInCal); } inline void muteRxRigIn() { mixRX.gain(RX_RIG_IN, 0.0); } inline void restoreRxRigIn() { mixRX.gain(RX_RIG_IN, iopConfig.rxRigInVol * iopConfig.rxRigInCal); } inline void updateRxUSBIn() { if (iopConfig.rxUSBInEnable) { mixRX.gain(RX_USB_IN, iopConfig.rxUSBInVol * iopConfig.rxUSBInCal); } else { mixRX.gain(RX_USB_IN, 0.0); } } inline void updateRxSpkrOut() { calRxSpkr.gain(iopConfig.rxSpkrOutCal); } inline void updateRxLineOut() { calRxLine.gain(iopConfig.rxLineOutCal); audioCtrl.lineOutLevel(iopConfig.rxLineOutLevel, iopConfig.txRigOutLevel); } inline void updateRxUSBOut() { calRxUSB.gain(iopConfig.rxUSBOutCal); } inline void updateTxMicIn() { audioCtrl.micGain(iopConfig.txMicInGain); mixTX.gain(TX_LINE_IN, iopConfig.txMicInVol * iopConfig.txMicInCal); } inline void muteTxMicIn() { mixTX.gain(TX_LINE_IN, 0.0); } inline void restoreTxMicIn() { mixTX.gain(TX_LINE_IN, iopConfig.txMicInVol * iopConfig.txMicInCal); } inline void updateTxLineIn() { audioCtrl.lineInLevel(iopConfig.rxRigInLevel, iopConfig.txLineInLevel); mixTX.gain(TX_LINE_IN, iopConfig.txLineInVol * iopConfig.txLineInCal); } inline void muteTxLineIn() { mixTX.gain(TX_LINE_IN, 0.0); } inline void restoreTxLineIn() { mixTX.gain(TX_LINE_IN, iopConfig.txLineInVol * iopConfig.txLineInCal); } inline void updateTxUSBIn() { mixTX.gain(TX_USB_IN, iopConfig.txUSBInVol * iopConfig.txUSBInCal); } inline void muteTxUSBIn() { mixTX.gain(TX_USB_IN, 0.0); } inline void restoreTxUSBIn() { mixTX.gain(TX_USB_IN, iopConfig.txUSBInVol * iopConfig.txUSBInCal); } inline void updateTxRigOut() { calTxLine.gain(iopConfig.txRigOutCal); audioCtrl.lineOutLevel(iopConfig.rxLineOutLevel, iopConfig.txRigOutLevel); } inline void updateTxUSBOut() { if (iopConfig.txUSBOutEnable) { calTxUSB.gain(iopConfig.txUSBOutCal); } else { calTxUSB.gain(0.0); } } void audioSelectTxInput(TxInput input) { if (audioTxInput != input) { audioTxInput = input; switch(input) { case TX_MIC_IN: muteTxUSBIn(); restoreTxMicIn(); break; case TX_LINE_IN: muteTxUSBIn(); restoreTxLineIn(); break; case TX_USB_IN: muteTxLineIn(); restoreTxUSBIn(); break; } } } // audioTransmit() // This should be called anytime transmit mode is entered. It should // in theory be called BEFORE the actual transmit signal (key/PTT) is // sent to the Raduino, in order to ensure that any audio source // transitions occur before transmission begins. void audioTransmit() { if (rigMode == MODE_SSB || rigMode == MODE_DIGI) { // First we're going to set the RX and TX audio DAC volumes to // zero while we change other mixer settings, to try to use the // DAC's volume ramping to minimize pops. // NOTE: Might need to add a brief delay? //audioCtrl.dacVolume(0.0, 0.0); // Next mute the incoming RX audio. Can't think of a good reason // to let RX audio in while we're transmitting. muteRxRigIn(); if (audioTxInput == TX_MIC_IN) { // Mute the TX line in in this case, too, because we need to // switch over to the mic input. muteTxLineIn(); // Now switch to the mic input, and set the mic gain. audioCtrl.inputSelect(AUDIO_INPUT_MIC); updateTxMicIn(); #if defined(FACTORY_CALIBRATION) USBSERIAL.println("=============================="); USBSERIAL.println("Transmitting with Mic input"); USBSERIAL.print("Mic gain: "); USBSERIAL.println(iopConfig.txMicInGain); USBSERIAL.print("Mic volume: "); USBSERIAL.println(iopConfig.txMicInVol); USBSERIAL.print("Mic calibration: "); USBSERIAL.println(iopConfig.txMicInCal); USBSERIAL.print("TX audio level: "); USBSERIAL.println(iopConfig.txRigOutLevel); USBSERIAL.print("TX audio calibration: "); USBSERIAL.println(iopConfig.txRigOutCal); USBSERIAL.println("=============================="); #endif } // Allow both transmit and receive audio output channels. This is safe // because the RX input is muted, and we might want to inject something else. //audioCtrl.dacVolume(1.0, 1.0); } } // audioReceive() // This should be called anytime receive mode is entered. It should // in theory be called AFTER the actual transmit signal (key/PTT) is // removed from the Raduino, in order to ensure that any audio source // transitions occur before receive begins. void audioReceive() { if (rigMode == MODE_SSB || rigMode == MODE_DIGI) { // First we're going to set the RX and TX audio DAC volumes to // zero while we switch inputs, because the DAC volumes can be // smoothly ramped by the SGTL5000 to avoid pops. //audioCtrl.dacVolume(0.0, 0.0); // Mute the mic, since we're going to be switching back to line // input for RX and TX. if (audioTxInput == TX_MIC_IN) { muteTxMicIn(); // Now switch to the line input, and restore mixer settings. audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); restoreTxLineIn(); } restoreRxRigIn(); // Now bring back up the DAC volumes. Hopefully this reduced pops... // When going back to receive, we leave transmit DAC at zero. //audioCtrl.dacVolume(1.0, 0.0); } } //====================================================================== void audioCalibrate(IOPConfig* 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 updateFilter[5]; void audioCWFilterNarrow() { audioCtrl.audioPreProcessorEnable(); // calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*); calcBiquad(FILTER_BANDPASS, 700, 0, 2, 524288, 44100, updateFilter); audioCtrl.eqFilter(0, updateFilter); audioCtrl.eqFilter(1, updateFilter); } //====================================================================== // EOF //======================================================================