2011-09-07 19:47:12 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <string.h>
|
2011-09-08 11:58:01 +00:00
|
|
|
#include <stdlib.h>
|
2011-09-07 19:47:12 +00:00
|
|
|
#include "wav.h"
|
|
|
|
#include "mmap_file.h"
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint32_t ChunkID;
|
|
|
|
uint32_t ChunkSize;
|
|
|
|
uint32_t Format;
|
|
|
|
uint32_t Subchunk1ID;
|
|
|
|
uint32_t Subchunk1Size;
|
|
|
|
uint16_t AudioFormat;
|
|
|
|
uint16_t NumChannels;
|
|
|
|
uint32_t SampleRate;
|
|
|
|
uint32_t ByteRate;
|
|
|
|
uint16_t BlockAlign;
|
|
|
|
uint16_t BitsPerSample;
|
|
|
|
uint32_t Subchunk2ID;
|
|
|
|
uint32_t Subchunk2Size;
|
|
|
|
} wav_head_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
void (*close)(pcm_t *);
|
|
|
|
void (*info)(pcm_t *);
|
|
|
|
int (*rate)(pcm_t *);
|
|
|
|
int (*channels)(pcm_t *);
|
|
|
|
int (*read)(struct pcm *, short *, int);
|
|
|
|
void *p;
|
|
|
|
short *b;
|
|
|
|
size_t size;
|
|
|
|
int r;
|
|
|
|
int c;
|
|
|
|
int samples;
|
|
|
|
int index;
|
|
|
|
} wav_t;
|
|
|
|
|
|
|
|
void close_wav(pcm_t *pcm)
|
|
|
|
{
|
|
|
|
wav_t *wav = (wav_t *)pcm;
|
|
|
|
munmap_file(wav->p, wav->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
void info_wav(pcm_t *pcm)
|
|
|
|
{
|
|
|
|
wav_t *wav = (wav_t *)pcm;
|
|
|
|
fprintf(stderr, "%d channel(s), %d rate, %d samples\n", wav->c, wav->r, wav->samples);
|
|
|
|
}
|
|
|
|
int rate_wav(pcm_t *pcm)
|
|
|
|
{
|
|
|
|
wav_t *wav = (wav_t *)pcm;
|
|
|
|
return wav->r;
|
|
|
|
}
|
|
|
|
int channels_wav(pcm_t *pcm)
|
|
|
|
{
|
|
|
|
wav_t *wav = (wav_t *)pcm;
|
|
|
|
return wav->c;
|
|
|
|
}
|
|
|
|
int read_wav(pcm_t *pcm, short *buff, int frames)
|
|
|
|
{
|
|
|
|
wav_t *wav = (wav_t *)pcm;
|
|
|
|
if ((wav->index + frames * wav->c) > wav->samples)
|
|
|
|
return 0;
|
|
|
|
memcpy(buff, wav->b + wav->index, sizeof(short) * frames * wav->c);
|
|
|
|
wav->index += frames * wav->c;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int open_wav(pcm_t **p, char *name)
|
|
|
|
{
|
|
|
|
wav_t *wav = (wav_t *)malloc(sizeof(wav_t));
|
|
|
|
wav->close = close_wav;
|
|
|
|
wav->info = info_wav;
|
|
|
|
wav->rate = rate_wav;
|
|
|
|
wav->channels = channels_wav;
|
|
|
|
wav->read = read_wav;
|
|
|
|
if (!mmap_file_ro(&wav->p, name, &wav->size)) {
|
|
|
|
fprintf(stderr, "couldnt open wav file %s!\n", name);
|
|
|
|
free(wav);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
wav_head_t *head = (wav_head_t *)wav->p;
|
|
|
|
wav->b = (short *)(wav->p + sizeof(wav_head_t));
|
|
|
|
|
|
|
|
if (head->ChunkID != 0x46464952 || head->Format != 0x45564157 ||
|
|
|
|
head->Subchunk1ID != 0x20746d66 || head->Subchunk1Size != 16 ||
|
|
|
|
head->AudioFormat != 1 || head->Subchunk2ID != 0x61746164) {
|
|
|
|
fprintf(stderr, "unsupported WAV file!\n");
|
|
|
|
munmap_file(wav->p, wav->size);
|
|
|
|
free(wav);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (head->BitsPerSample != 16) {
|
|
|
|
fprintf(stderr, "only 16bit WAV supported!\n");
|
|
|
|
munmap_file(wav->p, wav->size);
|
|
|
|
free(wav);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
wav->c = head->NumChannels;
|
|
|
|
wav->samples = head->Subchunk2Size / 2;
|
|
|
|
wav->index = 0;
|
|
|
|
wav->r = head->SampleRate;
|
|
|
|
*p = (pcm_t *)wav;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|