From: drowe67 Date: Sat, 17 Nov 2012 02:11:54 +0000 (+0000) Subject: moved tx and rx processing to OnIdle, using device-defined buffer sizes for portaudio... X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=ec7010cda0c0b17407af81cd5264bca85363c338;p=freetel-svn-tracking.git moved tx and rx processing to OnIdle, using device-defined buffer sizes for portaudio callbacks. Still testing. git-svn-id: https://svn.code.sf.net/p/freetel/code@1001 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/fdmdv2/src/dlg_audiooptions.cpp b/fdmdv2/src/dlg_audiooptions.cpp index 4cdec284..70cffa84 100644 --- a/fdmdv2/src/dlg_audiooptions.cpp +++ b/fdmdv2/src/dlg_audiooptions.cpp @@ -395,10 +395,12 @@ int AudioOptsDialog::setTextCtrlIfDevNumValid(wxTextCtrl *textCtrl, wxListCtrl * found_devNum = 0; for(i=0; iGetItemCount()-1; i++) { aDevNum = wxAtoi(listCtrl->GetItemText(i, 1)); - printf("aDevNum: %d devNum: %d\n", aDevNum, devNum); + //printf("aDevNum: %d devNum: %d\n", aDevNum, devNum); if (aDevNum == devNum) { found_devNum = 1; textCtrl->SetValue(listCtrl->GetItemText(i, 0) + " (" + wxString::Format(wxT("%i"),devNum) + ")"); + printf("setting focus of %d\n", i); + listCtrl->SetItemState(i, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED); } } diff --git a/fdmdv2/src/fdmdv2_defines.h b/fdmdv2/src/fdmdv2_defines.h index 9857982d..f4d8e3a5 100644 --- a/fdmdv2/src/fdmdv2_defines.h +++ b/fdmdv2/src/fdmdv2_defines.h @@ -60,7 +60,7 @@ // sample rate I/O & conversion constants -#define MAX_FPB 2048 // maximum value of portAudio framesPerBuffer +#define MAX_FPB 8096 // maximum value of portAudio framesPerBuffer #define PA_FPB 1024 // nominal value of portAudio framesPerBuffer #define SAMPLE_RATE 48000 // 48 kHz sampling rate rec. as we can trust accuracy of sound card #define N8 FDMDV_NOM_SAMPLES_PER_FRAME // processing buffer size at 8 kHz diff --git a/fdmdv2/src/fdmdv2_main.cpp b/fdmdv2/src/fdmdv2_main.cpp index 84b5d061..255e2c6b 100644 --- a/fdmdv2/src/fdmdv2_main.cpp +++ b/fdmdv2/src/fdmdv2_main.cpp @@ -235,6 +235,8 @@ MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent) m_auiNbookCtrl->AddPage(m_panelFreqOffset, L"Frequency \u0394", true, wxNullBitmap); } + wxGetApp().m_framesPerBuffer = pConfig->Read(wxT("/Audio/framesPerBuffer"), PA_FPB); + g_soundCard1InDeviceNum = pConfig->Read(wxT("/Audio/soundCard1InDeviceNum"), -1); g_soundCard1OutDeviceNum = pConfig->Read(wxT("/Audio/soundCard1OutDeviceNum"), -1); g_soundCard1SampleRate = pConfig->Read(wxT("/Audio/soundCard1SampleRate"), -1); @@ -329,6 +331,8 @@ MainFrame::~MainFrame() pConfig->Write(wxT("/Audio/SquelchActive"), g_SquelchActive); pConfig->Write(wxT("/Audio/SquelchLevel"), (int)(g_SquelchLevel*2.0)); + pConfig->Write(wxT("/Audio/framesPerBuffer"), wxGetApp().m_framesPerBuffer); + pConfig->Write(wxT("/Audio/soundCard1InDeviceNum"), g_soundCard1InDeviceNum); pConfig->Write(wxT("/Audio/soundCard1OutDeviceNum"), g_soundCard1OutDeviceNum); pConfig->Write(wxT("/Audio/soundCard1SampleRate"), g_soundCard1SampleRate ); @@ -381,7 +385,6 @@ MainFrame::~MainFrame() void MainFrame::OnTimer(wxTimerEvent &evt) { - m_panelWaterfall->m_newdata = true; m_panelWaterfall->Refresh(); @@ -429,7 +432,7 @@ void MainFrame::OnTimer(wxTimerEvent &evt) if (snr_limited < 0.0) snr_limited = 0; if (snr_limited > 20.0) snr_limited = 20.0; - m_gaugeSNR->SetValue((int)(snr_limited+0.5)); + m_gaugeSNR->SetValue((int)(snr_limited)); // sync LED @@ -441,7 +444,6 @@ void MainFrame::OnTimer(wxTimerEvent &evt) m_rbSync->SetForegroundColour( wxColour( 255, 0, 0 ) ); m_rbSync->SetValue(false); } - } #endif @@ -451,14 +453,9 @@ void MainFrame::OnTimer(wxTimerEvent &evt) //---------------------------------------------------------------- void MainFrame::OnIdle(wxIdleEvent& event) { - printf("OnIdle\n"); - if(m_panelWaterfall->m_newdata) - { - m_panelWaterfall->Refresh(); - } - if(m_panelSpectrum->m_newdata) - { - m_panelSpectrum->Refresh(); + if (m_RxRunning) { + //printf("OnIdle\n"); + txRxProcessing(); } } #endif // _USE_TIMER @@ -1013,6 +1010,7 @@ void MainFrame::OnTogBtnOnOff(wxCommandEvent& event) g_pFDMDV = fdmdv_create(); g_pCodec2 = codec2_create(CODEC2_MODE_1400); g_State = 0; + printf("g_stats.snr: %f\n", g_stats.snr_est); // init click-tune states @@ -1160,6 +1158,7 @@ void MainFrame::initPortAudioDevice(PortAudioWrap *pa, int inDevice, int outDev // portaudio struct so can't return any errors. So no need to trap // any errors in this function. + printf("indDevice: %d outDevice: %d\n", inDevice, outDevice); // init input params pa->setInputDevice(inDevice); @@ -1172,7 +1171,7 @@ void MainFrame::initPortAudioDevice(PortAudioWrap *pa, int inDevice, int outDev // init output params pa->setOutputDevice(outDevice); - pa->setOutputChannelCount(2); // stereo input + pa->setOutputChannelCount(2); // stereo output pa->setOutputSampleFormat(PA_SAMPLE_TYPE); pa->setOutputLatency(pa->getOutputDefaultLowLatency()); pa->setOutputHostApiStreamInfo(NULL); @@ -1186,9 +1185,10 @@ void MainFrame::initPortAudioDevice(PortAudioWrap *pa, int inDevice, int outDev framesPerBuffer = 1024. */ - pa->setFramesPerBuffer(PA_FPB); + pa->setFramesPerBuffer(wxGetApp().m_framesPerBuffer); + printf("framesPerBuffer: %d\n", wxGetApp().m_framesPerBuffer); pa->setSampleRate(sampleRate); - pa->setStreamFlags(0); + pa->setStreamFlags(paClipOff); } //------------------------------------------------------------------------- @@ -1307,31 +1307,10 @@ void MainFrame::startRxStream() // create FIFOs used to interface between different buffer sizes - m_rxUserdata->infifo1 = fifo_create(4*N48); - - m_rxUserdata->outfifo1 = fifo_create(4*N48); - - /* - During soundcard 1 callback, outfifo1 is read in PA_FPB = 1024 sample blocks. - - In tx processing: - + if outfifo1 has less than framesPerBuffer = PA_FPB = 1024 samples - + then tx process generates a 40ms @ 48kHz = 1920 sample blocks - + so we could have 1023 + 1920 samples - + so lets make it 1920*2 in size - */ - - m_rxUserdata->outfifo2 = fifo_create(4*N48); - - /* - infifo2 holds buffers from the microphone. These get read - in 40ms (1920 sample @ 48 kHz) blocks by the sound card 1 - callback. We write to the sound card in 1024 sample - blocks. So we need at least 1024+1920 samples, lest also allocate - 1920*2 samples - */ - - m_rxUserdata->infifo2 = fifo_create(4*N48); + m_rxUserdata->infifo1 = fifo_create(8*N48); + m_rxUserdata->outfifo1 = fifo_create(8*N48); + m_rxUserdata->outfifo2 = fifo_create(8*N48); + m_rxUserdata->infifo2 = fifo_create(8*N48); m_rxUserdata->rxinfifo = fifo_create(3 * FDMDV_NOM_SAMPLES_PER_FRAME); m_rxUserdata->rxoutfifo = fifo_create(2 * codec2_samples_per_frame(g_pCodec2)); @@ -1492,33 +1471,11 @@ void resample_for_plot(struct FIFO *plotFifo, short buf[], int length) fifo_write(plotFifo, dec_samples, nSamples); } -//------------------------------------------------------------------------- -// rxCallback() -//------------------------------------------------------------------------- - -/* - todo: - - + add tests to determine if we have real time audio I/O problems, - for example lost samples, buffer overflow, too slow processing - + should flag the user so they can tune the system - + maybe compute time spent doing demod compared to time between calls -*/ - -int MainFrame::rxCallback( - const void *inputBuffer, - void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData - ) +void MainFrame::txRxProcessing() { - paCallBackData *cbData = (paCallBackData*)userData; - short *rptr = (short*)inputBuffer; - short *wptr = (short*)outputBuffer; + paCallBackData *cbData = m_rxUserdata; - // temp buffers re-used by tx and rx processing + // Buffers re-used by tx and rx processing // signals in in48k/out48k are at a maximum sample rate of 48k, could be 44.1kHz // depending on sound hardware. @@ -1526,47 +1483,14 @@ int MainFrame::rxCallback( short in48k_short[2*N48]; short out8k_short[2*N8]; short out48k_short[2*N48]; - short indata[MAX_FPB]; - short outdata[MAX_FPB]; int nout; - unsigned int i; - - (void) timeInfo; - (void) statusFlags; - - //printf("%d cb1 .. %d", cb1++, cb1-cb2); - assert(inputBuffer != NULL); - assert(outputBuffer != NULL); - - /* - framesPerBuffer is portaudio-speak for number of samples we - actually get from the record side and need to provide to the - play side. On Linux (at least) it was found that - framesPerBuffer may not always be what we ask for in the - framesPerBuffer field of Pa_OpenStream. For example a request - for 960 sample buffers may lead to framesPerBuffer = 1024 in - this call back. - - So we use a bunch of FIFOs to interface between different - buffer sizes required at each processing step, and to - communicate between the call backs for the two sound cards. - */ + //printf("start infifo1: %5d outfifo1: %5d\n", fifo_n(cbData->infifo1), fifo_n(cbData->outfifo1)); // // RX side processing -------------------------------------------- // - // assemble a mono buffer (just use left channel) and write to FIFO - - assert(framesPerBuffer < MAX_FPB); - - for(i = 0; i < framesPerBuffer; i++, rptr += cbData->inputChannels1) - { - indata[i] = *rptr; - } - fifo_write(cbData->infifo1, indata, framesPerBuffer); - // while we have enough input samples available ... int nsam = g_soundCard1SampleRate * (float)N8/FS; @@ -1611,13 +1535,13 @@ int MainFrame::rxCallback( if (g_nSoundCards == 2 ) { - // Make sure we have at least framesPerBuffer modulator output - // samples. This locks the modulator to the sample - // rate of sound card 1. We want to make sure that modulator - // samples are uninterrupted by differences in sample rate - // between this sound card and sound card 2. + // Make sure we have at least 2 frames of modulator output + // samples. This locks the modulator to the sample + // rate of sound card 1. We want to make sure that modulator + // samples are uninterrupted by differences in sample rate + // between this sound card and sound card 2. - while((unsigned)fifo_n(cbData->outfifo1) < framesPerBuffer) { + while((unsigned)fifo_n(cbData->outfifo1) < 6*N48) { int nsam = g_soundCard2SampleRate * (float)codec2_samples_per_frame(g_pCodec2)/FS; assert(nsam <= 2*N48); @@ -1660,6 +1584,57 @@ int MainFrame::rxCallback( } } + //printf(" end infifo1: %5d outfifo1: %5d\n", fifo_n(cbData->infifo1), fifo_n(cbData->outfifo1)); + +} + +//------------------------------------------------------------------------- +// rxCallback() +//------------------------------------------------------------------------- + +int MainFrame::rxCallback( + const void *inputBuffer, + void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData + ) +{ + paCallBackData *cbData = (paCallBackData*)userData; + short *rptr = (short*)inputBuffer; + short *wptr = (short*)outputBuffer; + + short indata[MAX_FPB]; + short outdata[MAX_FPB]; + + unsigned int i; + + (void) timeInfo; + (void) statusFlags; + + assert(inputBuffer != NULL); + assert(outputBuffer != NULL); + + if (statusFlags) + printf("cb1 statusFlags: 0x%x\n", (int)statusFlags); + + // + // RX side processing -------------------------------------------- + // + + // assemble a mono buffer (just use left channel if stereo) and write to FIFO + + assert(framesPerBuffer < MAX_FPB); + + for(i = 0; i < framesPerBuffer; i++, rptr += cbData->inputChannels1) + { + indata[i] = *rptr; + } + if (fifo_write(cbData->infifo1, indata, framesPerBuffer)) { + //printf("infifo1 full\n"); + } + // OK now set up output samples for this callback if (fifo_read(cbData->outfifo1, outdata, framesPerBuffer) == 0) @@ -1673,6 +1648,7 @@ int MainFrame::rxCallback( } else { + //printf("outfifo1 empty\n"); // zero output if no data available for(i = 0; i < framesPerBuffer; i++, wptr += 2) { @@ -1680,7 +1656,6 @@ int MainFrame::rxCallback( wptr[1] = 0; } } - //printf("end cb1\n"); return paContinue; } @@ -1745,7 +1720,7 @@ void MainFrame::per_frame_rx_processing( // compute rx spectrum & get demod stats, and update GUI plot data fdmdv_get_rx_spectrum(g_pFDMDV, rx_spec, rx_fdm, nin_prev); fdmdv_get_demod_stats(g_pFDMDV, &g_stats); - + // Average rx spectrum data using a simple IIR low pass filter for(i = 0; i < FDMDV_NSPEC; i++) { @@ -1769,9 +1744,9 @@ void MainFrame::per_frame_rx_processing( case 0: // mute output audio when out of sync - for(i = 0; i < N8; i++) - output_buf[i] = 0; - fifo_write(output_fifo, output_buf, N8); + for(i = 0; i < N8; i++) + output_buf[i] = 0; + fifo_write(output_fifo, output_buf, N8); if((g_stats.fest_coarse_fine == 1) && (g_stats.snr_est > 3.0)) { @@ -1898,15 +1873,13 @@ int MainFrame::txCallback( short indata[MAX_FPB]; short outdata[MAX_FPB]; - //printf("%d cb2 ... %d", cb2++,cb1-cb2); + if (statusFlags) + printf("cb2 statusFlags: 0x%x\n", (int)statusFlags); // assemble a mono buffer (just use left channel) and write to FIFO assert(framesPerBuffer < MAX_FPB); - //if (statusFlags) - // printf("statusFlags: 0x%x\n", statusFlags); - for(i = 0; i < framesPerBuffer; i++, rptr += cbData->inputChannels2) { indata[i] = *rptr; @@ -1914,11 +1887,13 @@ int MainFrame::txCallback( //#define SC2_LOOPBACK #ifdef SC2_LOOPBACK + for(i = 0; i < framesPerBuffer; i++, wptr += 2) { wptr[0] = indata[i]; wptr[1] = indata[i]; } + #else fifo_write(cbData->infifo2, indata, framesPerBuffer); diff --git a/fdmdv2/src/fdmdv2_main.h b/fdmdv2/src/fdmdv2_main.h index 0d28362e..3f3d3600 100644 --- a/fdmdv2/src/fdmdv2_main.h +++ b/fdmdv2/src/fdmdv2_main.h @@ -49,7 +49,7 @@ #include "dlg_audiooptions.h" #define _USE_TIMER 1 -//#define _USE_ONIDLE 1 +#define _USE_ONIDLE 1 #define _DUMMY_DATA 1 //#define _AUDIO_PASSTHROUGH 1 #define _REFRESH_TIMER_PERIOD (DT*1000) @@ -93,9 +93,6 @@ class MainApp : public wxApp wxString m_strVendName; wxString m_StrAppName; -// wxRadioButton m_radioBtnPortAudio; -// wxRadioButton m_radioBtnFileOnly; - wxString m_textNumChOut; wxString m_textNumChIn; @@ -111,6 +108,7 @@ class MainApp : public wxApp wxString m_strRigCtrlDatabits; wxString m_strRigCtrlStopbits; wxString m_strRigCtrlParity; + int m_show_wf; int m_show_spect; int m_show_scatter; @@ -122,6 +120,8 @@ class MainApp : public wxApp wxRect m_rTopWindow; + int m_framesPerBuffer; + bool loadConfig(); bool saveConfig(); @@ -185,13 +185,18 @@ class MainFrame : public TopFrame PlotScalar* m_panelSpeechIn; PlotScalar* m_panelSpeechOut; PlotScalar* m_panelDemodIn; + bool m_RxRunning; - bool m_TxRunning; + + // PortAudio variables PortAudioWrap *m_rxPa; PortAudioWrap *m_txPa; + paCallBackData *m_rxUserdata; + PaError m_rxErr; PaError m_txErr; + #ifdef _USE_TIMER wxTimer m_plotTimer; #endif @@ -218,6 +223,8 @@ class MainFrame : public TopFrame void *userData ); + void txRxProcessing(); + static void per_frame_rx_processing( FIFO *output_fifo, // decoded speech samples int codec_bits[], // current frame of bits for decoder @@ -310,7 +317,7 @@ class MainFrame : public TopFrame void OnTimer(wxTimerEvent &evt); #endif #ifdef _USE_ONIDLE - void OnIdlge(wxIdleEvent &evt); + void OnIdle(wxIdleEvent &evt); #endif // wxString LoadUserImage(wxImage& image); private: