Talk About Network



Register and Login
Nick
Password
Register create new account Sign up is FREE and you can post replies, new topics, bookmark posts and more!
Recover lost password


Gaming > Development Audio > Any use for thi...
Latest [ Topics | Posts ] Archive Post A New Topic Post a Reply
<< Topic < Post Post 1 of 1 Topic 64 of 129
Post > Topic >>

Any use for this code? (reply to publicgis_d AT rogers dot com)

by "Wave" <nospam@[EMAIL PROTECTED] > Aug 31, 2004 at 02:24 AM

This is a command-line win32 program will lets you sample from an audio
card, starting at a preset time and ending at another time. Useful for
recording radio shows.

Any comments, pls reply to publicgis_d AT rogers DOT com

Enjoy

Kevin

============================================================================
==========



//    Copyright 2004: Kevin John Macdonald
//    You are free to use this code for personal use.

#define STRICT
#include <limits.h>
#include <signal.h>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <basetsd.h>
#include <mmreg.h>
#include <dxerr8.h>
#include <dsound.h>
#include "DSUtil.h"


typedef char      HH24MISS[6];

#define SAFE_DELETE(p)  { if(p) { delete (p);  (p)=NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }


// DEFAULT QUALITY PARAMETERS

#define DEFAULT_SAMPLE_FREQ_KHZ  (44)
#define DEFAULT_CHANNELS   (2)
#define DEFAULT_BITS_PER_SAMPLE  (16)

// AMPLITUDE THRESHOLDS

#define INVALID_AMP     (INT_MAX)
#define MAX_AMP_8BIT    (127)
#define MAX_AMP_16BIT    (32767)

// CLIPPING THRESHOLDS
//
// Note: two or more consecutive samples at or above the clip level
// are considered to be clipped samples (ie. input signal is too high).

#define CLIP_LEVEL_8BIT    (MAX_AMP_8BIT - 2)
#define CLIP_LEVEL_16BIT   (MAX_AMP_16BIT - 2)

// OTHER MANIFEST CONSTANTS

#define VERSION      "1.0"
#define SECONDS_IN_HOUR    (60 * 60)
#define SECONDS_IN_DAY    (24 * SECONDS_IN_HOUR)
#define BUF_SIZE_IN_SECONDS   (5)
#define NUM_POS_NOTIFICATIONS  (BUF_SIZE_IN_SECONDS * 2)
#define MIN_NOTIFY_SIZE    (2048)
#define MAX_AUDIO_DRIVER_GUIDS  (20)
#define MAX_AUDIO_DRIVER_DESC_LEN (100)
#define POLL_INTERVAL_MSEC   (250)


GUID       audioDriverGUIDs[MAX_AUDIO_DRIVER_GUIDS];
char
audioDriverDesc[MAX_AUDIO_DRIVER_GUIDS][MAX_AUDIO_DRIVER_DESC_LEN+1];
char
audioDriverName[MAX_AUDIO_DRIVER_GUIDS][MAX_AUDIO_DRIVER_DESC_LEN+1];
int        numAudioDrivers = 0;

const GUID *     captureDeviceGUID = 0;
DSBPOSITIONNOTIFY    posNotify[NUM_POS_NOTIFICATIONS + 1];

int        fmt = 0;

int        notifySize = 0;
int        captureBufferSize = 0;
int        nextCaptureOffset = 0;

WAVEFORMATEX     wfxInput;

HANDLE       notificationEvent = 0;

CWaveFile *      waveFile = 0;

IDirectSoundCapture *   dsc = 0;
IDirectSoundCaptureBuffer *  dscb = 0;
IDirectSoundNotify *   dsn = 0;

// Set to true if interrupt signal is caught to indicate to shutdown.
bool       shutdownSignalled = false;


void cvtTimetToComponents (
 const time_t    delay,
 int &      hr,
 int &      min,
 int &      sec)
{
 hr = delay / SECONDS_IN_HOUR;
 min = (delay - hr * SECONDS_IN_HOUR) / 60;
 sec = delay % 60;
}


const char * getTimeHH24MISS ()
{
 const time_t    long_now = time (0);
 const struct tm * const  now = localtime (&long_now);
 static char     hh24miss[7];

 if (! now) {
  printf ("localtime failed.\n");
  hh24miss[0] = 0;
 } else {
  sprintf (hh24miss, "%02d%02d%02d", now->tm_hour, now->tm_min,
now->tm_sec);
 }

 return hh24miss;
}


int cvt99ToInt (
 const char     dig[2])
{
 if ( ! isdigit (dig[0])
  || ! isdigit (dig[1])) {
  return -1;
 }

 return (dig[0] - '0') * 10 + dig[1] - '0';
}


int magnitude (
 const unsigned char   sample)
{
 if (wfxInput.wBitsPerSample != 8) {
  printf ("Internal error on line %d\n", __LINE__);
  exit (1);
 }

 if (sample == 0) {
  return 127;
 } else {
  return abs (sample - 128);
 }
}


int magnitude (
 const short     sample)
{
 if (wfxInput.wBitsPerSample != 16) {
  printf ("Internal error on line %d\n", __LINE__);
  exit (1);
 }

 if (sample == -32768) {
  return 32767;
 } else {
  return abs (sample);
 }
}


// Returned string is a null terminated string 38 characters long.

const char * guidToString (
 const GUID * const   guid)
{
 static char     str[40];

 sprintf (str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
    *((unsigned int *)guid), *(((unsigned short *)guid)+2),
    *(((unsigned short *)guid)+3), *(((unsigned char *)guid)+8),
    *(((unsigned char *)guid)+9), *(((unsigned char *)guid)+10),
    *(((unsigned char *)guid)+11), *(((unsigned char *)guid)+12),
    *(((unsigned char *)guid)+13), *(((unsigned char *)guid)+14),
    *(((unsigned char *)guid)+15));
 return str;
}


// Convert time in string 'hh24miss' to time_t value. if error, return -1.

time_t cvtHH24MISSToTime (
 const HH24MISS    hh24miss)
{
 // EXTRACT AND CHECK HOUR, MINUTE AND SECONDS COMPONENTS

 const int     hour = cvt99ToInt (hh24miss);
 const int     min = cvt99ToInt (hh24miss+2);
 const int     sec = cvt99ToInt (hh24miss+4);

 if (hour < 0 || hour > 23) {
  printf ("Bad hour.\n");
  return -1;
 }
 if (min < 0 || min > 59) {
  printf ("Bad minute.\n");
  return -1;
 }
 if (sec < 0 || sec > 59) {
  printf ("Bad second.\n");
  return -1;
 }

 // CONVERT

 const time_t    now_t = time (0);
 const struct tm * const  now_tm = localtime (&now_t);

 struct tm     t;

 t = *now_tm;
 t.tm_hour = hour;
 t.tm_min = min;
 t.tm_sec = sec;

 time_t      then_t = mktime (&t);

 if (then_t == -1) {
  printf ("mktime failed.\n");
  return -1;
 }

 // ADJUST IF TIME IS FOR TOMORROW

 HH24MISS     now;

 memcpy (now, getTimeHH24MISS (), 6);
 if (! now[0]) {
  return -1;
 }

 if (strncmp (hh24miss, now, 6) < 0) {
  printf ("Note: the time '%.6s' occurs tomorrow.\n", hh24miss);
  then_t += SECONDS_IN_DAY;
 }

 return then_t;
}


INT_PTR CALLBACK soundEnumCallback (
 GUID *      guid,
 LPSTR      strDesc,
 LPSTR      strDrvName,
 VOID *      /*pContext*/)
{
 // Skip the default device.
 if (guid && numAudioDrivers < MAX_AUDIO_DRIVER_GUIDS) {
  memcpy (audioDriverGUIDs + numAudioDrivers, guid, sizeof(GUID));
  strncpy ((char *) (audioDriverDesc + numAudioDrivers), strDesc,
MAX_AUDIO_DRIVER_DESC_LEN);
  strncpy ((char *) (audioDriverName + numAudioDrivers), strDrvName,
MAX_AUDIO_DRIVER_DESC_LEN);
  ++numAudioDrivers;
 }

 return TRUE;
}


IDirectSoundCapture * initDirectSound (
 const GUID * const   guid)
{
 IDirectSoundCapture *  p;

 if (CoInitialize (NULL) != S_OK) {
  printf ("Error: Failed to initialize COM library.\n");
  return 0;
 }

 if (DirectSoundCaptureCreate (guid, &p, NULL ) != DS_OK) {
  printf ("Error: Failed to initialize IDirectSoundCapture interface.\n");
  return 0;
 }

 return p;
}


void initWfxInput (
 const int     sampleFreq,
 const int     channels,
 const int     bitsPerSample)
{
 ZeroMemory (&wfxInput, sizeof(wfxInput));
 wfxInput.wFormatTag = WAVE_FORMAT_PCM;

 wfxInput.nSamplesPerSec = sampleFreq;
 wfxInput.wBitsPerSample = (unsigned short) bitsPerSample;
 wfxInput.nChannels = (unsigned short) channels;

 wfxInput.nBlockAlign = (unsigned short) (wfxInput.nChannels *
(wfxInput.wBitsPerSample / 8 ));
 wfxInput.nAvgBytesPerSec = wfxInput.nBlockAlign *
wfxInput.nSamplesPerSec;
}


bool initNotifications ()
{
 if(! dscb) {
  return false;
 }

 notificationEvent = CreateEvent (NULL, FALSE, FALSE, NULL );
 if (notificationEvent == NULL) {
  return false;
 }

 // Create a notification event, for when the sound stops playing
 if (dscb->QueryInterface (IID_IDirectSoundNotify, (VOID**)&dsn) != S_OK)
{
  return false;
 }

 // Setup the notification positions
 for (int i = 0; i < NUM_POS_NOTIFICATIONS; ++i) {
  posNotify[i].dwOffset = notifySize * (i+1) - 1;
  posNotify[i].hEventNotify = notificationEvent;
 }

 // Tell DirectSound when to notify us. the notification will come in the
from
 // of signaled events that are handled in WinMain()
 if (dsn->SetNotificationPositions (NUM_POS_NOTIFICATIONS, posNotify) !=
DS_OK) {
  return false;
 }

 return true;
}


bool createCaptureBuffer (
 WAVEFORMATEX &    wfx)
{
 SAFE_RELEASE (dsn);
 SAFE_RELEASE (dscb);

 // Set the buffer sizes
 captureBufferSize = wfx.nAvgBytesPerSec * BUF_SIZE_IN_SECONDS;

 // Set the notification size
 notifySize = max (MIN_NOTIFY_SIZE, captureBufferSize /
NUM_POS_NOTIFICATIONS);
 notifySize -= notifySize % wfx.nBlockAlign;

 // Create the capture buffer
 DSCBUFFERDESC    d;

 ZeroMemory (&d, sizeof(d));
 d.dwSize  = sizeof(d);
 d.dwBufferBytes = captureBufferSize;
 d.lpwfxFormat   = &wfx;

HRESULT h;
 if((h=dsc->CreateCaptureBuffer (&d, &dscb, 0)) != DS_OK) {
  return false;
 }

 nextCaptureOffset = 0;

 if(! initNotifications ()) {
  return false;
 }

 return true;
}


// Convert volume (expressed in percentage 0-100) into a magnitude value
within the range
// defined by the current dynamic range being sampled.
// domain/range have a somewhat exponential relationahip to mimic
amplitude/decibels
// relationship.

int cvtVolumePctToMagnitude (
 const int     volumePct)
{
 const double    MAX_PCT = 100;

 if (wfxInput.wBitsPerSample == 8) {
  return (int) (MAX_AMP_8BIT * volumePct * volumePct / (MAX_PCT *
MAX_PCT));

 } else if (wfxInput.wBitsPerSample == 16) {
  return (int) (MAX_AMP_16BIT * volumePct * volumePct / (MAX_PCT *
MAX_PCT));

 } else {
  return 0;
 }
}


int cvtMagnitudeToVolumePct (
 const int     magnitude)
{
 const double    MAX_PCT = 100;

 if (wfxInput.wBitsPerSample == 8) {
  return (int) sqrt (MAX_PCT * MAX_PCT * magnitude / MAX_AMP_8BIT);

 } else if (wfxInput.wBitsPerSample == 16) {
  return (int) ceil (sqrt (MAX_PCT * MAX_PCT * magnitude /
MAX_AMP_16BIT));

 } else {
  return 0;
 }
}


// the amplitude of each sample (all channels) in 'buf' (of length
'lenInBytes') are observed.
// output:
//  'cnt' measures the number of samples whose amplitude reach
10%,20%,30%..100% of the amplitude range.
//  'numClipped' measures the number of consecutive samples that exceed
amplitude limits.

void analyzeSamples (
 const void *    buf,
 const int     lenInBytes,
 int       cnt[10],
 int &      numClipped)
{
 for (int i = 0; i < 10; ++i) {
  cnt[i] = 0;
 }
 numClipped = 0;

 int       numSamples = 0;
 int       prevClipped = 0;

 // Performance concerns dictate separate implementations for 8 and 16
bits.
 switch (wfxInput.wBitsPerSample) {

 case 8:
  {for (const unsigned char * p = (const unsigned char *) buf; p < (const
unsigned char *) buf + lenInBytes; ++p) {
   const int mag = magnitude (*p);
   int pct = cvtMagnitudeToVolumePct (mag)/10;

   if (pct == 10) {
    pct = 9;
   }
   ++cnt[pct];
   if (mag >= CLIP_LEVEL_8BIT) {
    ++prevClipped;
   } else {
    if (prevClipped > 1) {
     // Only two or more consecutive samples are considered to have been
clipped.
     numClipped += prevClipped;
    }
    prevClipped = 0;
   }
  }}
  numSamples = lenInBytes;
  break;

 case 16:
  {for (const short * p = (const short *) buf; p < (const short *) buf +
lenInBytes / 2; ++p) {
   const int mag = magnitude (*p);
   int pct = cvtMagnitudeToVolumePct (mag)/10;

   if (pct == 10) {
    pct = 9;
   }
   ++cnt[pct];
   if (mag >= CLIP_LEVEL_16BIT) {
    ++prevClipped;
   } else {
    if (prevClipped > 1) {
     // Only two or more consecutive samples are considered to have been
clipped.
     numClipped += prevClipped;
    }
    prevClipped = 0;
   }
  }}
  numSamples = lenInBytes / 2;
  break;

 default:
  printf ("Undefined bit size.\n");
  numSamples = 1;
  break;
 }

 // NORMALIZE COUNT AND EXPRESS IN PERCENT

 for (i = 0; i < 10; ++i) {
  double     dval = (double) cnt[i] * 100 / numSamples;
  if (dval > 0 && dval < 1) {
   dval = 1;
  }
  cnt[i] = (int) floor (dval + 0.5);
 }
}


// The buffer 'buf' (size='bufLen') should be filtered (ie. discarded) if
its average
// volume is lower than 'volumeCutoff'. Return true if buffer should be
filtered.
// Filtering occurs if
// 1. average volume of all samples in buffer is at or below cutoff.
// 2. number of samples that exceed volume cutoff is less than 0.1% of all
samples.

bool filter (
 const void *    buf,
 const unsigned long   bufLen,
 const int     volumeCutoff)
{
 const int     MAG_THRESHOLD = cvtVolumePctToMagnitude (volumeCutoff);

 if (wfxInput.wBitsPerSample == 8) {
  unsigned char * const bufStart = (unsigned char *) buf;
  unsigned char * const bufEnd = bufStart + bufLen / sizeof (unsigned
char);
  const int    bufSamples = bufEnd - bufStart;
  int      sampleSum = 0;
  int      highSamples = 0;

  for (unsigned char * p = bufStart; p < bufEnd; ++p) {
   const int   mag = magnitude (*p);
   sampleSum += mag;
   if (mag > MAG_THRESHOLD) {
    ++highSamples;
   }
  }
  return sampleSum / bufSamples <= MAG_THRESHOLD
   && highSamples < bufSamples / 1000;

 } else if (wfxInput.wBitsPerSample == 16) {
  short * const   bufStart = (short *) buf;
  short * const   bufEnd = bufStart + bufLen / sizeof (short);
  const int    bufSamples = bufEnd - bufStart;
  int      sampleSum = 0;
  int      highSamples = 0;

  for (short * p = bufStart; p < bufEnd; ++p) {
   const int   mag = magnitude (*p);
   sampleSum += mag;
   if (mag > MAG_THRESHOLD) {
    ++highSamples;
   }
  }
  return sampleSum / bufSamples <= MAG_THRESHOLD
   && highSamples < bufSamples / 1000;

 } else {
  // Unsupported sample size.
  return 0;
 }
}


bool recordCapturedData (
 const int     volumeCutoff,
 const bool     verbose)
{
 // CONSISTENCY CHECK

 if(! dscb) {
  printf ("Internal error on line %d\n", __LINE__);
  return false;
 }
 if(! waveFile) {
  printf ("Internal error on line %d\n", __LINE__);
  return false;
 }

 // IDENTIFY WHICH BUFFER EXTENTS (ONE OR TWO) THAT ARE TO BE WRITTEN

 DWORD      readPos;

 if(dscb->GetCurrentPosition (0, &readPos) != DS_OK) {
  printf ("Cannot get current buf pos.\n");
  return false;
 }

 int       lockSize = readPos - nextCaptureOffset;
 if (lockSize < 0) {
  lockSize += captureBufferSize;
 }

 // Block align lock size so that we are always write on a boundary
 lockSize -= (lockSize % notifySize);
 if (lockSize == 0) {
  return false;
 }

 int       cnt[10];
 int       numClipped;
 void *      ext1 = 0;
 DWORD      extLen1 = 0;
 void *      ext2 = 0;
 DWORD      extLen2 = 0;
 UINT      ioWrite = 0;
 DWORD      extLen = 0;

 // LOCK THE CAPTURE BUFFER

 if (dscb->Lock (nextCaptureOffset, lockSize, &ext1, &extLen1, &ext2,
&extLen2, 0) != DS_OK) {
  printf ("Cannot lock buf.\n");
  return false;
 }

 // WRITE THE CAPTURE BUFFER

 if (verbose) {
  analyzeSamples (ext1, extLen1, cnt, numClipped);
  printf ("%.6s: %3d %3d ", getTimeHH24MISS (), numClipped, cnt[0]);
  for (int i = 1; i < 10; ++i) {
   printf ("%2d ", cnt[i]);
  }
 }

 extLen = extLen1;
 if (volumeCutoff != -1) {
  if (filter (ext1, extLen1, volumeCutoff)) {
   if (verbose) {
    printf ("    (silent)");
   }
   extLen = 0;
  }
 }
 if (verbose) {
  printf ("\n");
 }
 if (extLen > 0 && waveFile->Write (extLen, (BYTE *) ext1, &ioWrite) !=
S_OK) {
  printf ("waveFile->Write 1 failed.\n");
  return false;
 }

 // Move the capture offset along
 nextCaptureOffset += extLen1;
 nextCaptureOffset %= captureBufferSize; // Circular buffer

 // OPTIONALLY WRITE THE SECOND CAPTURE BUFFER

 if (ext2) {
  if (verbose) {
   analyzeSamples (ext2, extLen2, cnt, numClipped);
   printf ("%.6s: %3d %3d ", getTimeHH24MISS (), numClipped, cnt[0]);
   for (int i = 1; i < 10; ++i) {
    printf ("%2d ", cnt[i]);
   }
  }
  extLen = extLen2;
  if (volumeCutoff != -1) {
   if (filter (ext2, extLen2, volumeCutoff)) {
    if (verbose) {
     printf ("    (silent)");
    }
    extLen = 0;
   }
  }
  if (verbose) {
   printf ("\n");
  }
  if (extLen > 0 && waveFile->Write (extLen, (BYTE *) ext2, &ioWrite) !=
S_OK) {
   printf ("waveFile->Write 2 failed.\n");
   return false;
  }

  // Move the capture offset along
  nextCaptureOffset += extLen2;
  nextCaptureOffset %= captureBufferSize; // Circular buffer
 }

 // Unlock the capture buffer
 if (dscb->Unlock (ext1, extLen1, ext2, extLen2) != DS_OK) {
  printf ("Cannot unlock buffer.\n");
  return false;
 }

 return true;
}


// Start recording immediately and end when time = 'finish'.

bool startRecording (
 const time_t    finish,
 const int     volumeCutoff,
 const bool     verbose)
{
 if(dscb->Start (DSCBSTART_LOOPING) != DS_OK) {
  printf ("Failed to start recording.\n");
  return false;
 }

 while (  time (0) < finish
   && ! shutdownSignalled) {
  const int r = WaitForMultipleObjects (1, &notificationEvent, FALSE,
POLL_INTERVAL_MSEC);
  switch (r) {

  case WAIT_FAILED:
   printf ("Failed to start recording.\n");
   goto CLEANUP;

  case WAIT_OBJECT_0 + 0:
   if (! recordCapturedData (volumeCutoff, verbose)) {
    printf ("Failed to record captured data.\n");
    goto CLEANUP;
   }
   break;
  case WAIT_TIMEOUT:
   break;

  default:
   printf ("Internal inconsistency: WaitForMultipleObjects returned %d\n",
r);
  }
 }

CLEANUP:
 if (dscb->Stop () != DS_OK) {
  printf ("Failed to stop recording.\n");
  return false;
 }

 return true;
}


void cleanup ()
{
 SAFE_DELETE(waveFile);

 // Release DirectSound interfaces
 SAFE_RELEASE (dsn);
 SAFE_RELEASE (dscb);
 SAFE_RELEASE (dsc);

 // Release COM
 CoUninitialize();
}


bool setShutdownSigHandler ();
void sigHandler (
 int       sig)
{
 setShutdownSigHandler ();
 if (sig != SIGINT) {
  printf ("Warning: caught unexpected signal '%d'\n", sig);
 }
 printf ("Received shutdown signal. Shutting down soon...\n");
 shutdownSignalled = true;
}

bool setShutdownSigHandler ()
{
 return signal (SIGINT, sigHandler) != SIG_ERR;
}


void showUsage (
 const char * const   prgName)
{
 printf
("\n----------------------------------------------------------------------\n
");
 printf ("Capture a signal from an audio device starting and ending at\n"
   "preset times and save it to a wave file.\n"
   "\n"
   "Usage\n"
   "-----\n"
   "%s { flags } -e end_time wave_filename\n"
   "\n"
         "    Where flags are any of the following:\n"
   "        -f  8 | 11 | 22 |   -- sample frequency (KHz)\n"
   "           44 | 48 | 88 | 96\n"
   "        -c 1 | 2            -- # channels (1=mono, 2=stereo)\n"
   "        -b 8 | 16           -- bits per sample\n"
   "        -s start_time       -- time when recording begins\n"
   "        -e end_time         -- time when recording ends\n"
   "        -v                  -- verbose (report on signal amplitude)\n"
   "        -a volume_cutoff    -- only keep samples above volume cutoff
(0-99%)\n"
   "        -?                  -- show usage info\n"
   "\n"
   "Defaults are -f %d -c %d -b %d -s {now}\n"
   "Both start_time end_time are entered as HH24MISS, where HH24 is
hour\n"
   "(00..23), MI is minute (00..59) and SS is seconds (00..59)\n",
   prgName, DEFAULT_SAMPLE_FREQ_KHZ, DEFAULT_CHANNELS,
DEFAULT_BITS_PER_SAMPLE);

 printf ("\n"
   "Signal Amplitude Report\n"
   "-----------------------\n"
   "The 'v' flag will report on the amplitude of the samples stored in
the\n"
   "audio buffer before they are written to the wave file. A report
occupies\n"
   "one line and is structured as follows:\n"
   "999999: 999999 999 99 99 99 99 99 99 99 99 99 99\n"
   "^       ^      ^   ^  ^  ^  ^  ^  ^  ^  ^  ^  ^\n"
   "|       |      |    \\------------------------/\n"
   "|       |      |     percent of samples whose amplitude are within
the\n"
   "|       |      |     range 0..10%%, 10..20%%, .. 80..90%% and
90..100%%\n"
   "|       |      |\n"
   "|       |      number of samples that have been clipped (ie.
samples\n"
   "|       |      whose amplitude are at 100%%)\n"
   "|       buffer size (in bytes)\n"
   "current time (hh24miss)\n");

 printf ("\n"
   "Product Info\n"
   "------------\n"
   "Version   : %s\n"
   "Build date: %s\n", VERSION, __DATE__);
}


int main (
 int      argc,
 const char **   argv)
{
 // ASSIGN DEFAULT VALUES TO COMMAND LINE PARAMETERS

/*
// for debugging only.
if (argc == 1) {
printf ("Using defaults.\n");
argc=12;
argv[0] = "RecordIt";
argv[1] = "-f";
argv[2] = "44";
argv[3] = "-c";
argv[4] = "2";
argv[5] = "-b";
argv[6] = "16";
argv[7] = "-a";
argv[8] = "10";
argv[9] = "-e";
argv[10] = "095000";
argv[11] = "a.wav";
}
*/


 int      sampleFreq  = DEFAULT_SAMPLE_FREQ_KHZ; // -f
 int      channels  = DEFAULT_CHANNELS;   // -c
 int      bitsPerSample = DEFAULT_BITS_PER_SAMPLE; // -b
 HH24MISS    startHH24MISS = { 0 };     // -s
 HH24MISS    endHH24MISS  = { 0 };     // -e
 int      volumeCutoff = -1;      // -a
 bool     verbose   = false;     // -v
 const char *   waveFilename = 0;

 if (argc < 4) {
  printf ("Missing -e flag and wave filename.\n");
  showUsage (argv[0]);
  return 1;
 }

 // EXTRACT AND VERIFY ALL COMMAND LINE PARAMETERS EXCEPT LAST ONE

 for (int i = 1; i < argc - 1; ++i) {
  if (argv[i][0] != '-') {
   printf ("All arguments except the last must be flags that begin with
'-'.\n");
   showUsage (argv[0]);
   return 1;
  }

  const char    flag = argv[i][1];
  switch (flag) {
  case '?':
   showUsage (argv[0]);
   return 0;
  case 'f':
   sampleFreq  = atoi (argv[++i]);
   break;
  case 'c':
   channels  = atoi (argv[++i]);
   break;
  case 'b':
   bitsPerSample = atoi (argv[++i]);
   break;
  case 's':
   strncpy (startHH24MISS, argv[++i], 6);
   break;
  case 'e':
   strncpy (endHH24MISS, argv[++i], 6);
   break;
  case 'a':
   volumeCutoff = atoi (argv[++i]);
   break;
  case 'v':
   verbose = true;
   break;
  default:
   printf ("Invalid flag: %c\n", flag);
   showUsage (argv[0]);
   return 1;
  }
 }

 // EXTRACT AND VERIFY LAST COMMAND LINE PARAMETER

 waveFilename = argv[argc-1];
 if (! isalpha (waveFilename[0]) && waveFilename[0] != '_') {
  printf ("Last parameter must be wave filename.\n");
  showUsage (argv[0]);
  return 1;
 }

 // ENSURE FILE DOES NOT EXIST

 if (::GetFileAttributes (waveFilename) != -1) {
  printf ("Cannot create new wave file, because a file of that name
already
exists.\n");
  return 1;
 }

 // CHECK EXTRACTED PARAMETER VALUES

 switch (sampleFreq) {
 case 8:
  sampleFreq = 8000;
  break;
 case 11:
  sampleFreq = 11025;
  break;
 case 22:
  sampleFreq = 22050;
  break;
 case 44:
  sampleFreq = 44100;
  break;
 case 48:
  sampleFreq = 48000;
  break;
 case 88:
  sampleFreq = 88200;
  break;
 case 96:
  sampleFreq = 96000;
  break;
 default:
  printf ("Bad argument to flag '-f'.\n");
  showUsage (argv[0]);
  return 1;
 }

 if (channels < 1 || channels > 2) {
  printf ("Bad argument to flag '-c'.\n");
  showUsage (argv[0]);
  return 1;
 }

 if (volumeCutoff < -1 || volumeCutoff > 99) {
   printf ("Bad argument to flag '-a'.\n");
   showUsage (argv[0]);
   return 1;
 }

 if (bitsPerSample != 8 && bitsPerSample != 16) {
  printf ("Bad argument to flag '-b'.\n");
  showUsage (argv[0]);
  return 1;
 }

 time_t      start_t;
 time_t      end_t;

 if (startHH24MISS[0] == 0) {
  // start time defaults to NOW.
  start_t = time (0);
 } else {
  start_t = cvtHH24MISSToTime (startHH24MISS);
 }

 if (start_t == -1) {
  printf ("Cannot initialize start time.\n");
  showUsage (argv[0]);
  return 1;
 }

 if (endHH24MISS[0] == 0) {
  printf ("Missing parameter: -e end_time.\n");
  showUsage (argv[0]);
  return 1;
 }

 end_t = cvtHH24MISSToTime (endHH24MISS);
 if (end_t == -1) {
  printf ("Cannot initialize end time.\n");
  showUsage (argv[0]);
  return 1;
 }

 if (start_t >= end_t) {
  printf ("Start time must precede end time.\n");
  showUsage (argv[0]);
  return 1;
 }

 // ENUMERATE THEN SELECT AUDIO CAPTURE DEVICE

 {
 int       drv = 0;

 numAudioDrivers = 0;
 DirectSoundCaptureEnumerate ((LPDSENUMCALLBACK)soundEnumCallback, 0);

 if (numAudioDrivers == 0) {
  printf ("The computer has no audio capture devices.\n");
  return 1;

 } else if (numAudioDrivers == 1) {
  drv = 0;

 } else {
  printf ("The computer has the following audio capture devices:\n");
  for (int i = 0; i < numAudioDrivers; ++i) {
   printf ("%2d: %s (%s)\n", i, audioDriverDesc[i], audioDriverName[i]);
  }
  printf ("Please select one from list above: ");
  scanf ("%d", &drv);
  if (drv < 0 || drv >= numAudioDrivers) {
   printf ("Error: invalid selection.\n");
   return 1;
  }
 }

 captureDeviceGUID = audioDriverGUIDs + drv;
 printf ("Recording capture device: %s (%s)\n", audioDriverDesc[drv],
audioDriverName[drv]);
 }

 dsc = initDirectSound (captureDeviceGUID);
 if (! dsc) {
  return 1;
 }

 // INITIALIZE AUDIO CAPTURE DEVICE

 initWfxInput (sampleFreq, channels, bitsPerSample);
 if (! createCaptureBuffer (wfxInput)) {
  printf ("Error: cannot create capture buffer. Possible causes:\n");
  printf ("- another program has is using the audio capture device.\n");
  printf ("- the sampling parameters are unsupported (eg. sampling rate is
too high).\n");
  return 1;
 }

 // OPEN WAVE FILE

 waveFile = new CWaveFile;

 // Get the format of the capture buffer in g_wfxCaptureWaveFormat
 WAVEFORMATEX wfx;
 ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
 dscb->GetFormat (&wfx, sizeof(WAVEFORMATEX), NULL);
 if (waveFile->Open (const_cast<char*> (waveFilename), &wfx,
WAVEFILE_WRITE)) {
  printf ("Cannot open wave file.\n");
  return 1;
 }

 // REPORT ON PENDING ACTIVITIES

 printf ("\nRecording schedule:\n");
 printf ("     Begin   : %.19s\n", ctime (&start_t));
 printf ("     End     : %.19s\n", ctime (&end_t));

 {
 const int     duration = end_t - start_t;
 int       hr;
 int       min;
 int       sec;
 cvtTimetToComponents (duration, hr, min, sec);
 printf ("     Duration: %02d:%02d:%02d\n", hr, min, sec);
 }

 printf ("     Quality : %dHz %d-bit %s\n", sampleFreq, bitsPerSample,
channels == 1 ? "Mono" : "Stereo");

 if (volumeCutoff != -1) {
  printf ("Volume Cutoff: %d\n\n", volumeCutoff);
 }

 // SETUP SIGNAL HANDLER

 if (! setShutdownSigHandler ()) {
  printf ("Cannot register signal handler.\n");
  return 1;
 }

 // WAIT TO BEGIN RECORDING

 int       delay;

 delay = start_t - time (0);
 if (delay > 0) {
  printf ("\n");
  do {
   int       hr;
   int       min;
   int       sec;

   Sleep (POLL_INTERVAL_MSEC);
   delay = start_t - time (0);
   cvtTimetToComponents (delay, hr, min, sec);
   printf ("Waiting %02d:%02d:%02d before recording starts...\r", hr, min,
sec);
  } while ( delay > 0
    && ! shutdownSignalled);

  printf ("\n");
 }


 // BEGIN RECORDING

 if (! shutdownSignalled) {
  printf ("\nRecording has started.\n");
  startRecording (end_t, volumeCutoff, verbose);
  printf ("\nRecording has finished.\n");
 }

 // SHUTDOWN

 cleanup ();
 return 0;
}

/*
Live
Frequency Response: 10Hz - 44KHz
Signal to Noise Ratio: >96 db
Noise Floor: -120dB
Sampling Rate for Playback/Recording (Stereo): 8 KHz - 48 KHz
Supply Voltage Requirement (Loading): +5, +12, -12 Volt
Current Consumption (Typical): 300, 500, 30 mA respectively
Microphone Impedance: 600 Ohms
Line-In Impedance: 47 KOhms
CD Audio-In Impedance: 50 KOhms
Microphone Sensitivity: 10 - 200 mVpp
Line-In Sensitivity: 0 - 2 Vpp
CD Audio-In Sensitivity: 0 - 2 Vpp
AD/DA Resolution: 16 bits
Output Power (Max.): N/A - available only on specific models

input jacs (facing card)


1  2  3  4  5

1=joystick
2=
3=headphones
4=microphone in
5=line in (for sony portable radio)


*/




 1 Posts in Topic:
Any use for this code? (reply to publicgis_d AT rogers dot com)
"Wave" <nosp  2004-08-31 02:24:45 

Post A Reply:
  Go here to Signup

AddThis Feed Button


About - Advertising - Contact - Frequently Asked Questions - Privacy Policy - Terms of Use - Signup

Contact
tan12V112 Sat May 17 0:50:19 CDT 2008.