/**************************************************************************/
/* svgafft --  Spectrum Analyzer                                          */
/*                                                                        */ 
/* signal class implementation                                            */
/**************************************************************************/

/**************************************************************************

    Copyright (C) 1995 Andrew Veliath

    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., 675 Mass Ave, Cambridge, MA 02139, USA.


***************************************************************************/

// $Id: signal.cc,v 0.10 1995/05/01 22:04:54 drewvel Exp $             

#include <iostream.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/soundcard.h>
#include <sys/ioctl.h>
#include "signal.h"

/*******************************************************************/
/* friendly functions                                              */
/*******************************************************************/

/*******************************************************************/
void ShowDSPSettings(Signal& s)
{
  int rate, bits, channels;
  ioctl(s.sig, SOUND_PCM_READ_BITS, &bits);
  ioctl(s.sig, SOUND_PCM_READ_CHANNELS, &channels);
  ioctl(s.sig, SOUND_PCM_READ_RATE, &rate);
  cout << "bit resolution: " << bits << endl;
  cout << "channels: " << channels << endl;
  cout << "sampling rate: " << rate << endl;
}


/*******************************************************************/
/* Signal Methods                                                  */
/*******************************************************************/

/*******************************************************************/
Signal::Signal(char *fname, Parms& parms) 
{
  p=parms;
  InitSignal(fname);
}


/*******************************************************************/
Signal::~Signal() 
{
  CloseSignal();
}


/*******************************************************************/
boolean Signal::SetDSPValue(int cmd, char *name, int& parm, 
			    int comtype, int d)
{
  int orig;
  boolean ok=true;

  DOUT(cerr << name << " query: " << parm);

  orig=parm;
  if (ioctl(sig, cmd, &parm)==-1) {
    cerr << "ioctl() failed with " << parm << "." << endl;
    ok=false;
  } else {

    switch (comtype) {
    case 1:
      if (parm!=orig) {
	cerr << "error:  got " << parm << " for " << name << endl;
	cerr << "query was for " << orig << endl;
	ok=false;
      } else 
	DOUT("got " << parm);
      break;

    case 2:
    if (abs(parm-orig)>d) {
	cerr << "error: deviation too high for " << name << ", got " 
	  << parm << "." << endl;
	cerr << "query was " << orig << endl;
	ok=false;
      } else 
	DOUT("got " << parm);
      break;            

    default:
      ok=false;
    }
    
  }
  return ok;
}


/*******************************************************************/
boolean Signal::UpdateParms(Parms& parms)
{
  boolean ok=true;
  int parm;
  
  DOUT("signal->UpdateParms()");

  if (sigOpen) {
    // sync sound
    ioctl(sig, SOUND_PCM_SYNC, 0);
    
    // set bit resolution
    parm=parms.Bit_Resolution;
    ok=ok && SetDSPValue(SOUND_PCM_WRITE_BITS, "bit resolution", parm);
    parms.Bit_Resolution=parm;

    // set to mono mode
    parm=1;
    ok=ok && SetDSPValue(SOUND_PCM_WRITE_CHANNELS, "channels", parm);

    // set sample rate
    parm=parms.Sample_Rate;
    ok=ok && SetDSPValue(SOUND_PCM_WRITE_RATE, "sampling rate", parm, 2, 2048);
    parms.Sample_Rate=parm;

    // if OK then use new parameters
    if (ok) p=parms;

  } 
  else 
    return false;

  return ok;
}


/*******************************************************************/
boolean Signal::DivDMABuffer(int num)
{
  boolean ok=true;

  if (sigOpen) 
    /* reduce dma buffer to improve response for
       smaller sampling rates */        
    ok=SetDSPValue(SOUND_PCM_SUBDIVIDE, "subdivide dma buffer", num);
  
  return ok;
}


/*******************************************************************/
boolean Signal::InitSignal(char *fname)
{
  CloseSignal();
  
  boolean ok;

  sig=open(fname, O_RDONLY);
  if (sig>0) {

    sigOpen=true;
    
    DivDMABuffer(4);
      
    ioctl(sig, SOUND_PCM_RESET, 0);
   
    ok=UpdateParms(p);

    if (ok) return true;    
    else return false;    

  } else {
    sigOpen=false;
    return false;
  }
}


/*******************************************************************/
void Signal::Flush()
{
  if (sigOpen)
    ioctl(sig, SOUND_PCM_SYNC, 0);
}    


/*******************************************************************/
void Signal::CloseSignal()
{
  if (sigOpen) {
    ioctl(sig, SOUND_PCM_RESET, 0);
    close(sig);
    sigOpen=false;
  }
}


/*******************************************************************/
void Signal::SetParms(Parms& parms) 
{
  p=parms;
}

/*******************************************************************/
Parms& Signal::GetParms() 
{
  return p;
}


/*******************************************************************/
