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

sound.c

/*  sound.c
 *
 *  Soundcard handling functions of xdemorse application
 */

/*
 *  xdemorse: An application to decode and display
 *  Morse code signals using a computer's sound card
 *
 *  Copyright (C) 2002  Neoklis Kyriazis
 *
 *  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:
 *
 *  http://www.gnu.org/copyleft/gpl.txt
 */

#include "xdemorse.h"

extern int
  dsp_fd, /* File descriptor of DSP device   */
  mix_fd; /* File descriptor of mixer device */

/* fft in buffer */
extern int *fft_in_r;

/* Runtime config data */
extern rc_data_t rc_data;

/*------------------------------------------------------------------------*/

/*  Setup_Sound_Card()
 *
 *  Sets up mixer and DSP devices
 */

  gboolean
Setup_Sound_Card( void )
{
  int
      new_recsrc, /* New recording source (RECORD_SRC) */
      dsp_speed,  /* DSP sampling speed as in xdemorse.h */
      frag_size,  /* DSP buffer (fragment) size in kb  */
      level,      /* Rec/Volume level request to mixer */
      num_chan,   /* Stereo(=2) or Mono(=1) selection  */
      sample_fmt, /* DSP sample format, 8-bit unsigned */
      itmp;

  /* Mixer device to be set-up (input or reclev) */
  unsigned int device;

  /* Error messages */
  char message[90];

  /* Sound device names from souncard.h */
  char *dev_name[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;

  /* File lock information   */
  struct flock lockinfo;

  /*** Open and lock mixer and dsp devices ***/
  /* Open mixer device, abort on error   */
  if( (mix_fd = open(rc_data.mix_dev, O_RDONLY, 0)) == -1 )
  {
      perror( rc_data.mix_dev );
      snprintf( message, 90,
            "Unable to open mixer device %s\n"
            "Quit and correct xdemorserc", rc_data.mix_dev );
      Error_Dialog( message );
      return(FALSE);
  }

  /* Attempt to lock entire mixer device file */
  lockinfo.l_type   = F_RDLCK;
  lockinfo.l_whence = SEEK_SET;
  lockinfo.l_start  = 0;
  lockinfo.l_len    = 0;

  /* If mixer device is already locked, abort */
  if( fcntl( mix_fd, F_SETLK, &lockinfo ) < 0 )
  {
      perror( rc_data.mix_dev );
      fcntl( mix_fd, F_GETLK, &lockinfo );
      fprintf( stderr, "xdemorse: Lock %s: Device is locked by pid %d\n",
            rc_data.mix_dev, lockinfo.l_pid );
      snprintf( message, 90,
            "Unable to lock %s\n"
            "Device locked by pid %d\n"
            "Quit and correct xdemorserc",
            rc_data.mix_dev, lockinfo.l_pid );
      Error_Dialog( message );
      return(FALSE);
  }

  /* Open DSP device, abort on error */
  if( (dsp_fd = open(rc_data.dsp_dev, O_RDONLY, 0)) == -1 )
  {
      perror( rc_data.dsp_dev );
      snprintf( message, 90,
            "Unable to open dsp device %s\n"
            "Quit and correct xdemorserc", rc_data.dsp_dev);
      Error_Dialog( message );
      return(FALSE);
  }

  /* Attempt to lock entire DSP device file */
  lockinfo.l_type   = F_RDLCK;
  lockinfo.l_whence = SEEK_SET;
  lockinfo.l_start  = 0;
  lockinfo.l_len    = 0;

  /* If DSP device is already locked, abort */
  if( fcntl( dsp_fd, F_SETLK, &lockinfo ) < 0 )
  {
      perror( rc_data.dsp_dev );
      fcntl( dsp_fd, F_GETLK, &lockinfo );
      fprintf( stderr, "xdemorse: Lock %s: Device is locked by pid %d\n",
            rc_data.dsp_dev, lockinfo.l_pid );
      snprintf( message, 90,
            "Unable to lock %s\n"
            "Device locked by pid %d"
            "Quit and correct xdemorserc",
            rc_data.dsp_dev, lockinfo.l_pid );
      Error_Dialog( message );
      return(FALSE);
  }

  /*** Setup sound card parameters ***/

  /* Find number of recording source matching source name */
  for( new_recsrc = 0; new_recsrc < SOUND_MIXER_NRDEVICES; new_recsrc++ )
      if( strcmp( dev_name[new_recsrc], rc_data.rec_src ) == 0 )
        break;

  /* Make recording source mask */
  itmp = 1 << new_recsrc;

  /* Attempt to select recording source, abort on error */
  if( ioctl(mix_fd, SOUND_MIXER_WRITE_RECSRC, &itmp) == -1 )
  {
      perror("xdemorse: SOUND_MIXER_WRITE_RECSRC");
      snprintf( message, 90,
            "Failed to select Recording\n"
            "Source: %s\n"
            "Quit and correct xdemorserc", rc_data.rec_src );
      Error_Dialog( message );
      return(FALSE);
  }
  if( itmp != 1 << new_recsrc )
  {
      snprintf( message, 90,
            "Failed to select Recording\n"
            "Source: %s\n"
            "Quit and correct xdemorserc", rc_data.rec_src );
      Error_Dialog( message );
      return(FALSE);
  }

  /* Zero level of recording source to silence (my) speakers */
  level = 0;
  if( ioctl(mix_fd, MIXER_WRITE(new_recsrc), &level) == -1 )
  {
      perror("xdemorse: Setting Recording source level");
      snprintf( message, 90,
            "Failed to set %s level\n"
            "Quit and correct xdemorserc", rc_data.rec_src );
      Error_Dialog( message );
      return(FALSE);
  }
  if( level != 0 )
  {
      snprintf( message, 90,
            "Failed to set %s level\n"
            "Quit and correct xdemorserc", rc_data.rec_src );
      Error_Dialog( message );
      return(FALSE);
  }

  /* Find recording level device */
  for( device = 0; device < SOUND_MIXER_NRDEVICES; device++ )
      if( strcmp( dev_name[device], rc_data.inp_lev ) == 0 )
        break;

  if( device ==  SOUND_MIXER_NRDEVICES )
  {
      snprintf( message, 90,
            "Failed to select Recording\n"
            " Level device: %s\n"
            "Quit and correct xdemorserc", rc_data.inp_lev );
      Error_Dialog( message );
      return(FALSE);
  }

  /* Write recording level to mixer, abort on error */
  level = itmp = rc_data.rec_lev | (rc_data.rec_lev << 8);
  if( ioctl(mix_fd, MIXER_WRITE(device), &level) == -1 )
  {
      perror("xdemorse: Setting Recording level");
      Error_Dialog(
            "Failed to set Recording level\n"
            "Quit and correct xdemorserc" );
      return(FALSE);
  }
  if( level != itmp )
  {
      Error_Dialog(
            "Failed to set Recording level\n"
            "Quit and correct xdemorserc" );
      return(FALSE);
  }

  /* Set fragment size according to stereo/mono mode */
  itmp = 1; frag_size = 0;
  num_chan = rc_data.num_chn;
  while( (itmp << frag_size) != BUFFER_SIZE ) frag_size++;
  itmp += num_chan << 18;
  ioctl( dsp_fd, SNDCTL_DSP_SETFRAGMENT, &frag_size );

  /* Set sample format to unsigned 8-bit, abort on error */
  sample_fmt = AFMT_U8;
  if( ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &sample_fmt) == -1 )
  {
      perror( "xdemorse: SNDCTL_DSP_SETFMT");
      Error_Dialog(
            "Failed to set dsp format: AFMT_U8\n"
            "Quit and correct xdemorserc" );
      return(FALSE);
  }
  if( sample_fmt != AFMT_U8 )
  {
      Error_Dialog(
            "Failed to set dsp format: AFMT_U8\n"
            "Quit and correct xdemorserc" );
      return(FALSE);
  }

  /* Set stereo/mono mode */
  itmp = num_chan;
  if( ioctl(dsp_fd, SNDCTL_DSP_CHANNELS, &itmp) == -1 )
      perror("SNDCTL_DSP_CHANNELS");

  /* Setup DSP sampling speed, abort on error */
  dsp_speed = rc_data.dsp_speed;
  if( ioctl(dsp_fd, SNDCTL_DSP_SPEED, &dsp_speed) == -1 )
  {
      perror( "xdemorse: SNDCTL_DSP_SPEED");
      snprintf( message, 90,
            "Failed to set DSP speed to %d\n"
            "Quit and correct xdemorserc", rc_data.dsp_speed );
      Error_Dialog( message );
      return(FALSE);
  }
  if( dsp_speed != rc_data.dsp_speed )
  {
      snprintf( message, 90,
            "Failed to set DSP speed to %d\n"
            "Quit and correct xdemorserc", rc_data.dsp_speed );
      Error_Dialog( message );
      return(FALSE);
  }

  return( TRUE );

} /* End of Setup_Sound_Card() */

/*------------------------------------------------------------------------*/

/*  Get_Signal_Sample()
 *
 *  Gets the next DSP sample of the signal input
 */

  int
Signal_Sample(void)
{
  /* Number of samples read from dsp */
  int sample_cnt;

  static int
      fft_idx = 0, /* fft input buffer idx */
      cnt = 0;     /* Count of calls to this function */

  /* New DSP sample of audio input  */
  int sample;


  /* Refill dsp samples buffer when needed */
  if( rc_data.buffer_idx >= rc_data.buffer_size )
  {
      /* Start buffer index according to stereo/mono mode */
      if( rc_data.num_chn == 1 ) /* Mono */
        rc_data.buffer_idx = 0;
      else
        rc_data.buffer_idx = rc_data.use_chn;

      /* Read audio samples from DSP, abort on error */
      if( (sample_cnt = read(dsp_fd, rc_data.buffer, rc_data.buffer_size)) == -1 )
      {
        perror( "xdemorse: dsp read()" );
        Error_Dialog(
              "Error reading from dsp device\n"
              "Quit xdemorse and correct" );
        Set_Flag( DSP_IO_ERROR );
      }
      if( sample_cnt != rc_data.buffer_size )
      {
        Error_Dialog(
              "Error reading from dsp device\n"
              "Quit xdemorse and correct" );
        Set_Flag( DSP_IO_ERROR );
      }

  } /* End of if( buffer_idx >= buffer_size ) */

  /* Remove neutral value (128) from samples */
  sample = rc_data.buffer[ rc_data.buffer_idx ] - 128;

  /* Display waterfall when input buffer full */
  /* rc_data.fft_stride samples added for each input element */
  if( cnt == 0 )
      fft_in_r[fft_idx]  = sample;
  else
      fft_in_r[fft_idx] += sample;

  if( ++cnt >= rc_data.fft_stride )
  {
      fft_idx++;
      cnt = 0;
  }

  if( fft_idx >= FFT_SIZE )
  {
      fft_idx = 0;
      Display_Waterfall();
  }

  /* Increment according to mono/stereo mode */
  rc_data.buffer_idx += rc_data.num_chn;

  return( sample );

} /* End of Get_Signal_Sample() */

/*------------------------------------------------------------------------*/

Generated by  Doxygen 1.6.0   Back to index