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

rcfile.c

#include <stdio.h>
#include <sys/types.h>
#include <malloc.h>
#include <string.h>
#include <sys/stat.h>

#include "../include/cfgfmt.h"
#include "../include/string.h"
#include "../include/strexp.h"
#include "../include/fio.h"

#include "ymode.h"
#include "soundpaths.h"
#include "ysound.h"
#include "ymixer.h"
#include "rcfile.h"
#include "options.h"


int RCLoadFromFile(const char *filename);


/*
 *      Structure to contain a mixer device settings read from
 *      file.
 */
typedef struct {
      char *name;
      Coefficient val[YTotalMixers][YMixerValues];
} mixer_device_fdata_struct;

static void RCMixerParseMixerValueString(
      const char *s,
      Coefficient *value1, Coefficient *value2,
      Coefficient *value3, Coefficient *value4
);
static void MixerFreeFData(
      mixer_device_fdata_struct **ptr, int total
);
static mixer_device_fdata_struct **MixerRCLoadAllFromFile(
      const char *filename, int *total
);
int MixerRCLoadFromFile(const char *filename, Recorder *recorder);
int MixerRCSaveToFile(const char *filename, Recorder *recorder);


#define MIN(a,b)        ((a) < (b) ? (a) : (b))
#define MAX(a,b)        ((a) > (b) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define ABSOLUTE(x)     (((x) < 0) ? ((x) * -1) : (x))


extern int YAntiShift(int in);      /* In main.c */


/*
 *    Loads configuration.
 *
 *    Any current Audio modes and sound paths will be deleted
 *    and then loaded with the new ones from the file.
 */
int RCLoadFromFile(const char *filename)
{
      int status;
      char *strptr, *strptr2;

      FILE *fp;
      struct stat stat_buf;

      char parm[CFG_PARAMETER_MAX];
      char val[CFG_VALUE_MAX];
      int lines_read = 0;

      YMode *ymode_ptr;
      SoundPath *sp_ptr;


      /* Check if file exists. */
      if(filename == NULL)
          return(-1);
      if(stat(filename, &stat_buf))
      {
          fprintf(stderr, "%s: No such file.\n", filename);
          return(-1);
      }

      /* Open YIFF Sound Server configuration file. */
      fp = FOpen(filename, "rb");
      if(fp == NULL)
      {
          fprintf(stderr, "%s: Cannot open.\n", filename);
          return(-1);
      }


      /* Free allocated resources that would be reloaded with the
       * contents of the configuration file to be loaded.
       */

      /* Y Audio Modes. */    
      YModeDeleteAll();

      /* Y Sound Paths. */
      SoundPathDeleteAll();


/* Reads the next line, fetches parm and val. Will break the loop
 * if end of file is reached or continue as needed. Make sure variable
 * is initially reset to NULL before start of reading file. Uses
 * variables; strptr, strptr2, fp, parm, val, and lines_read.
 */
#define DO_READ_LINE    \
{ \
 /* Free previous line and allocate/read next line. */ \
 free(strptr); \
 strptr = FReadNextLineAlloc(fp, UNIXCFG_COMMENT_CHAR); \
 if(strptr == NULL) \
  break; \
 lines_read++; \
 \
 /* Fetch parameter. */ \
 strptr2 = StringCfgParseParm(strptr); \
 if(strptr2 == NULL) \
  continue; \
 strncpy(parm, strptr2, CFG_PARAMETER_MAX); \
 parm[CFG_PARAMETER_MAX - 1] = '\0'; \
 \
 /* Fetch value. */ \
 strptr2 = StringCfgParseValue(strptr); \
 if(strptr2 == NULL) \
  strptr2 = "0";  /* Set it to "0" if NULL. */ \
 strncpy(val, strptr2, CFG_VALUE_MAX); \
 val[CFG_VALUE_MAX - 1] = '\0'; \
}

      /* Begin reading file. */
      strptr = NULL;
      while(1)
      {
          DO_READ_LINE

          /* VersionMajor */
          if(!strcasecmp(parm, "VersionMajor"))
          {

          }
          /* VersionMinor */
          else if(!strcasecmp(parm, "VersionMinor"))
          {

          }

          /* Listening port number. */
          else if(!strcasecmp(parm, "Port"))
          {
            option.port = atoi(val);
          }
          /* Refresh interval. */
          else if(!strcasecmp(parm, "RefreshInterval"))
          {
            option.refresh_int.ms = atol(val) / 1000;
            option.refresh_int.us = atol(val) % 1000;
          }
          /* DSP device. */
          else if(!strcasecmp(parm, "DSPDevice") ||
                !strcasecmp(parm, "Device")
          )
          {
            strncpy(
                fname.device,
                val,
                PATH_MAX + NAME_MAX
            );
            if(stat(fname.device, &stat_buf))
            {
                fprintf(stderr,
   "%s: Line %i: Warning: %s: No such device.\n",
                      filename,
                      lines_read,
                      fname.device
                );
            }
          }
          /* Mixer device. */
          else if(!strcasecmp(parm, "MixerDevice") ||
                !strcasecmp(parm, "Mixer")
          )
          {
            strncpy(
                fname.mixer,
                val,
                PATH_MAX + NAME_MAX
            );
            if(fname.mixer[0] != '\0')
            {
                if(stat(fname.mixer, &stat_buf))
                  fprintf(stderr,
   "%s: Line %i: Warning: %s: No such device.\n",
                      filename,
                      lines_read,
                      fname.mixer
                  );
            }
          }
          /* MIDI player command. */
          else if(!strcasecmp(parm, "MIDIPlayCommand"))
          {
            free(option.midi_play_cmd);
            option.midi_play_cmd = strdup(val);
          }
          /* ALSA MIDI device port. */
          else if(!strcasecmp(parm, "MIDIDevicePort"))
          {
#ifdef ALSA_RUN_CONFORM
            /* If -1 then implies it is not set. */
            if(option.midi_device_number < 0)
            {
                /* Was not previously set, so set it with the
                 * specified value from configuration file.
                 */
                option.midi_device_number = atoi(val);
            }
#endif      /* ALSA_RUN_CONFORM */
          }

          /* **************************************************** */
          /* BeginYAudioMode */
          else if(!strcasecmp(parm, "BeginYAudioMode") ||
                !strcasecmp(parm, "BeginAudioMode") ||
                !strcasecmp(parm, "BeginYMode") ||
                !strcasecmp(parm, "BeginMode")
          )
          {
            status = YModeAllocate(NULL);
            ymode_ptr = YModeGetPtr(status);
            if(ymode_ptr == NULL)
                continue;

            while(1)
            {
                DO_READ_LINE

                /* Name */
                if(!strcasecmp(parm, "Name"))
                {
                  free(ymode_ptr->name);
                  ymode_ptr->name = StringCopyAlloc(val);
                }
                /* Cycle */
                else if(!strcasecmp(parm, "Cycle"))
                {
                  ymode_ptr->cycle.ms = atol(val) / 1000;
                  ymode_ptr->cycle.us = atol(val) % 1000;
                }
                /* WriteAhead */
                else if(!strcasecmp(parm, "WriteAhead"))
                {
                  ymode_ptr->write_ahead.ms = atol(val) / 1000;
                  ymode_ptr->write_ahead.us = atol(val) % 1000;
                }
                /* SampleSize */
                else if(!strcasecmp(parm, "SampleSize"))
                {
                  ymode_ptr->sample_size = atoi(val);

                  if(ymode_ptr->sample_size == 16)
                      ymode_ptr->sample_size = 16;
                  else
                      ymode_ptr->sample_size = 8;
                }
                /* Channels */
                else if(!strcasecmp(parm, "Channels"))
                {
                  ymode_ptr->channels = atoi(val);

                  if(ymode_ptr->channels == 2)
                      ymode_ptr->channels = 2;
                  else
                      ymode_ptr->channels = 1;
                }
                /* SampleRate */
                else if(!strcasecmp(parm, "SampleRate"))
                {
                  ymode_ptr->sample_rate = atoi(val);
                }
#ifdef OSS_BUFFRAG
                /* AllowFragmenting */
                else if(!strcasecmp(parm, "AllowFragmenting"))
                {
                  ymode_ptr->allow_fragments = StringIsYes(val);
                }
                /* Fragments */
                else if(!strcasecmp(parm, "Fragments"))
                {
                  ymode_ptr->num_fragments = atoi(val);
                }
                /* FragmentSize */
                else if(!strcasecmp(parm, "FragmentSize"))
                {
                  /*   Note: On file, it's bytes, in memory it's
                   *   shifts.
                   */
                  ymode_ptr->fragment_size = YAntiShift(atoi(val) - 1);
                }
#endif  /* OSS_BUFFRAG */
                /* FlipStereo */
                else if(!strcasecmp(parm, "FlipStereo"))
                {
                  ymode_ptr->flip_stereo = StringIsYes(val);
                }
                /* Direction */
                else if(!strcasecmp(parm, "Direction"))
                {
                  if(!strcasecmp(val, "Record"))
                      ymode_ptr->direction = AUDIO_DIRECTION_RECORD;
                  else
                      ymode_ptr->direction = AUDIO_DIRECTION_PLAY;
                }

                /* EndYAudioMode */
                else if(!strcasecmp(parm, "EndYAudioMode") ||
                      !strcasecmp(parm, "EndAudioMode") ||
                      !strcasecmp(parm, "EndYMode") ||
                      !strcasecmp(parm, "EndMode")
                )
                {
                  break;
                }

                /* Unknown parameter. */
                else
                { 
                  fprintf(stderr,
                      "%s: Line %i: Unknown parameter: %s\n",
                      filename,
                      lines_read,
                      parm
                  );
                  continue;
                }

            }
          }

          /* **************************************************** */
          /* BeginYSoundPath */
          else if(!strcasecmp(parm, "BeginYSoundPath") ||
                !strcasecmp(parm, "BeginSoundPath")
          )
          {
            status = SoundPathAllocate();
            sp_ptr = SoundPathGetPtr(status);
            if(sp_ptr == NULL)
                continue;

            while(1)
            {
                DO_READ_LINE

                /* Path */   
                if(!strcasecmp(parm, "Path"))
                {
                  free(sp_ptr->path);
                  sp_ptr->path = StringCopyAlloc(val);
                }
                /* EndYSoundPath */
                else if(!strcasecmp(parm, "EndYSoundPath") ||
                      !strcasecmp(parm, "EndSoundPath")
                )
                {
                  break;
                }
                /* Unknown parameter. */  
                else
                {
                  fprintf(stderr,
                      "%s: Line %i: Unknown parameter: %s\n",
                      filename,
                      lines_read,
                      parm
                  );
                  continue;
                } 
            }
          }

          /* Unknown parameter. */
          else
          {
            fprintf(stderr, "%s: Line %i: Unknown parameter: %s\n",
                filename,
                lines_read,
                parm
            );
          }
      }

#undef DO_READ_LINE

      /* Close the file. */
      FClose(fp);


      return(0);
}

/*
 *    Parses two values seperated by a white space from string
 *    s and puts them into the Coefficient values.
 */
static void RCMixerParseMixerValueString(
      const char *s,
      Coefficient *value1, Coefficient *value2,
      Coefficient *value3, Coefficient *value4
)
{
      /* Seek past spaces and get value 1. */
      while(ISBLANK(*s))
          s++;
      if(value1 != NULL)
          *value1 = atof(s);

      /* Seek to and get value 2. */
      while(!ISBLANK(*s) && (*s != '\0'))
          s++;
      while(ISBLANK(*s))
          s++;
      if(value2 != NULL)
          *value2 = atof(s);

      /* Seek to and get value 3. */
      while(!ISBLANK(*s) && (*s != '\0'))
          s++;
      while(ISBLANK(*s))
          s++;
      if(value3 != NULL)
          *value3 = atof(s);

      /* Seek to and get value 4. */
      while(!ISBLANK(*s) && (*s != '\0'))
          s++;
      while(ISBLANK(*s))
          s++;
      if(value4 != NULL)
          *value4 = atof(s);
}

/*
 *    Deallocates mixer device file data list.
 */
static void MixerFreeFData(mixer_device_fdata_struct **ptr, int total)
{
      int i;
      mixer_device_fdata_struct *mdfd_ptr;

      for(i = 0; i < total; i++)
      {
          mdfd_ptr = ptr[i];
          if(mdfd_ptr == NULL)
            continue;

          free(mdfd_ptr->name);
          free(mdfd_ptr);
      }
      free(ptr);
}

/*
 *    Loads all mixer device channel values from the specified
 *    file and returns an allocated array of listings for each
 *    device.
 *
 *    This array needs to be free'ed by the calling function.
 */
static mixer_device_fdata_struct **MixerRCLoadAllFromFile(
      const char *filename, int *total
)
{
      int i, n;
      char *strptr, *strptr2;

      FILE *fp;
      int lines_read = 0;
      struct stat stat_buf;
      char parm[CFG_PARAMETER_MAX];
      char val[CFG_VALUE_MAX];
   
      char *mixer_name[] = YMixerConicalNames;

      mixer_device_fdata_struct **ptr = NULL;
      mixer_device_fdata_struct *mdfd_ptr;


      if((filename == NULL) ||
         (total == NULL)
      )
          return(NULL);

      if(stat(filename, &stat_buf))
          return(NULL);

      /* Reset total. */
      (*total) = 0;

      /* Open mixer device file for reading. */
      fp = FOpen(filename, "rb");
      if(fp == NULL)
          return(NULL);

/* Reads the next line, fetches parm and val. Will break the loop
 * if end of file is reached or continue as needed. Make sure variable
 * is initially reset to NULL before start of reading file. Uses
 * variables; strptr, strptr2, fp, parm, val, and lines_read.
 */
#define DO_READ_LINE    \
{ \
 /* Free previous line and allocate/read next line. */ \
 free(strptr); \
 strptr = FReadNextLineAlloc(fp, UNIXCFG_COMMENT_CHAR); \
 if(strptr == NULL) \
  break; \
 lines_read++; \
 \
 /* Fetch parameter. */ \
 strptr2 = StringCfgParseParm(strptr); \
 if(strptr2 == NULL) \
  continue; \
 strncpy(parm, strptr2, CFG_PARAMETER_MAX); \
 parm[CFG_PARAMETER_MAX - 1] = '\0'; \
 \
 /* Fetch value. */ \
 strptr2 = StringCfgParseValue(strptr); \
 if(strptr2 == NULL) \
  strptr2 = "0";  /* Set it to "0" if NULL. */ \
 strncpy(val, strptr2, CFG_VALUE_MAX); \
 val[CFG_VALUE_MAX - 1] = '\0'; \
}

      /* Begin reading file. */
      strptr = NULL;
      while(1)
      {
          DO_READ_LINE

          /* BeginMixer */
          if(!strcasecmp(parm, "BeginMixer"))
          {
            /* Allocate a new mixer device structure. */
            i = (*total);
            (*total) = i + 1;
            ptr = (mixer_device_fdata_struct **)realloc(
                ptr,
                (*total) * sizeof(mixer_device_fdata_struct *)
            );
            if(ptr == NULL)
            {
                (*total) = 0;
                continue;
            }

            ptr[i] = (mixer_device_fdata_struct *)calloc(
                1,
                sizeof(mixer_device_fdata_struct)
            );
            if(ptr[i] == NULL)
            {
                (*total) = i;
                continue;
            }
            mdfd_ptr = ptr[i];

            /* Record mixer device's name. */
            mdfd_ptr->name = StringCopyAlloc(val);


            while(1)
            {
                DO_READ_LINE

                /* Go through mixer device channel names. */  
                for(n = 0; n < YTotalMixers; n++)
                {
                  if(!strcasecmp(parm, mixer_name[n]))
                  {
                      RCMixerParseMixerValueString(
                        val,
                        (YMixerValues > 0) ?
                            &mdfd_ptr->val[n][0] : NULL,
                        (YMixerValues > 1) ?
                            &mdfd_ptr->val[n][1] : NULL,
                        (YMixerValues > 2) ?
                            &mdfd_ptr->val[n][2] : NULL,
                        (YMixerValues > 3) ?
                            &mdfd_ptr->val[n][3] : NULL
                      );
                  }
                }
                /* EndMixer */
                if(!strcasecmp(parm, "EndMixer"))
                {
                  break;
                }       
            } 
          }
          /* Unknown parameter. */
          else
          {
            fprintf(
                stderr,
                "%s: Line %i: Unknown parameter: %s\n",
                filename,
                lines_read,
                parm
            );
          }
      }

#undef DO_READ_LINE

      /* Close mixer device data file. */
      FClose(fp);

      return(ptr);
}


/*
 *    Loads the mixer device channel values from the specified
 *    file and updates the recorder's mixer device channel values.
 *
 *    The recorder's mixer must already be opened for this
 *    function to have any affect.
 *
 *    If global fname.mixer is an empty string then no mixer data
 *    will be loaded.
 */
int MixerRCLoadFromFile(const char *filename, Recorder *recorder)
{
      int i, mixer_index, total;
      int set_our_mixer = 0;
      mixer_device_fdata_struct **ptr, *mdfd_ptr;
      const char *this_mixer_dev_name;


      if((filename == NULL) || (recorder == NULL))
          return(-1);

      /* Get pointer to our mixer device's name, this will be
       * used to check through the listing of mixers to see which
       * one we want to load values for.
       */
      this_mixer_dev_name = fname.mixer;
      if(this_mixer_dev_name[0] == '\0')
      {
          /* No mixer device to load. */
          return(0);
      }

      /* Load all mixer devices data from file. */
      ptr = MixerRCLoadAllFromFile(filename, &total);
      if(ptr == NULL)
          total = 0;

      /* No mixer devices loaded? */
      if(total <= 0)
          return(-1);

      /* Go through mixer device listing. */
      for(i = 0; i < total; i++)
      {
          mdfd_ptr = ptr[i];

          if(mdfd_ptr == NULL)
            continue;
          if(mdfd_ptr->name == NULL)
            continue;

          /* Match mixer device name. */
          if(!strcasecmp(mdfd_ptr->name, this_mixer_dev_name))
          {
            /* This is the mixer device we're looking for, now go
             * through each mixer device channel setting.
             */
            for(mixer_index = 0; mixer_index < YTotalMixers; mixer_index++)
            {
                /* Set mixer values for our mixer. */
                YMixerSet(
                  recorder, mixer_index + YMixerCodeBaseOffset,
                  mdfd_ptr->val[mixer_index]
                );
            }

            set_our_mixer = 1;
          }
      }

      /* Deallocate the loaded mixer data listing. */
      MixerFreeFData(ptr, total);

      if(set_our_mixer)
          return(0);
      else
          return(-1);
}

/*
 *    Saves the mixer device channel values specified in the
 *    recorder to file.
 *
 *    Other mixer device channel values in the file will also
 *    be read and rewritten to file (their values will be
 *    preserved).
 *
 *    If the fname.mixer is an empty string then no operation
 *    will be performed.
 *
 *    The recorder's mixer must already be opened for this
 *    function to have any affect.
 */
int MixerRCSaveToFile(const char *filename, Recorder *recorder)
{
      int i, mixer_index, total;
      int got_our_mixer = 0;
      FILE *fp;
      mixer_device_fdata_struct **ptr, *mdfd_ptr;
      const char *this_mixer_dev_name;
      char *mixer_name[] = YMixerConicalNames;


      if((filename == NULL) ||
         (recorder == NULL)
      )
          return(-1);

      /* Get pointer to our mixer device's name, this will be
       * used to check through the listing of mixers to see which
       * one we want to save values for.
       */
      this_mixer_dev_name = fname.mixer;
      if(this_mixer_dev_name[0] == '\0')
      {
          /* Mixer device name is empty string, nothing to save. */
          return(0);
      }

      /* Load all mixer devices data from file. */
      ptr = MixerRCLoadAllFromFile(filename, &total);
      if(ptr == NULL)
          total = 0;

      /* Go through mixer device listing, search for our mixer
       * device by matching name. If it is found, then update
       * its values with the current mixer device channel values.
       */
      for(i = 0; i < total; i++)
      {
          mdfd_ptr = ptr[i];

          if(mdfd_ptr == NULL)
            continue;
          if(mdfd_ptr->name == NULL)
            continue;

          /* Match mixer device name. */
          if(!strcasecmp(mdfd_ptr->name, this_mixer_dev_name))
          {
            /* This is the mixer device we're looking for, now go
             * through each mixer device channel setting.
             */
            for(mixer_index = 0; mixer_index < YTotalMixers; mixer_index++)
            {
                /* Get current mixer values for our mixer, store
                 * the fetched values into the mixer device file
                 * data structure which we will save later.
                 */
                YMixerGet(
                  recorder, mixer_index + YMixerCodeBaseOffset,
                  mdfd_ptr->val[mixer_index]
                );
            }
          }

          /* Mark that we have set values for our mixer device
           * in the list.
           */
          got_our_mixer = 1;
      }
      /* If our mixer device was not in the loaded mixer device listing
       * then append it to the list.
       */
      if(!got_our_mixer)
      {
          /* Sanitize total. */
          if(total < 0)
            total = 0;

          /* Allocate one more pointer. */
          i = total;
          total++;
          ptr = (mixer_device_fdata_struct **)realloc(
            ptr,
            total * sizeof(mixer_device_fdata_struct *)
          );
          if(ptr == NULL)
          {
            total = 0;
          }
          else
          {
            /* Allocate our mixer device structure in the list. */
            ptr[i] = (mixer_device_fdata_struct *)calloc(
                1,
                sizeof(mixer_device_fdata_struct)
            );
            mdfd_ptr = ptr[i];
            if(mdfd_ptr != NULL)
            {
                mdfd_ptr->name = strdup(this_mixer_dev_name);

                /* Go through mixer device channel settings. */
                for(mixer_index = 0; mixer_index < YTotalMixers; mixer_index++)
                {
                  /* Get current mixer values for our mixer, store
                   * the fetched values into the mixer device file
                   * data structure which we will save later.
                   */   
                  YMixerGet(
                      recorder, mixer_index + YMixerCodeBaseOffset,
                      mdfd_ptr->val[mixer_index]
                  );
                }
            }
          }
      }

      /* Do not deallocate mixer device listing just yet, we need
       * to write them back to file below.
       */

      /* Open mixer device file for writing */
      fp = FOpen(filename, "wb");
      if(fp != NULL)
      {
          /* Write commented heading. */
          fprintf(fp,
"# Mixer device channel settings.\n\
# This file is automatically generated by the YIFF Sound Server.\n\
# You may manually edit this file as needed.\n\
#\n"
          );

          /* Write each mixer device channel values to file. */
          for(i = 0; i < total; i++)
          {
            mdfd_ptr = ptr[i];

            if(mdfd_ptr == NULL)
                continue;
            if(mdfd_ptr->name == NULL)
                continue;

            fprintf(fp, "BeginMixer = %s\n",
                mdfd_ptr->name
            );

            /* Write each mixer channel values. */
            for(mixer_index = 0; mixer_index < YTotalMixers; mixer_index++)
            {
                fprintf(fp, "    %s = %f %f %f %f\n",
                  mixer_name[mixer_index],
                  (YMixerValues > 0) ?
                      mdfd_ptr->val[mixer_index][0] : 0.0,
                  (YMixerValues > 1) ?
                      mdfd_ptr->val[mixer_index][1] : 0.0,
                  (YMixerValues > 2) ?
                      mdfd_ptr->val[mixer_index][2] : 0.0,
                  (YMixerValues > 3) ?
                      mdfd_ptr->val[mixer_index][3] : 0.0
                );
            }

            fprintf(fp, "EndMixer\n");
          }

          /* Close the file. */
          FClose(fp);
          fp = NULL;
      }

      /* Deallocate loaded mixer device file data listing. */
      MixerFreeFData(ptr, total);

      return(0);
}


Generated by  Doxygen 1.6.0   Back to index