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

midi.c

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

#include "midi.h"


/* static void swap32(int32_t *i); */
static void swapu32(u_int32_t *i);
/*
static int MidiFGetVarlenNumber(FILE *fp);
static int MidiGetVarlenNumber(const char *buf, int max);
 */

int MidiIsFileMidi(const char *filename);
int MidiRead(const char *filename, FILE *fp, MidiDataStruct *md);
void MidiDestroy(MidiDataStruct *md);


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


#if 0
void swap32(int32_t *i)
{
      int32_t tmp;
      int8_t *src, *tar;

      if(i == NULL)
          return;

      tmp = *i;
      src = (int8_t *)&tmp;
      tar = (int8_t *)i;

      tar[3] = src[0];
      tar[2] = src[1];
      tar[1] = src[2];
      tar[0] = src[3];
}
#endif

void swapu32(u_int32_t *i)
{
      u_int32_t tmp = *i;
      u_int8_t *src = (u_int8_t *)&tmp,
             *tar = (u_int8_t *)i;

      tar[3] = src[0];
      tar[2] = src[1];
      tar[1] = src[2];
      tar[0] = src[3];
}

#if 0
/*
 *    Reads variable-length number from FILE pointer fp,
 *    fp will be incremented to the point just after the bytes
 *    making up the variable-length number.
 */
int MidiFGetVarlenNumber(FILE *fp)
{
      int c, p = 0, val = 0;


      if(fp == NULL)
          return(0);

      do
      {
          c = fgetc(fp);
          if(c == EOF)
            break;

          val += (((u_int8_t)c & 0x7f) << (p * 8));
          p++;
      }
      while(((u_int8_t)c & 0x80) && (p <= 4));

      return(val);
}
#endif

#if 0
/*
 *      Reads variable-length number from buffer pointer buf.
 *    Will not read more than max bytes.
 */
int MidiGetVarlenNumber(const char *buf, int max)
{
      int p = 0, val = 0;


      if(buf == NULL)
          return(0);
 
      do
      {
          val += (((u_int8_t)*buf & 0x7f) << (p * 8));

          buf++;
          p++;
      }
      while(((u_int8_t)*buf & 0x80) && (p <= max));

      return(val);
}
#endif

/*
 *    Returns MidiSuccess if filename is a MIDI file or
 *    MidiBadValue if filename is not a MIDI file.
 */
int MidiIsFileMidi(const char *filename)
{
      int i, c;
      struct stat stat_buf;
      FILE *fp;
      char chunk_type_name[MidiChunkTypeNameLen + 1];


      if(filename == NULL)
          return(MidiBadValue);


      /* Check if file exists. */
      if(stat(filename, &stat_buf))
          return(MidiBadValue);

      /* Open file. */
      fp = fopen(filename, "rb");
      if(fp == NULL)
          return(MidiBadValue);


      /* Read first few bytes. */
      *chunk_type_name = '\0';
      for(i = 0; i < MidiChunkTypeNameLen; i++)
      {
          c = fgetc(fp);
          if(c == EOF)
            break;

          chunk_type_name[i] = (char)c;
      }
      chunk_type_name[MidiChunkTypeNameLen] = '\0';

      /* Close file. */
      fclose(fp);
      

      if(!strcmp(chunk_type_name, MidiChunkTypeNameHeader) ||
         !strcmp(chunk_type_name, MidiChunkTypeNameTrack)
      )
          return(MidiSuccess);
      else
          return(MidiBadValue);
}


/*
 *   Reads the header from the stream fp and initializes the given
 *   md structure if fp is valid and a midi file.
 *
 *   The given filename is used as referance purposes, it can be NULL.
 *
 *   If MidiSuccess is returned then the given fp will be transfered
 *   to the md structure and should not be referanced again. For all
 *   other return values, the calling function is responsible for
 *   closing the given fp.
 */
int MidiRead(const char *filename, FILE *fp, MidiDataStruct *md)
{
      int need_break;
      int i, c;
      struct stat stat_buf;
      off_t filepos, filesize;

      char chunk_type_name[MidiChunkTypeNameLen + 1];
      u_int32_t chunk_len;
      MidiChunkStruct *chunk;

      u_int8_t *buf_ptr;
      int buf_len;


      if(md == NULL)
          return(MidiNoBuffers);
      if(fp == NULL)
          return(MidiNoAccess);

      /* Rewind fp to beginning of midi file. */
      rewind(fp);


      /* Reset values. */
      memset(md, 0x00, sizeof(MidiDataStruct));

      /* Get size of file. */
      if(fstat(fileno(fp), &stat_buf))
          return(MidiNoAccess);

      filesize = stat_buf.st_size;
      if(filesize == 0)
          return(MidiErrorNotMidi);


      /* Check if this is a midi file by reading the first few bytes. */
      *chunk_type_name = '\0';
      for(i = 0; i < MidiChunkTypeNameLen; i++)
      {
          c = fgetc(fp);
          if(c == EOF)
            break;

          chunk_type_name[i] = (char)c;
      }
      chunk_type_name[MidiChunkTypeNameLen] = '\0';
      if(strcmp(chunk_type_name, MidiChunkTypeNameHeader) &&
         strcmp(chunk_type_name, MidiChunkTypeNameTrack)
      )
          return(MidiErrorNotMidi);


      /* Begin reading midi file header. */

      /* Record file name. */
      if(filename != NULL)
          md->filename = strdup(filename);


      /* Read each chunk in the file. */
      rewind(fp);
      filepos = 0;
      while(filepos < filesize)
      {
          need_break = 0;

          /* Chunk type (4 bytes). */
          for(i = 0; i < MidiChunkTypeNameLen; i++)
          {
            c = fgetc(fp);
            if(c == EOF)
            {
                need_break = 1;
                break;
            }

            chunk_type_name[i] = (char)c;
          }
          chunk_type_name[MidiChunkTypeNameLen] = '\0'; /* Safe. */
          if(need_break)
            break;

          /* Read chunk length (4 bytes). */
          fread(&chunk_len, sizeof(u_int32_t), 1, fp);
          swapu32(&chunk_len);

          /* Chunk length specified in the file data does not include
           * chunk type and length bytes so add 8 to chunk_len.
           */
          chunk_len += (MidiChunkTypeNameLen + sizeof(u_int32_t)); 

          /* Allocate raw data buffer and read raw chunk data into it. */
          buf_len = (int)chunk_len - 8;
          if(buf_len > 0)
          {
              buf_ptr = (u_int8_t *)malloc(buf_len * sizeof(u_int8_t));
            if(buf_ptr != NULL)
                fread(buf_ptr, sizeof(u_int8_t), buf_len, fp);
            else
                break;
          }
          else
          {
            buf_ptr = NULL;
            buf_len = 0;
          }


          /* Allocate a new chunk structure. */
          i = md->total_chunks;
          md->total_chunks++;
          md->chunk = (MidiChunkStruct **)realloc(
            md->chunk,
            md->total_chunks * sizeof(MidiChunkStruct *)
          );
          if(md->chunk == NULL)
          {
            md->total_chunks = 0;
            break;
          }
          md->chunk[i] = chunk = (MidiChunkStruct *)calloc(
            1, sizeof(MidiChunkStruct)
          );
          if(chunk == NULL)
          {
            md->total_chunks -= 1;
            break;
          }



          /* Put fetched data into chunk structure. */

          /* Chunk type. */
          if(!strcmp(chunk_type_name, MidiChunkTypeNameHeader))
            chunk->type = MidiChunkTypeHeader;
          else if(!strcmp(chunk_type_name, MidiChunkTypeNameTrack))
            chunk->type = MidiChunkTypeTrack;
          else
            chunk->type = MidiChunkTypeUnknown;

          /* Chunk length. */
          chunk->len = chunk_len;

          /* Raw data buffer and length of it (might be NULL). */
          chunk->buf_len = buf_len;
          chunk->buf = buf_ptr;


          /* Parse by chunk type. */
          /* Header chunk. */
          if(chunk->type == MidiChunkTypeHeader)
          {
            if(buf_len >= 6)
            {
                /* Update the header information. */
                md->format = (int16_t)(
                  ((u_int16_t)buf_ptr[0] << 8) +
                  (u_int16_t)buf_ptr[1]
                );

                md->tracks = (int16_t)(
                  ((u_int16_t)buf_ptr[2] << 8) +
                  (u_int16_t)buf_ptr[3]  
                );

                md->divisions = (int16_t)(
                  ((u_int16_t)buf_ptr[4] << 8) +
                  (u_int16_t)buf_ptr[5]
                );
            }
          }
          /* Track chunk. */
          else if(chunk->type == MidiChunkTypeTrack)
          {

/* TODO */

          }


          /* Increment file position. */
          filepos += chunk_len;
          if(fseek(fp, filepos, SEEK_SET) == -1)
            break;
      }


      /* Close file since we are returning MidiSuccess and the calling
       * function will not referance the given fp again.
       */
/* Note, later on if we are reading the midi file, we should record
 * the given fp on the md structure.
 */
      fclose(fp);

      return(MidiSuccess);
}

/*
 *    Deallocates all allocated substructures in md.
 */
void MidiDestroy(MidiDataStruct *md)
{
      int i, n;
      MidiChunkStruct *chunk;


      if(md == NULL)
          return;

      free(md->filename);
      md->filename = NULL;


      /* Free each chunk. */
      for(i = 0; i < md->total_chunks; i++)
      {
          chunk = md->chunk[i];
          if(chunk == NULL)
            continue;

          /* Free each event in the chunk. */
          for(n = 0; n < chunk->total_events; n++)
            free(chunk->event[n]);
          free(chunk->event);

          /* Free raw data buffer. */
          free(chunk->buf);

          /* Free structure itself. */
          free(chunk);
      }

      free(md->chunk);
      md->chunk = NULL;
      md->total_chunks = 0;
}

Generated by  Doxygen 1.6.0   Back to index