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

afw.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
extern int errno;

#include "../include/string.h"
#include "../include/disk.h"
#include "../include/prochandle.h"

#include "midi.h"
#include "raw.h"
#include "wav.h"
#include "voc.h"

#include "midiiow.h"
#include "afw.h"
#include "options.h"


static void AFWCopyDataAlloc(
      const void *data,
      int len,
      SoundBuffer **prev_data,
      YDataLength *prev_len
);

int AFWOpen(const char *path, AFWDataStruct *af_data);
int AFWLoadSegment(
      AFWDataStruct *af_data,
      YDataPosition position,
      YDataLength length,
      Audio *audio
);
void AFWClose(AFWDataStruct *af_data, Audio *audio);


#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))


/*
 *    Coppies the data to the previous data pointer.
 *    Reallocating it as needed.
 *
 *    prev_data and prev_len are assumed valid.
 */
static void AFWCopyDataAlloc(
      const void *data,
      int len,
      SoundBuffer **prev_data,
      YDataLength *prev_len
)
{
      if((data == NULL) ||
         (len < 1)
      )
      {
          if((*prev_data) != NULL)
          {
            free(*prev_data);
            (*prev_data) = NULL;
          }
          (*prev_len) = 0;

          return;
      }
      else
      {
          if((*prev_len) != len)
          {
            (*prev_len) = len;

            (*prev_data) = (SoundBuffer *)realloc(
                *prev_data,
                (*prev_len) * sizeof(SoundBuffer)
            );
            if((*prev_data) == NULL)
            {
                (*prev_len) = 0;
                return;
            }
          }

          memcpy(
            *prev_data, /* Destination. */
            data,       /* Source. */
            (*prev_len) * sizeof(SoundBuffer)
          );
      }

      return;
}

/*
 *    Reads the header of an audio file specified by path
 *    and puts its parameters and type data in the buffer
 *    pointed at af_data.
 */
int AFWOpen(const char *path, AFWDataStruct *af_data)
{
      FILE *fp;
      raw_data_struct rd, *rd_ptr;
      wav_data_struct wd, *wd_ptr;
      voc_data_struct vd, *vd_ptr;
      MidiDataStruct md, *md_ptr;
      struct stat stat_buf;


      if((path == NULL) || (af_data == NULL))
          return(-1);

      /* Reset afw data structure. */
      memset(af_data, 0x00, sizeof(AFWDataStruct));

      /* Open file. */
      fp = fopen(path, "rb");
      if(fp == NULL)
          return(-1);

      /* Get file statistics. */
      if(fstat(fileno(fp), &stat_buf))
          return(-1);

      /* The object cannot be a directory. */
      if(S_ISDIR(stat_buf.st_mode))
          return(-1);

      /* Try passing the opened fp to each of the library read
       * header functions. If any of the header functions return
       * success then that is the right one to use because the
       * file types were detected to match.
       *
       * Also on success we should not referance our fp again.
       */
      /* Is it a WAV file? */
      if(WavReadHeader(path, fp, &wd) == WavSuccess)
      {
          fp = NULL;          /* Do not referance the fp again. */

          /* Load as a WAV file. */
          af_data->ptr = calloc(1, sizeof(wav_data_struct));
          if(af_data->ptr == NULL)
            return(-1);
          else
            wd_ptr = (wav_data_struct *)af_data->ptr;

          memcpy(wd_ptr, &wd, sizeof(wav_data_struct));

          /* Copy other data from library specific structure to
           * our afw data structure.
           */
          af_data->file_format = AFWFileFormatWav;
          af_data->sndobj_format = SndObjTypeDSP;
          af_data->entire_length = wd.data_chunk_size;
          af_data->buffer = NULL;
          af_data->length = 0;

          af_data->block_align = wd.block_align;
          af_data->block_length = ((wd.bits_per_sample == 16) ?
            2 : 1
          );

          af_data->sample_size = wd.bits_per_sample;
          af_data->channels = wd.channels;
          af_data->sample_rate = wd.samples_per_sec;
          af_data->bytes_per_sec = wd.bytes_per_sec;
      }
      /* Is it a VOC file? */
      else if(VocReadHeader(path, fp, &vd) == VocSuccess)
      {
          int i;


          fp = NULL;          /* Do not referance the fp again. */

          /* Load as a VOC file. */
          af_data->ptr = calloc(1, sizeof(voc_data_struct));
          if(af_data->ptr == NULL)
            return(-1);
          else
            vd_ptr = (voc_data_struct *)af_data->ptr;

          memcpy(vd_ptr, &vd, sizeof(voc_data_struct));

          /* Copy other data from library specific structure to
           * our afw data structure.
           */
          af_data->file_format = AFWFileFormatVoc;
          af_data->sndobj_format = SndObjTypeDSP;
          af_data->entire_length = vd.total_data_len;
          af_data->buffer = NULL;
          af_data->length = 0;

          /* Get block align and length. */
          af_data->block_align = 0;
          af_data->block_length = 1;
          for(i = 0; i < vd.total_datablocks; i++)
          {
            if(vd.datablock[i] == NULL)
                continue;
            if(vd.datablock[i]->type != VocBlockTypeSoundData)
                continue;

            af_data->block_align = 0;
            af_data->block_length =
                ((vd.datablock[i]->bits == 16) ? 2 : 1);

            af_data->sample_size = 8;
            af_data->channels = 1;
            af_data->sample_rate =
                vd.datablock[i]->sample_rate;
            af_data->bytes_per_sec = af_data->sample_rate;
          }
      }
      /* Is it a MIDI file? */
      else if(MidiRead(path, fp, &md) == MidiSuccess)
      {
          fp = NULL;          /* Do not referance the fp again. */

          /* Load as a MIDI file. */
          af_data->ptr = calloc(1, sizeof(MidiDataStruct));
          if(af_data->ptr == NULL)
            return(-1);
          else
            md_ptr = (MidiDataStruct *)af_data->ptr;

          memcpy(md_ptr, &md, sizeof(MidiDataStruct));

          /* Copy other data from library specific structure to   
           * our afw data structure.
           */
          af_data->file_format = AFWFileFormatMidi;
          af_data->sndobj_format = SndObjTypeMIDI;
          af_data->entire_length = 0;
          af_data->buffer = NULL;
          af_data->length = 0;

          af_data->block_align = 0;
          af_data->block_length = 0;

          af_data->sample_size = 0;
          af_data->channels = 0;
          af_data->sample_rate = 0;
          af_data->bytes_per_sec = 0;
      }
      /* Is it a RAW file? (This needs to be checked last). */
      else if(RawReadHeader(path, fp, &rd) == RawSuccess)
      {
          fp = NULL;          /* Do not referance the fp again. */

          /* Load as a RAW file. */
          af_data->ptr = calloc(1, sizeof(raw_data_struct));
          if(af_data->ptr == NULL)
            return(-1);
          else
            rd_ptr = (raw_data_struct *)af_data->ptr;

          memcpy(rd_ptr, &rd, sizeof(raw_data_struct));

          /* Copy other data from library specific structure to
           * our afw data structure.
           */
          af_data->file_format = AFWFileFormatRaw;
          af_data->sndobj_format = SndObjTypeDSP;
          af_data->entire_length = rd.data_length;
          af_data->buffer = NULL;
          af_data->length = 0;

          af_data->block_align = rd.block_align;
          af_data->block_length = (rd.sample_size == 16) ?
            2 : 1;

          af_data->sample_size = rd.sample_size;
          af_data->channels = rd.channels;
          af_data->sample_rate = rd.sample_rate;
          af_data->bytes_per_sec = rd.sample_rate *
            ((rd.sample_size == 16) ? 2 : 1);
      }

      /* If fp is not NULL, then that implies it did not match
       * any file type supported.
       */
      if(fp != NULL)
      {
          fclose(fp);
          return(-1);
      }
      else
      {
          return(0);
      }
}


/*
 *    If af_data has a sndobj_format of SndObjTypeDSP, then this
 *    function:
 *
 *    Frees buffer on af_data (if allocated), reads a segment of
 *    data from the DSP sound object on file, and then allocates
 *    a new buffer and updates values on af_data. Returns 0 on success
 *    or -1 on error.
 *
 *
 *    If af_data has a sndobj_format of SndObjTypeMIDI, then this
 *    function:
 *
 *    Checks if the MIDI sound object is being played; If the
 *    sound object is not being played then it forks off a
 *    process to control the MIDI device to play the MIDI sound
 *    object on file, returning:
 *          0   on success
 *          -1  on error
 *          -2  another play process started thus stopping this one
 *          -3  finished play
 *    If the MIDI sound object is last known to be playing (marked
 *    by a previous call to this function), then it checks if the
 *    child process playing the MIDI sound object is still playing
 *    it, if it has stopped playing then -3 is returned or if it
 *    is still playing then 0 is returned.
 */
int AFWLoadSegment(
      AFWDataStruct *af_data,
      YDataPosition position,
      YDataLength length,
      Audio *audio
)
{
      int status;
      pid_t pid;
      raw_data_struct *raw_data;
      wav_data_struct *wav_data;
      voc_data_struct *voc_data;
      MidiDataStruct *midi_data;

      MIDIAudio *midi_audio_ptr = NULL;


      if(af_data == NULL)
          return(-1);
      if(af_data->ptr == NULL)
          return(-1);

      /* Check sound object format type. */
      if(af_data->sndobj_format == SndObjTypeMIDI)
      {
          /* It is a MIDI Sound Object. */

          status = 0;

          /* Get pointer to MIDI Audio. */
          if(audio == NULL)
          {
            status = -1;
            return(status);
          }
          else
          {
            midi_audio_ptr = &audio->midi_audio;
          }

          /* Handle by MIDI file format. */
          switch(af_data->file_format)
          {
            case AFWFileFormatMidi:
              midi_data = (MidiDataStruct *)af_data->ptr;

            /* Get pid of actual current MIDI play (if any). */
            pid = MIDIIOWIsPlaying(midi_audio_ptr);

            /* Was this MIDI being played? */
            if(af_data->pid > 0)
            {
                /* MIDI play is _expected_ to be currently active. */

                /* Is a MIDI currently being played? */
                if(pid > 0)
                {
                  /*   MIDI play is active but is it the same play
                   *   as this MIDI object?
                   */
                    if(pid != af_data->pid)
                  {
                      /* No it is not the same play, so mark this
                       * as stopped.
                       */
                      status = -2;
                      af_data->pid = 0;
                  }
                }
                else
                {
                  /* Midi play process has finished. */
                  status = -3;
                  af_data->pid = 0;
                }
            }
            else
            {
                /* This MIDI was not being played, so we are going to
                 * start playing this MIDI.
                 */

                /* Is a MIDI currently being played? */
                if(pid > 0)
                {
                  /* An MIDI is still being played, stop it. */
                  MIDIIOWStop(midi_audio_ptr);

                  pid = 0;
                }

                /* Begin new midi play. */
                if(midi_data->filename != NULL)
                {
                  pid = MIDIIOWPlay(
                      midi_audio_ptr,
                      midi_data->filename
                  );
                  if(pid == 0)
                      status = -1;

                  /* Record new pid. */
                  af_data->pid = pid;
                }
            }
            break;

            default:
            status = -1;
            break;
          }

          return(status);
      }
      else if(af_data->sndobj_format == SndObjTypeDSP)
      {
          /* It is a DSP Sound Object. */

          /* Do not free the buffer on our af_data, it is shared and
           * will be free'ed by the call to the library function.
           */
          af_data->length = 0;

          /* Load audio segment by the sound object file format. */
          switch(af_data->file_format)
          {
            case AFWFileFormatRaw:
            raw_data = (raw_data_struct *)af_data->ptr;
            status = RawReadPartialData(
                raw_data,
                position,   
                length,
                RawReadSigned8
            );
            if(status == RawSuccess)
            {
                AFWCopyDataAlloc(
                  raw_data->data,
                  raw_data->data_len,
                  &af_data->buffer,
                  &af_data->length
                );
            }
            else
            {
                af_data->buffer = NULL;
            }
            break;

            case AFWFileFormatWav:
              wav_data = (wav_data_struct *)af_data->ptr;
              status = WavReadPartialData(
                wav_data,
                position,           /* Position. */
                length,       /* How much to load. */
                WavReadSigned8
              );
              if(status == WavSuccess)
              {
                AFWCopyDataAlloc(
                  wav_data->data,
                  wav_data->data_len,
                  &af_data->buffer,
                  &af_data->length
                );
              }
              else
            {
                af_data->buffer = NULL;
            }
            break;

            case AFWFileFormatVoc:
            voc_data = (voc_data_struct *)af_data->ptr;
              status = VocReadPartialData(
                voc_data,
                position,
                length,
                VocReadSigned8
              );
            if(status == VocSuccess)
            {
                AFWCopyDataAlloc(
                  voc_data->data,
                  voc_data->data_len,
                  &af_data->buffer,
                  &af_data->length
                );
            }
            else
            {
                af_data->buffer = NULL;
            }
            break;

            case AFWFileFormatMP3:
            return(-1);
            break;
 
            default:
              return(-1);
            break;
          }
      }
      else
      {
          /* Unsupported sound object type. */
          return(-1);
      }


      return(0);
}

/*
 *    Closes the audio file, deallocating any allocated resources.
 *
 *    If the object was a MIDI, then the MIDI play process will
 *    be stopped.
 */
void AFWClose(AFWDataStruct *af_data, Audio *audio)
{
      pid_t pid;
      MIDIAudio *midi_audio_ptr;


      if(af_data == NULL)
          return;

      /* Deallocate library resources and memory. */
      switch(af_data->file_format)
      {
        case AFWFileFormatRaw:
          RawDestroyData((raw_data_struct *)af_data->ptr);
          break;

        case AFWFileFormatWav:
          WavDestroyData((wav_data_struct *)af_data->ptr);
          break;

        case AFWFileFormatVoc:
          VocDestroyData((voc_data_struct *)af_data->ptr);
          break;

        case AFWFileFormatMP3:
          break;

        case AFWFileFormatMidi:
          /* Get pointer to MIDI Audio. */
          if(audio != NULL)
          {
            midi_audio_ptr = &audio->midi_audio;

            /* Stop MIDI play if it is playing this. */
            pid = MIDIIOWIsPlaying(midi_audio_ptr);

            if((af_data->pid == pid) &&
               (af_data->pid > 0)
            )
            {
                /* MIDI play is still playing this MIDI, stop it. */
                MIDIIOWStop(midi_audio_ptr);
            }
          }

          /* Reset pid. */
          af_data->pid = 0;

          MidiDestroy((MidiDataStruct *)af_data->ptr);
          break;

        default:
          break;
      }

      /* Free library structure (library does not free this). */
      free(af_data->ptr);
      af_data->ptr = NULL;

      /* Free loaded DSP data, since it's a duplicate of the data
       * loaded by the library.
       */
      free(af_data->buffer);
      af_data->buffer = NULL;
      af_data->length = 0;

      af_data->block_align = 0;
      af_data->block_length = 1;

      af_data->pid = 0;


      return;
}

Generated by  Doxygen 1.6.0   Back to index