/*************************************************************************** * Copyright (C) 2004 by Johan Maes - ON4QZ * * on4qz@telenet.be * * http://users.telenet.be/on4qz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "dspfunctions.h" #include #include "qsstvglobal.h" #include #include // used by memmove #include "fftdisplay.h" #include "wavio.h" #include "configdialog.h" #include "synthes.h" #include "utils.h" #define VOLINTEGRATOR 0.01 //#define DEBUGDSPFUNC dspFunctions *dsp; int idefaultFilter; int idefaultPostFilter; const char *filterString[NUMFILTERS]= { "400 Hz", "600 Hz", "800 Hz", "1000 Hz" }; const char *postFilterString[NUMPOSTFILTERS]= { "200 Hz", "400 Hz", "600 Hz", "NO Filter" }; dspFunctions::dspFunctions(fftDisplay *fftDPtr) { fftDisplayPtr=fftDPtr; fftDisplayPtr->initFFT(1024,samplingrate); writeInputIndex=0; writeOutputIndex=0; sndPtr=NULL; resIprev=0; resQprev=0; timer=new QTimer(this); connect(timer, SIGNAL(timeout()),this,SLOT(slotReceiveData())); captureFromSoundcard=TRUE; // setup the soundcard (by default in receive) if (sndPtr==NULL) { sndPtr=new soundcard(samplingrate); connect(sndPtr,SIGNAL(signalStopped()),this,SLOT(slotTXStopped())); } wave=new wavIO(samplingrate); numberOfSamples=0; dataPtr=NULL; Fc=1750.; osc.init(Fc/rxClock); angleToFc=rxClock/(2*M_PI); running=FALSE; synth=new synthesizer(txClock); volume=0; } dspFunctions::~dspFunctions() { delete synth; if (sndPtr) delete sndPtr; } /** Set the source to capture from. This is either the soundcard or a wav file */ void dspFunctions::setCaptureSource(bool fromSoundCard, QString *fn,bool rd) { bool res; numberOfSamples=0; dataPtr=NULL; if(fromSoundCard) { captureFromSoundcard=TRUE; } else { captureFromSoundcard=FALSE; if(fn!=NULL) { if(rd) { res=wave->readFile(*fn,FALSE); } else { res=wave->writeFile(*fn,FALSE,TRUE); //we'll use block by block write } } else { if(rd) { res=wave->readFile(QString(""),TRUE); } else { res=wave->writeFile(QString(""),TRUE,TRUE); } } if (res) { logfile.add("setting up wav for read/write"); numberOfSamples=wave->getNumberOfSamples(); dataPtr=wave->getDataPointer(); dataIndex=0; } } } bool dspFunctions::startReceive() { QString errorstring; if(captureFromSoundcard) { if(!sndPtr->startReceive(audioDevice,errorstring)) { QMessageBox::warning(0,"Soundcard error",errorstring,QMessageBox::Ok,0 ); return FALSE; } } // start the fetching data readInputIndex=0; writeInputIndex=0; // readFilteredIndex=0; running=TRUE; timer->start(0,TRUE); return TRUE; } /*! \fn dspFunctions::startTransmit() \brief start Transmitting data */ bool dspFunctions::startTransmit() { QString errorstring; timer->stop(); running=FALSE; if(captureFromSoundcard) { if(!sndPtr->startTransmit(audioDevice,errorstring)) { QMessageBox::warning(0,"Soundcard error",errorstring,QMessageBox::Ok,0 ); return FALSE; } } else { } running=TRUE; writeOutputIndex=0; return TRUE; } //static int fftCounter=0; //static short unsigned int fftPointer=0; /*! \fn dspFunctions::slotReceiveData() \brief collect date-a from soundcard or wav This is an indepedent timer driven routine. It collects data from the soundcard or wavfile into a large buffer \sa startTransmit */ void dspFunctions::slotReceiveData() { bool ok; #ifdef DEBUGDSPFUNC logfile.add("timerresp"); #endif unsigned long int len=0; if(captureFromSoundcard) { do { ok=sndPtr->read((char *)&inputBuffer[writeInputIndex]); if(ok) { len=sndPtr->audioBufferLen/sizeof(short int); fftDisplayPtr->realFFT(&inputBuffer[writeInputIndex]); demodulate(&inputBuffer[writeInputIndex],len); fftDisplayPtr->repaint(FALSE); writeInputIndex=(writeInputIndex+len)&INPUTINDEXMASK; } } while(ok); timer->start(150,TRUE); } else { if ((writeInputIndex+AUDIOBUFFERSIZE*sizeof(short int))==readInputIndex) { // avoid overrunning timer->start(100,TRUE); return; } len=(numberOfSamples-dataIndex)*2; if (len>(AUDIOBUFFERSIZE*sizeof(short int))) len=AUDIOBUFFERSIZE*sizeof(short int); if(len<=0) { emit signalEndOfInput(); return; } memmove(&inputBuffer[writeInputIndex],&dataPtr[dataIndex],len); len=len/sizeof(short int); fftDisplayPtr->realFFT(&inputBuffer[writeInputIndex]); fftDisplayPtr->repaint(FALSE); demodulate(&inputBuffer[writeInputIndex],len); writeInputIndex=(writeInputIndex+len)&INPUTINDEXMASK; dataIndex+=len; #ifdef DEBUGDSPFUNC logfile.add ("timerreq file"); #endif // timer->start((AUDIOBUFFERSIZE*1000)/samplingrate,TRUE); timer->start(0,TRUE); } } /* void dspFunctions::rerunFilter() { //we repositioned the read pointer unsigned int i; float f; bool s; for (i=0;i2500) demod=2500; if (demod<800) demod=800; // take absolute value of unfiltered input and square it to get the power // do the same with the filtered sync signal // the bandwidth of the filter is 200Hz // the bandwith of the input is 3200Hz resS=fabsf(resS); // absolute value of filtered signal resF=fabsf(samplesS[zeroes/2]); // absolute value of unfiltered signal memmove(averageF, averageF+1, (AVTAPS-1)*sizeof(float)); memmove(averageS, averageS+1, (AVTAPS-1)*sizeof(float)); memmove(averageFreq, averageFreq+1, (AVTAPS-1)*sizeof(float)); averageF[AVTAPS-1]=resF; averageS[AVTAPS-1]=resS; averageFreq[AVTAPS-1]=demod; avFreq=0; resF=resS=0; for(i=0;i4*resF); filteredBuffer[writeInputIndex+k]=avFreq; } } float dspFunctions::postFilter(float val) { unsigned int i; float resI = 0; float *fp1 = samplesPost; const float *cf1 = postFilterPtr; memmove(samplesPost, samplesPost+1, (postFilterLength-1)*sizeof(float)); samplesPost[postFilterLength-1] = val; for(i=0;idelayedStop(); // will send signal back } else { slotTXStopped(); } } /** write in blocks of size audioBufferLen/sizeof(short int) */ bool dspFunctions::put(short int t) { outputBuffer[writeOutputIndex++]=t; if (writeOutputIndex==(sndPtr->audioBufferLen/sizeof(short int))) { if(captureFromSoundcard) { if(sndPtr->write((char *)outputBuffer)) { writeOutputIndex=0; return TRUE; } else { writeOutputIndex--; return FALSE; } } else { writeOutputIndex=0; wave->writeData((char *)outputBuffer,sndPtr->audioBufferLen); } } return TRUE; } /* void dspFunctions::reposition(int len) { readInputIndex-=(len+filterLength+postFilterLength); readInputIndex&=INPUTINDEXMASK; // initFFT(); readFilteredIndex-=len; readFilteredIndex&=INPUTINDEXMASK; rerunFilter(); } */ void dspFunctions::slotTXStopped() { #ifdef DEBUGDSPFUNC logfile.add("dspFunctions::slotTXStopped()"); #endif emit signalTXStopped(); if(!captureFromSoundcard) { wave->writeData(NULL,0); } } eIOState dspFunctions::nextSample(float freq) { eIOState res; if((res=putSample(synth->nextSample(freq)))==WAITING) { synth->unget(); } return res; } /*! \fn dspFunctions::getDuration(int numSamples) \brief returns duration in msec for sampling \a numSamples */ unsigned int dspFunctions::getDuration(int numSamples) { return (int)(((double)numSamples*1000.)/rxClock+0.5); }