Logo Search packages:      
Sourcecode: qsstv version File versions  Download package

dspfunc.cpp

/***************************************************************************
                          dspfunc.cpp  -  QSSTV
                             -------------------
    begin                : Tue Apr 17 22:27:58 CEST 2001
    copyright            : (C) 2001 by Johan Maes ON1MH
    email                : on1mh@pandora.be
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "dspfunc.h"
#include <qmessagebox.h>
#include "qsstvglobal.h"
#include <qtimer.h>
#include <math.h>
#include <string.h> // used by memmove
#include "soundcard.h"
#include "fft.h"

//#include "configfile.h"

#include "filterparam.h"

//#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()
{
      readInputPtr=0;
      writeInputPtr=0;
      writeOutputPtr=0;
      sndPtr=NULL;
      resIprev=0;
      resQprev=0;
      timer=new QTimer(this);
      connect(timer, SIGNAL(timeout()),this,SLOT(slotReceiveData()));
      finput.setName("test");
      
//    initFFT();
// recording=FALSE;
}


dspFunctions::~dspFunctions()
{
      if (sndPtr) delete sndPtr;
}

void dspFunctions::computeSineTable(int fs,int fc,int istep)
{
      angleToFc=fs/(2*M_PI);
  sineIndex=0;
  Fc=(float)fc;
  step=istep;

  // both the samplingfreq. and the carrier frequency must be a integral
  // multiple of step.

  sineLen=fs/(fc/step);
  cosOffset=sineLen/4;

  // use a table of at least 1 full-cycle + 90 degrees
  // then we only have to check the index once for wrap-around
  // when calculating the sine and cosine

  for (int i=0;i<128;i++)
    {
       mixerSineTable[i]=sin((2.*M_PI*(double)i)/(double)sineLen);
    } 
      
}

void dspFunctions::initDSP(unsigned int sampleRate)
{
      // setup the soundcard (by default in receive)
      if (sndPtr==NULL)
            {
                  sndPtr=new  soundcard(sampleRate);
                  connect(sndPtr,SIGNAL(signalStopped()),this,SLOT(slotTXStopped()));
            }
      computeSineTable(sampleRate,1750,7);
}


bool dspFunctions::startReceive()
{
//    int i;
      QString errorstring;
      if(!finput.isOpen())
            {
            if(!sndPtr->startReceive(configFile.readOption("Audiodev"),errorstring))
                  {
                        QMessageBox::warning(0,"Soundcard error",errorstring,QMessageBox::Ok,0 );
                        return FALSE;
                  }
            }
      // start the fetching data
      readInputPtr=0;
      writeInputPtr=0;
      readFilteredPtr=0;
      
#ifdef DSPDEBUG
      debug ("timerreq start");
#endif
      timer->start(0,TRUE);
      return TRUE;
}

bool dspFunctions::startTransmit()
{
      QString errorstring;
      timer->stop();
      if(!sndPtr->startTransmit(configFile.readOption("Audiodev"),errorstring))
            {
                  QMessageBox::warning(0,"Soundcard error",errorstring,QMessageBox::Ok,0 );
                  return FALSE;
            }
      writeOutputPtr=0;
      return TRUE;
}

void dspFunctions::setFFTDisplayPointer(fft *t)
{
            fftPtr=t;
            fftPtr->initFFT(1024);
}

//static int fftCounter=0;
//static short unsigned int fftPointer=0;

void dspFunctions::slotReceiveData()
{
#ifdef DEBUGDSPFUNC
      debug ("timerresp");
#endif
      int len=0;

      if(!finput.isOpen())
            {
                  do
                        {
                              len=sndPtr->readBuffer((char *)&inputBuffer[writeInputPtr]);
                              if(len>0)
                                    {
                                          len=len/sizeof(short int);
                                          fftPtr->realFFT(&inputBuffer[writeInputPtr]);
                                          fftPtr->repaint(FALSE);
                                          writeInputPtr+=len;
                                    }
                        }
                  while(len>0);
#ifdef DEBUGDSPFUNC
            debug ("timerreq sc");
#endif
            timer->start(150,TRUE);
            }
      else
            {
                  if ((writeInputPtr+AUDIOBUFFERSIZE*sizeof(short int))==readInputPtr)
                        {
                              // avoid overrunning
                              timer->start(100,TRUE);
                              return;
                        }
                  len=finput.readBlock((char *)&inputBuffer[writeInputPtr],AUDIOBUFFERSIZE*sizeof(short int));
                  if(len<=0)
                        {
                              finput.close();
                              emit signalEndOfInput();
                              return;
                        }
                  len=len/sizeof(short int);
                  fftPtr->realFFT(&inputBuffer[writeInputPtr]);
                  fftPtr->repaint(FALSE);
                  writeInputPtr+=len;
                                    
#ifdef DEBUGDSPFUNC
                  debug ("timerreq file");
#endif
                  timer->start(5,TRUE);   
            }
}

void dspFunctions::rerunFilter()
{
      //we repositioned the read pointer
      int i;
      sineIndex=0; // we can choose whatever starting point
      for (i=0;i<filterLength+postFilterLength;i++)
            {
                  demodulate(inputBuffer[readInputPtr++]);
            }
}


float dspFunctions::demodulate(short int val)
{
      float resI=0;
      float resQ=0;
      float fval;
      int i;
      
      cf1 = filterI;
  fp1 = samplesI;
  fp2 = samplesQ;
      memmove(samplesI+1, samplesI, (filterLength-1)*sizeof(float));
  memmove(samplesQ+1, samplesQ, (filterLength-1)*sizeof(float));
  fval=(float) val;
      
      samplesI[0] = fval*mixerSineTable[sineIndex];
  samplesQ[0] = fval*mixerSineTable[sineIndex+cosOffset];
  sineIndex+=step;
  sineIndex=(sineIndex>=sineLen ? sineIndex-sineLen :sineIndex);
      for(i=0;i<filterLength;i++,fp1++,fp2++,cf1++)
            {
            resI+=(*fp1)*(*cf1);
            resQ+=(*fp2)*(*cf1);
            }
      discRe=resI*resIprev+resQ*resQprev;
  discIm=-resQ*resIprev+resQprev*resI;
  volume=(volume*(1.-VOLINTEGRATOR) +VOLINTEGRATOR*sqrt((resIprev*resIprev+resQprev*resQprev)));
  resIprev=resI;
  resQprev=resQ;
  if(discRe==0)
      {
      discRe=0.0001;
      }
  fval=(Fc-atan(discIm/discRe)*angleToFc);
//  computeFFT(fval);
  fval=lowpass(fval);
  return fval;
}


float dspFunctions::lowpass(float val)
{
  int i;
  float resI = 0;
  fp1 = lpsamples;
  cf1 = postFilterI;
  memmove(lpsamples+1, lpsamples, (postFilterLength-1)*sizeof(float));
  lpsamples[0] = val;

      for(i=0;i<postFilterLength;i++,fp1++,cf1++)
      {
      resI+=(*fp1)*(*cf1);
            }
      return resI;
}


int dspFunctions::getVolume()
{
      return ((int)(8000*log10(volume)));
}

void dspFunctions::setFilter(efilterType filterType)
{
  int i;
  const float *qmfI=0;
  filterLength=FILTAPS;
  switch (filterType)
    {
      case F400: qmfI=fir_main400;  break;
      case F600: qmfI=fir_main600; break;
      case F800: qmfI=fir_main800;break;
            case F1000: qmfI=fir_main1000;break;
/*
            case F600: qmfI=lp600_800I; break;
      case F800: qmfI=lp800_1000I;break;
      case F1000: qmfI=lp1000_1200I;break; */
      
    }
  for (i=0;i<filterLength;i++)
    {
      filterI[i]=qmfI[i];
   }
}


void dspFunctions::setPostFilter(enum epostFilterType t)
{
      int i;
  const float *pofI=0;
  float sum=0.;
  postFilterLength=POSTFILTAPS;
  switch (t)
      {
            case NARROW:
                  pofI=fir_post200;
            break;
            case MEDIUM:
                  pofI=fir_post400;
            break;
            case WIDE:
                  pofI=fir_post600;
            break;
            case POSTNONE:
                  pofI=fir_postNONE;
            break;
      }
      for (i=0;i<postFilterLength;i++)
      {
            postFilterI[i]=pofI[i];
            sum+=postFilterI[i];
      }
#ifdef DEBUGDSPFUNC
     debug("filtersum=%f",sum);
#endif      
}

void dspFunctions::delayedStop()
{
#ifdef DEBUGDSPFUNC
   debug("dspFunctions::delayedStop()");
#endif
      sndPtr->delayedStop(); // will send signal back
}

bool dspFunctions::put(short int t)
{
      outputBuffer[writeOutputPtr++]=t;
      if (writeOutputPtr==(sndPtr->audioBufferLen/sizeof(short int)))
            {
                  if(!foutput.isOpen())
                        {
                              if(sndPtr->writeBuffer((char *)outputBuffer))
                                    {
                                          writeOutputPtr=0;
                                          return TRUE;
                                    }
                              else
                                    {
                                          writeOutputPtr--;
                                          return FALSE;
                                    }
                        }
                  else
                        {
                              writeOutputPtr=0;
                              foutput.writeBlock((char *)outputBuffer,sndPtr->audioBufferLen);
                        }
                  }
      return TRUE;
}

void dspFunctions::cancelDump()
{
      disableDump();
      foutput.remove();
}

void dspFunctions::disableDump()
{
      enableDump(NULL,NULL);
}

void dspFunctions::enableDump(const QString &nameRx,const QString &nameTx)
{
      timer->stop();
      if(sndPtr) sndPtr->stop();
      finput.close();
      foutput.close();
      if(nameRx)
            {
                  finput.setName(nameRx);
                  finput.open(IO_Raw|IO_ReadOnly);    
            }
      else if(nameTx)
            {
                  foutput.setName(nameTx);
                  foutput.open(IO_Raw|IO_WriteOnly|IO_Truncate);
            }
}

void dspFunctions::stop()
{
#ifdef DEBUGDSPFUNC
      debug("dspFunctions::stop()");
#endif
      disableDump(); //stops everything
}


void dspFunctions::reposition(short unsigned int len)
{
      readInputPtr-=(len+filterLength+postFilterLength);
//    initFFT();
      readFilteredPtr-=len;
      rerunFilter();
}

void dspFunctions::slotTXStopped()
{
#ifdef DEBUGDSPFUNC
      debug("dspFunctions::slotTXStopped()");
#endif
      emit signalTXStopped();
}


Generated by  Doxygen 1.6.0   Back to index