/*************************************************************************** * 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. * ***************************************************************************/ #ifndef DSPFUNCTIONS_H #define DSPFUNCTIONS_H #include "soundcard.h" #include "qsstvglobal.h" #include #include #include #include "nco.h" #include "filterparam.h" /** DSP functions: data capture, buffer management, filtering @author Johan Maes - ON4QZ */ class wavIO; class fftDisplay; class synthesizer; #define NUMFILTERS 4 #define NUMPOSTFILTERS 4 #define MAXTAPS 150 #define AVTAPS 50 #define AVFREQ 10 #define AVDELAY ((AVTAPS-AVFREQ)/2) #define BUFFER1M 0x100000 // must be greater than 6 lines SCOTTIE DX #define INPUTBUFFERLEN BUFFER1M #define INPUTINDEXMASK (BUFFER1M-1) #define OUTPUTBUFFERLEN AUDIOBUFFERSIZE #define OUTPUTINDEXMASK (OUTPUTBUFFERLEN-1) //! class for dsp functions class dspFunctions : public QObject { Q_OBJECT public: dspFunctions(fftDisplay *fftDPtr); ~dspFunctions(); void setCaptureSource(bool fromSoundCard, QString *fn=NULL,bool rd=TRUE); bool startReceive(); bool startTransmit(); // void rerunFilter(); unsigned int rewind(unsigned int len); unsigned int forward(unsigned int len); unsigned int reposition(unsigned int len); eIOState getDemodulatedData(float &f,bool &s,unsigned int &pos); eIOState getDemodulatedData(float &f); float getDemodulatedDataAt(unsigned int pos); void setFilter(efilterType filterType); void stop() { timer->stop(); running=FALSE; sndPtr->stop(); } eIOState putSample(short int val); eIOState nextSample(float freq); double getVolume() { return volume; } unsigned int rxCount(); unsigned int getDuration(int numSamples); unsigned int getPos() { return readInputIndex; } void delayedStop(); public slots: void slotReceiveData(); void slotTXStopped(); signals: void signalEndOfInput(); void signalTXStopped(); private: synthesizer *synth; short int inputBuffer[INPUTBUFFERLEN]; short int outputBuffer[OUTPUTBUFFERLEN]; float filteredBuffer[INPUTBUFFERLEN]; bool syncDetectBuffer[INPUTBUFFERLEN]; bool captureFromSoundcard; unsigned long int numberOfSamples; unsigned long int dataIndex; short int *dataPtr; wavIO *wave; fftDisplay *fftDisplayPtr; unsigned int writeOutputIndex; unsigned int writeInputIndex; unsigned int readInputIndex; // unsigned short int readFilteredIndex; soundcard *sndPtr; float resIprev; float resQprev; unsigned int filterLength; unsigned int postFilterLength; QTimer *timer; void demodulate(short int *val,unsigned int len); float postFilter(float val); void setPostFilter(enum epostFilterType t); bool put(short int t); nco osc; const float *filterI; const float *filterS; float samplesI[MAXTAPS]; float samplesQ[MAXTAPS]; float samplesS[MAXTAPS]; float samplesPost[MAXTAPS]; float discRe; float discIm; float Fc; float angleToFc; float *postFilterPtr; float *filterPtr; float averageF[AVTAPS]; float averageS[AVTAPS]; float averageFreq[AVTAPS]; unsigned int test; bool running; double volume; }; /*! \fn dspFunctions::getDemodulatedData(float &f,bool &s,unsigned int &pos) \brief get demodulatated data and sync info from buffer Returns the next sample of demodulated data from the ringbuffer, together with the sync detection logic. The current position in the buffer is returned in \a pos. \param f on return will contain one sample of filtered data \param s TRUE if sync frequency detected, FALSE otherwise \param pos returns the position in the buffer of the sample */ inline eIOState dspFunctions::getDemodulatedData(float &f,bool &s,unsigned int &pos) { if(!running) return STOPPED; while(writeInputIndex==readInputIndex) { return WAITING; } f=filteredBuffer[readInputIndex]; s=syncDetectBuffer[readInputIndex]; pos=readInputIndex++; readInputIndex&=INPUTINDEXMASK; return DONE; } /*! \fn dspFunctions::getDemodulatedData(float &f) \brief get demodulatated data from buffer Returns the next sample of demodulated data from the ringbuffer. \param f on return will contain one sample of filtered data */ inline eIOState dspFunctions::getDemodulatedData(float &f) { if(!running) return STOPPED; while(writeInputIndex==readInputIndex) { return WAITING; } f=filteredBuffer[readInputIndex++]; readInputIndex&=INPUTINDEXMASK; return DONE; } /*! \fn dspFunctions::rxCount() \brief returns the number of available samples in the receive buffer */ inline unsigned int dspFunctions::rxCount() { if(!running) return 0; return ((writeInputIndex-readInputIndex)&INPUTINDEXMASK); } /*! \fn dspFunctions::getDemodulatedDataAt(unsigned int pos) \brief returns the filtered data at position \a pos in the receive buffer */ inline float dspFunctions::getDemodulatedDataAt(unsigned int pos) { return filteredBuffer[pos&INPUTINDEXMASK]; } /*! \fn dspFunctions::rewind(unsigned int len) \brief The new position in the receive buffer is the current position -\a len The new position in the receive buffer is the current position -\a len. No checks are made to ensure that this points to valid data (i.e. len should always be smaller than or equal to the number of valid samples in the ringbuffer */ inline unsigned int dspFunctions::rewind(unsigned int len) { return readInputIndex=(readInputIndex-len)&INPUTINDEXMASK; } /*! \fn dspFunctions::forward(unsigned int len) \brief The new position in the receive buffer is the current position + \a len The new position in the receive buffer is the current position +\a len. No checks are made to ensure that this points to valid data (i.e. the current position + \a len should always be smaller than or equal to the readInputIndex) */ inline unsigned int dspFunctions::forward(unsigned int len) { return readInputIndex=(readInputIndex+len)&INPUTINDEXMASK; } /*! \fn dspFunctions::reposition(unsigned int pos) \brief Set the current position to \a pos Set the current (=readInputIndex) position to \a pos. No checks are made to ensure that this points to valid data. */ inline unsigned int dspFunctions::reposition(unsigned int pos) { return readInputIndex=(pos&INPUTINDEXMASK); } inline eIOState dspFunctions::putSample(short int val) { if(!running) { return STOPPED; } if(!put(val)) { return WAITING; } return DONE; } extern dspFunctions *dsp; #endif