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

gmi_wav.c

/*
 *      Tag and audio information retrieval from Riff/WAVE files.
 *
 *      Copyright (c) 2005 Nyaochi
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
 * http://www.gnu.org/copyleft/gpl.html .
 *
 */

/* $Id: gmi_wav.c,v 1.3 2005/07/20 02:03:48 nyaochi Exp $ */

#ifdef      HAVE_CONFIG_H
#include <config.h>
#endif/*HAVE_CONFIG_H*/

#include <os.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <ucs2char.h>
#include <h10db.h>
#include <getmediainfo.h>

#define     MIN(a, b)   ((a) < (b) ? (a) : (b))

struct tag_chunk_header {
      uint32_t id;
      uint32_t size;
};
typedef struct tag_chunk_header chunk_header_t;


/* Currently, only for little endian machines. */
static int read_uint16le(uint16_t* val, FILE *fp)
{
      uint8_t v[2];
      int ret = (fread(v, sizeof(uint8_t), 2, fp) == 2) ? 0 : 1;
      *val = (uint16_t)v[1] << 8 | (uint16_t)v[0];
      return ret;
}

static int read_uint32le(uint32_t* val, FILE *fp)
{
      uint8_t v[4];
      int ret = (fread(v, sizeof(uint8_t), 4, fp) == 4) ? 0 : 1;
      *val = (uint32_t)v[3] << 24 | (uint32_t)v[2] << 16 | (uint32_t)v[1] << 8 | (uint32_t)v[0];
      return ret;
}

static int read_chunk_header(chunk_header_t* ch, FILE *fp)
{
      int ret = 0;
      ret |= read_uint32le(&ch->id, fp);
      ret |= read_uint32le(&ch->size, fp);
      return ret;
}




int parse_listinfo(media_info* info, FILE *fp, uint32_t chunksize)
{
      int ret = 0;
      char buffer[1024];
      chunk_header_t ch;

      long base = ftell(fp);
      long offset = 0;

      while (offset = ftell(fp), base <= offset && offset < base+(long)chunksize) {
            long pos = 0;
            uint32_t size;
            if (pos < 0) {
                  goto parse_listinfo_error;
            }
            ret |= read_chunk_header(&ch, fp);
            if (feof(fp)) {
                  break;
            }
            if (ret != 0) {
                  goto parse_listinfo_error;
            }

            pos = ftell(fp);

            memset(buffer, 0, sizeof(buffer));
            size = MIN(ch.size, sizeof(buffer)-2);
            fread(buffer, sizeof(char), size, fp);

            switch (ch.id) {
            case 0x44525049:  /* "IPRD" */
                  free(info->album);
                  info->album = mbsdupucs2_music(buffer);
                  break;
            case 0x4D414E49:  /* "INAM" */
                  free(info->title);
                  info->title = mbsdupucs2_music(buffer);
                  break;
            case 0x54524149:  /* "IART" */
                  free(info->artist);
                  info->artist = mbsdupucs2_music(buffer);
                  break;
            case 0x524E4749:  /* "IGNR" */
                  free(info->genre);
                  info->genre = mbsdupucs2_music(buffer);
                  break;
            case 0x44524349:  /* "ICRD" */
                  info->year = atoi(buffer);
                  break;
            case 0x6974726B:  /* "itrk" */
                  info->tracknumer = atoi(buffer);
                  break;
            }

            /* Round out the chunk size to align word boundary. */
            if (ch.size & 0x01) {
                  ch.size++;
            }

            fseek(fp, pos + ch.size, SEEK_SET);
      }

      return 0;

parse_listinfo_error:
      return 1;
}


int get_riff_audio_info(media_info* info, const ucs2_char_t *filename)
{
      int ret = 0;
      FILE *fp = NULL;
      uint32_t tmp32;
      uint16_t tmp16;
      chunk_header_t ch;
      uint16_t channels, sample_bits;
      
      /* Open the audio file. */
      fp = ucs2fopen(filename, "rb");
      if (!fp) {
            return -1;
      }

      /* Make sure RIFF format. */
      ret |= read_chunk_header(&ch, fp);
      if (ret != 0 || ch.id != 0x46464952) {
            goto get_riff_audio_info_error;
      }
      info->filesize = ch.size + 8;

      /* Make sure Riff type to be "WAVE". */
      ret |= read_uint32le(&tmp32, fp);
      if (ret != 0 || tmp32 != 0x45564157) {
            goto get_riff_audio_info_error;
      }

      for (;;) {
            long pos = 0;
            if (pos < 0) {
                  goto get_riff_audio_info_error;
            }
            ret |= read_chunk_header(&ch, fp);
            if (feof(fp)) {
                  break;
            }
            if (ret != 0) {
                  goto get_riff_audio_info_error;
            }

            pos = ftell(fp);

            switch (ch.id) {
            case 0x20746D66:  /* "fmt " */
                  /* Make sure the format to be PCM. */
                  ret |= read_uint16le(&tmp16, fp);
                  if (ret != 0 || tmp16 != 1) {
                        goto get_riff_audio_info_error;
                  }
                  /* Read number of channels. */
                  ret |= read_uint16le(&channels, fp);
                  if (ret != 0) {
                        goto get_riff_audio_info_error;                             
                  }
                  /* Read sample rate. */
                  ret |= read_uint32le(&tmp32, fp);
                  if (ret != 0) {
                        goto get_riff_audio_info_error;                             
                  }
                  info->samplerate = tmp32;
                  /* Skip averate bytes per second. */
                  ret |= read_uint32le(&tmp32, fp);
                  if (ret != 0) {
                        goto get_riff_audio_info_error;                             
                  }
                  /* Skip block align. */
                  ret |= read_uint16le(&tmp16, fp);
                  if (ret != 0) {
                        goto get_riff_audio_info_error;                             
                  }
                  /* Read sample bit. */
                  ret |= read_uint16le(&sample_bits, fp);
                  if (ret != 0) {
                        goto get_riff_audio_info_error;                             
                  }
                  /* Calculate bitrate. */
                  info->bitrate = channels * sample_bits * info->samplerate;
                  break;
            case 0x61746164:
                  info->duration = (uint32_t)((double)ch.size * 8.0 / info->bitrate);
                  break;
            case 0x5453494C:
                  ret |= read_uint32le(&tmp32, fp);
                  if (ret != 0) {
                        goto get_riff_audio_info_error;                             
                  }
                  if (tmp32 == 0x4F464E49) {
                        ret |= parse_listinfo(info, fp, ch.size - 4);
                        if (ret != 0) {
                              goto get_riff_audio_info_error;                             
                        }
                  }
                  break;
            }

            fseek(fp, pos + ch.size, SEEK_SET);
      }

      fclose(fp);
      return 0;

get_riff_audio_info_error:
      fclose(fp);
      return -1;
}

int gettag_wav(media_info* info, const ucs2_char_t *path, const ucs2_char_t *file)
{
      int ret = 0;

      /* Obtain the filename. */
      ucs2_char_t pathname[MAX_PATH+1];
      ucs2cpy(pathname, path);
      ucs2cat(pathname, file);

      /* Set the pathname and filename. */
      info->pathname = ucs2dup(path);
      info->filename = ucs2dup(file);

      /* Set the filename to title in case we could not retrieve track title. */
      free(info->title);
      info->title = gettag_setfilename(file);

      ret = get_riff_audio_info(info, pathname);

      if (!info->title || !*info->title) {
            ucs2free(info->title);
            info->title = gettag_setfilename(file);
      }

      return ret;
}

Generated by  Doxygen 1.6.0   Back to index