#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#include <math.h>

/************************************************************************
  GE-Ease (pronounced "Geez")
  The EDACS Beep Eliminator
  (C) 1998 Aaron Rossetto [aaronr@vytalnet.com]

  This program is freeware, and as such, I expect no remuneration from
  this program, nor do I make any warranties as to its effectiveness or
  use.  If you screw up your computer from this program, too bad.  Don't
  come crying to me for money or help.  USE AT YOUR OWN RISK.

  This code may be freely modified and redistributed, so long as my
  name remains in this comment as creator of this program.  Also, if you
  end up making the big bucks from this program, I wanna be cut into the
  deal  :-)
 ************************************************************************/

//--- GLOBALS ---
#define MAX_CHANNELS           30
#define PI                     ( (double) 3.141592654 )

struct _chanInfo
{
  int   channelNo;
  BOOL  stat;
  BOOL  initLO;
  UINT  timerID;
  DWORD loTime;
} channelInfo[MAX_CHANNELS];
int nChannels;
int audioDeviceID;
HANDLE hPort;
HWAVEIN hAudio;
double rOutMin, rOutMax;
double beepLimit;

//--- PROTOTYPES ---
int OpenComm( char *, HANDLE * );
int SelectAudioDevice();
int OpenAudioDevice( int, HWAVEIN * );
void SetChannel( int );
BOOL GetSquelchStatus();
void DoSampling( char * );
BOOL FFTBeep( char * );
void _WriteComm( char * );
void _ReadComm( char * );
void CheckExpire();

//----MAINLINE---------------------------------------------------------
int main( int argc, char **argv )
{
  for( int i = 0; i < MAX_CHANNELS; i++ )
  {
    channelInfo[i].stat = FALSE;
    channelInfo[i].initLO = TRUE;
  }
 
  if( argc < 3 )
  {
    printf( "Usage: %s COM1|COM2|COM3|COM4 beepLimit\n", argv[0] );
    return 1;
  }

  beepLimit = (double) atoi( argv[2] );
  printf( "GE-Ease (a Win32 console application)\n" );
  printf( "(C) 1998 Aaron Rossetto [aaronr@vytalnet.com]\n\n" );
  printf( "Be aware that this program only works with a BC895XLT at the moment.\n\n" );
  printf( "Enter each channel number on your scanner corresponding to the GE system.\n" );
  printf( "Only type one per line.  End with a blank line.  EXCLUDE THE CONTROL CHANNEL.\n" );
  printf( "^C quits while scanning.\n" );

  nChannels = 0;
  char channelEntry[15];
  do
  {
    gets( channelEntry );
    if( strlen( channelEntry ) < 1 )
      break;

    channelInfo[nChannels].channelNo = atoi( channelEntry );
    channelInfo[nChannels].stat = TRUE; 
    channelInfo[nChannels].initLO = FALSE;
    nChannels++;
  }
  while( nChannels < 30 );

  if( nChannels == 0 )
  {
    printf( "No channels entered--program terminating.\n" );
    return 1;
  }

  if( ( audioDeviceID = SelectAudioDevice() ) < 0 ) 
  {
    printf( "No audio input device found or entered--program terminating.\n" );
    return 1;
  }

  if( !OpenAudioDevice( audioDeviceID, &hAudio ) )
  {
    printf( "Can't open audio device ID %d--program terminating.\n", audioDeviceID );
    return 1;
  }
 
  if( !OpenComm( argv[1], &hPort ) )
  {
    printf( "Can't open communications port %s--program terminating.\n", argv[1] );
    waveInClose( hAudio );
    return 1;
  }

  while( 1 )
  {
    CheckExpire();

    for( i = 0; i < MAX_CHANNELS; i++ )
    {
      if( !channelInfo[i].stat )
        continue;

      SetChannel( channelInfo[i].channelNo );
      if( !GetSquelchStatus() )
        continue;

      printf( "** Activity: channel %d\n", channelInfo[i].channelNo );
      char audioData[1024];
      BOOL foundBeep = FALSE;
      rOutMin = 10000.0;
      rOutMax = -10000.0;
      BOOL bailFlag = FALSE;
      while( !foundBeep )
      {
        DoSampling( audioData );
        foundBeep = FFTBeep( audioData );
        if( !GetSquelchStatus() )
        {
          bailFlag = TRUE;
          break;
        }
      }
      if( !bailFlag )
      {
        channelInfo[i].stat = FALSE;
        channelInfo[i].loTime = GetTickCount();
      }
      printf( "\n" );
    }
  }
} 

//---------------------------------------------------------------------
void CheckExpire()
{
  DWORD now = GetTickCount();

  for( int i = 0; i < MAX_CHANNELS; i++ )
  {
    if( ( !channelInfo[i].stat ) && ( !channelInfo[i].initLO ) )
    {
      if( ( GetTickCount() - channelInfo[i].loTime ) > 3000 )
      {
        channelInfo[i].stat = TRUE;
        printf( "** Channel %d restored\n", channelInfo[i].channelNo );
      }
    }
  }
}

//---------------------------------------------------------------------
int OpenComm( char *comPort, HANDLE *hCommPort )
{
  HANDLE hComm;
  DCB     portDCB;

  hComm = CreateFile( comPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,
                      OPEN_EXISTING, 0, NULL );
  if( hComm == INVALID_HANDLE_VALUE )
  {
    printf( "CreateFile error on %s [%ld].\n", comPort, GetLastError() );
    return 0;
  }

  if( !GetCommState( hComm, &portDCB ) )
  {
    CloseHandle( hComm );
    return 0;
  }

  portDCB.BaudRate = CBR_9600;
  portDCB.Parity = FALSE;
  portDCB.fDtrControl = DTR_CONTROL_DISABLE;
  portDCB.fRtsControl = RTS_CONTROL_DISABLE;
  portDCB.fOutX = FALSE;
  portDCB.fInX = FALSE;
  portDCB.fAbortOnError = FALSE;
  portDCB.ByteSize = 8;
  portDCB.Parity = NOPARITY;
  portDCB.StopBits = ONESTOPBIT;
  portDCB.fNull = FALSE;

  if( !SetCommState( hComm, &portDCB ) )
  {
    CloseHandle( hComm );
    return 0;
  }

  *hCommPort = hComm;
  return 1;
}

//---------------------------------------------------------------------
int SelectAudioDevice()
{
  UINT nAudio = waveInGetNumDevs();
  if( nAudio < 1 )
    return -1;
  int selection;

  printf( "\nSelect an audio input device:\n" );

  WAVEINCAPS devCaps;
  for( UINT i = 0; i < nAudio; i++ )
  {
    MMRESULT result = waveInGetDevCaps( i, &devCaps, sizeof( WAVEINCAPS ) );
    if( result == MMSYSERR_NOERROR )
      printf( "%d: %s\n", i, devCaps.szPname );
    else
    {
      printf( "Can't determine audio device's capabilities [%d].\n", result );
      return -1;
    }
  }

  do
  {
    printf( ">" );
    scanf( "%d", &selection );
  }
  while( ( selection < 0 ) || ( selection > nAudio ) );

  return selection;
}

//---------------------------------------------------------------------
int OpenAudioDevice( int devID, HWAVEIN *hWaveDev )
{
  WAVEFORMATEX waveFormat;
  waveFormat.wFormatTag = WAVE_FORMAT_PCM;
  waveFormat.nChannels = 1;
  waveFormat.nSamplesPerSec = 22050;
  waveFormat.nAvgBytesPerSec = 22050;
  waveFormat.nBlockAlign = 1;
  waveFormat.wBitsPerSample = 8;
  waveFormat.cbSize = 0;

  MMRESULT result = waveInOpen( hWaveDev, devID,
                                &waveFormat, NULL, NULL, CALLBACK_NULL );
  if( result != MMSYSERR_NOERROR )
  {
    printf( "Can't open selected audio in device [%d].\n", result );
    return 0;
  }
 
  return 1;
}

//---------------------------------------------------------------------
void SetChannel( int chanNo )
{
  char scannerData[16];
  char result[128];

  sprintf( scannerData, "MA%03d\x0d", chanNo );
  _WriteComm( scannerData );
  _ReadComm( result );

  if( strncmp( result, "ERR", 3 ) == 0 )
    printf( "** Error: Can't set scanner to channel %d\n", chanNo );
}

//---------------------------------------------------------------------
BOOL GetSquelchStatus()
{
  char result[128];

  _WriteComm( "SQ\x0d" );
  _ReadComm( result );
  if( result[0] == '-' )
    return 0;
  if( result[0] == '+' )
    return 1;

  return 0;
}

//---------------------------------------------------------------------
void DoSampling( char *pAudioData )
{
  WAVEHDR audioInfo;
  audioInfo.lpData = pAudioData;
  audioInfo.dwBufferLength = 1024L;
  audioInfo.dwUser = 0L;
  audioInfo.dwFlags = 0L;
  audioInfo.dwBytesRecorded = 0L;
  audioInfo.dwFlags = 0L;

  MMRESULT result = waveInPrepareHeader( hAudio, &audioInfo, sizeof( WAVEHDR ) );
  if( result != MMSYSERR_NOERROR )
  {
    printf( "** Error preparing header\n" );
    return;
  }

  result = waveInAddBuffer( hAudio, &audioInfo, sizeof( WAVEHDR ) );
  if( result != MMSYSERR_NOERROR )
  {
    printf( "** Error adding buffer\n" );
    return;
  }

  result = waveInStart( hAudio );
  if( result != MMSYSERR_NOERROR )
  {
    printf( "** Error starting recording\n" );
    return;
  }

  while( ( audioInfo.dwFlags & WHDR_DONE ) == 0 );

  result = waveInUnprepareHeader( hAudio, &audioInfo, sizeof( WAVEHDR ) );
  if( result != MMSYSERR_NOERROR )
    printf( "** Error unpreparing header\n" );

}

//---------------------------------------------------------------------
BOOL FFTBeep( char *data )
{
  double rIn[1024], iIn[1024];
  double rOut, iOut;
  double cos1, cos2, cos3, theta, beta;
  double sin1, sin2, sin3;
  int    k;

  for( int i = 0; i < 1024; i++ )
  {
    rIn[i] = (double) ( (unsigned char) data[i] );
    iIn[i] = 0.0;
  }

  rOut = iOut = 0.0;
  theta = ( 2 * PI ) * 223 / 1024;
  sin1 = sin( -2 * theta );
  sin2 = sin( -theta );
  cos1 = cos( -2 * theta );
  cos2 = cos( -theta );
  beta = 2 * cos2;
  for( k = 0; k < 1024; k++ )
  {
    sin3 = beta * sin2 - sin1;
    sin1 = sin2;
    sin2 = sin3;
    cos3 = beta * cos2 - cos1;
    cos1 = cos2;
    cos2 = cos3;

    rOut = rOut + ( rIn[k] * cos3 ) - ( iIn[k] * sin3 );
//  iOut = iOut + ( iIn[k] * cos3 ) + ( rIn[k] * sin3 );
  }

  if( rOut < rOutMin )
    rOutMin = rOut;
  if( rOut > rOutMax )
    rOutMax = rOut;
  printf( "%7.2f  %7.2f\r", rOutMin, rOutMax );
  return( ( rOut > beepLimit ) || ( rOut < -beepLimit ) );
}

//---------------------------------------------------------------------
void _WriteComm( char *string )
{
  DWORD nRead;

  WriteFile( hPort, string, strlen( string ), &nRead, 0 );
}

//---------------------------------------------------------------------
void _ReadComm( char *buffer )
{
  DWORD nRead;
  int   bufPtr = 0;

  ReadFile( hPort, &buffer[bufPtr], 1, &nRead, 0 );
  while( 1 )
  {
    if( buffer[bufPtr] < 32 )
    {
      buffer[bufPtr] = 0;
      return;
    }

    bufPtr++;
    ReadFile( hPort, &buffer[bufPtr], 1, &nRead, 0 );
  }
}


syntax highlighted by Code2HTML, v. 0.9.1