📄 wavfile.c
字号:
/* $Header: /cvsroot/qgo/qgo/src/wavfile.c,v 1.8 2005/09/08 18:46:31 yfh2 Exp $ * Copyright: wavfile.c (c) Erik de Castro Lopo erikd@zip.com.au * * wavfile.c - Functions for reading and writing MS-Windoze .WAV files. * * 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, 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. * * This code was originally written to manipulate Windoze .WAV files * under i386 Linux. Please send any bug reports or requests for * enhancements to : erikd@zip.com.au * * * Revision 1.4 2004/05/26 17:44:05 yfh2 * 0.2.1 b1 preparing BSD compatibiility * * Revision 1.3 2003/04/14 07:41:49 frosla * 0.0.16b8: skipped some widget; cosmetics * * Revision 1.1.1.1 1999/11/21 19:50:56 wwg * Import wavplay-1.3 into CVS * * Revision 1.2 1997/04/17 00:59:55 wwg * Fixed so that a fmt chunk that is larger than expected * is accepted, but if smaller - _then_ treat it as an * error. * * Revision 1.1 1997/04/14 00:14:38 wwg * Initial revision * * change log: * 16.02.97 - Erik de Castro Lopo * Ported from MS-Windows to Linux for Warren W. Gay's * wavplay project. */ #ifdef __linux__static const char rcsid[] = "@(#)wavfile.c $Revision: 1.8 $";#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <malloc.h>#include <string.h>#include <memory.h>#include <signal.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/ioctl.h>#include <assert.h>#include <linux/soundcard.h>#if WORDS_BIGENDIAN#define SwapLE16(x) ((((u_int16_t)x)<<8)|(((u_int16_t)x)>>8))#define SwapLE32(x) ((((u_int32_t)x)<<24)|((((u_int32_t)x)<<8)&0x00FF0000) \ |((((u_int32_t)x)>>8)&0x0000FF00)|(((u_int32_t)x)>>24))#else#define SwapLE16(x) (x)#define SwapLE32(x) (x)#endif#include "wavplay.h"#define BUFFERSIZE 1024#define PCM_WAVE_FORMAT 1#define TRUE 1#define FALSE 0#define RECPLAY_UPDATES_PER_SEC 3typedef struct{ u_int32_t dwSize ; u_int16_t wFormatTag ; u_int16_t wChannels ; u_int32_t dwSamplesPerSec ; u_int32_t dwAvgBytesPerSec ; u_int16_t wBlockAlign ; u_int16_t wBitsPerSample ;} WAVEFORMAT ;typedef struct{ char RiffID [4] ; u_int32_t RiffSize ; char WaveID [4] ; char FmtID [4] ; u_int32_t FmtSize ; u_int16_t wFormatTag ; u_int16_t nChannels ; u_int32_t nSamplesPerSec ; u_int32_t nAvgBytesPerSec ; u_int16_t nBlockAlign ; u_int16_t wBitsPerSample ; char DataID [4] ; u_int32_t nDataBytes ;} WAVE_HEADER ;/*=================================================================================================*/char* findchunk (char* s1, char* s2, size_t n) ;/*=================================================================================================*/static WAVE_HEADER waveheader ={ { 'R', 'I', 'F', 'F' }, 0, { 'W', 'A', 'V', 'E' }, { 'f', 'm', 't', ' ' }, 16, /* FmtSize*/ PCM_WAVE_FORMAT, /* wFormatTag*/ 0, /* nChannels*/ 0, 0, 0, 0, { 'd', 'a', 't', 'a' }, 0} ; /* waveheader*/static ErrFunc v_erf; /* wwg: Error reporting function */static void _v_erf(const char *, va_list); /* This module's error reporting function */static char emsg[2048];/* * Error reporting function for this source module: */static voiderr(const char *format,...) { va_list ap; fprintf(stdout, "error : %s \n",format); /*/if ( v_erf == NULL )*/ /*/ return; /* Only report error if we have function */ va_start(ap,format); _v_erf(format,ap); /* Use caller's supplied function */ va_end(ap);}static void_v_erf(const char *format,va_list ap) { vsprintf(emsg,format,ap); /* Capture message into emsg[] */}int WaveReadHeader (int wavefile, int* channels, u_long* samplerate, int* samplebits, u_long* samples, u_long* datastart,ErrFunc erf){ static WAVEFORMAT waveformat ; static char buffer [ BUFFERSIZE ] ; /* Function is not reentrant.*/ char* ptr ; u_long databytes ; v_erf = erf; /* wwg: Set error reporting function */ if (lseek (wavefile, 0L, SEEK_SET)) { err("%s",sys_errlist[errno]); /* wwg: Report error */ return WR_BADSEEK ; } read (wavefile, buffer, BUFFERSIZE) ; if (findchunk (buffer, "RIFF", BUFFERSIZE) != buffer) { err("Bad format: Cannot find RIFF file marker"); /* wwg: Report error */ return WR_BADRIFF ; } if (! findchunk (buffer, "WAVE", BUFFERSIZE)) { err("Bad format: Cannot find WAVE file marker"); /* wwg: report error */ return WR_BADWAVE ; } ptr = findchunk (buffer, "fmt ", BUFFERSIZE) ; if (! ptr) { err("Bad format: Cannot find 'fmt' file marker"); /* wwg: report error */ return WR_BADFORMAT ; } ptr += 4 ; /* Move past "fmt ".*/ memcpy (&waveformat, ptr, sizeof (WAVEFORMAT)) ; waveformat.dwSize = SwapLE32(waveformat.dwSize); waveformat.wFormatTag = SwapLE16(waveformat.wFormatTag) ; waveformat.wChannels = SwapLE16(waveformat.wChannels) ; waveformat.dwSamplesPerSec = SwapLE32(waveformat.dwSamplesPerSec) ; waveformat.dwAvgBytesPerSec = SwapLE32(waveformat.dwAvgBytesPerSec) ; waveformat.wBlockAlign = SwapLE16(waveformat.wBlockAlign) ; waveformat.wBitsPerSample = SwapLE16(waveformat.wBitsPerSample) ; if (waveformat.dwSize < (sizeof (WAVEFORMAT) - sizeof (u_long))) { err("Bad format: Bad fmt size"); /* wwg: report error */ return WR_BADFORMATSIZE ; } if (waveformat.wFormatTag != PCM_WAVE_FORMAT) { err("Only supports PCM wave format"); /* wwg: report error */ return WR_NOTPCMFORMAT ; } ptr = findchunk (buffer, "data", BUFFERSIZE) ; if (! ptr) { err("Bad format: unable to find 'data' file marker"); /* wwg: report error */ return WR_NODATACHUNK ; } ptr += 4 ; /* Move past "data".*/ memcpy (&databytes, ptr, sizeof (u_long)) ; /* Everything is now cool, so fill in output data.*/ *channels = waveformat.wChannels ; *samplerate = waveformat.dwSamplesPerSec ; *samplebits = waveformat.wBitsPerSample ; *samples = databytes / waveformat.wBlockAlign ; *datastart = ((u_long) (ptr + 4)) - ((u_long) (&(buffer[0]))) ; if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wBlockAlign) { err("Bad file format"); /* wwg: report error */ return WR_BADFORMATDATA ; } if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wChannels / ((waveformat.wBitsPerSample == 16) ? 2 : 1)) { err("Bad file format"); /* wwg: report error */ return WR_BADFORMATDATA ; } return 0 ;} ; /* WaveReadHeader*//*===========================================================================================*/#if 0char* WaveFileError (int errno){ switch (errno) { case WW_BADOUTPUTFILE : return "Bad output file.\n" ; case WW_BADWRITEHEADER : return "Not able to write WAV header.\n" ; case WR_BADALLOC : return "Not able to allocate memory.\n" ; case WR_BADSEEK : return "fseek failed.\n" ; case WR_BADRIFF : return "Not able to find 'RIFF' file marker.\n" ; case WR_BADWAVE : return "Not able to find 'WAVE' file marker.\n" ; case WR_BADFORMAT : return "Not able to find 'fmt ' file marker.\n" ; case WR_BADFORMATSIZE : return "Format size incorrect.\n" ; case WR_NOTPCMFORMAT : return "Not PCM format WAV file.\n" ; case WR_NODATACHUNK : return "Not able to find 'data' file marker.\n" ; case WR_BADFORMATDATA : return "Format data questionable.\n" ; default : return "No error\n" ; } ; return NULL ; } ; /* WaveFileError*/#endif/*===========================================================================================*/char* findchunk (char* pstart, char* fourcc, size_t n){ char *pend ; int k, test ; pend = pstart + n ; while (pstart < pend) { if (*pstart == *fourcc) /* found match for first char*/ { test = TRUE ; for (k = 1 ; fourcc [k] != 0 ; k++) test = (test ? ( pstart [k] == fourcc [k] ) : FALSE) ; if (test) return pstart ; } ; /* if*/ pstart ++ ; } ; /* while lpstart*/ return NULL ;} ; /* findchuck*//* $Source: /cvsroot/qgo/qgo/src/wavfile.c,v $ *//* * Internal routine to allocate WAVFILE structure: */static WAVFILE *wavfile_alloc(const char *Pathname) { WAVFILE *wfile = (WAVFILE *) malloc(sizeof (WAVFILE)); if ( wfile == NULL ) { err("%s: Allocating WAVFILE structure",sys_errlist[ENOMEM]); return NULL; } memset(wfile,0,sizeof *wfile); if ( (wfile->Pathname = strdup(Pathname)) == NULL ) { free(wfile); err("%s: Allocating storage for WAVFILE.Pathname",sys_errlist[ENOMEM]); return NULL; } wfile->fd = -1; /* Initialize fd as not open */ wfile->wavinfo.Channels = Mono; wfile->wavinfo.DataBits = 8; return wfile;}/* * Internal routine to release WAVFILE structure: * No errors reported. */static voidwavfile_free(WAVFILE *wfile) { if ( wfile->Pathname != NULL ) free(wfile->Pathname); free(wfile);}/* * Open a WAV file for reading: returns (WAVFILE *) * * The opened file is positioned at the first byte of WAV file data, or * NULL is returned if the open is unsuccessful. */WAVFILE *WavOpenForRead(const char *Pathname,ErrFunc erf) { WAVFILE *wfile = wavfile_alloc(Pathname); int e; /* Saved errno value */ UInt32 offset; /* File offset */ Byte ubuf[4]; /* 4 byte buffer */ UInt32 dbytes; /* Data byte count */ /* wavfile.c values : */ int channels; /* Channels recorded in this wav file */ u_long samplerate; /* Sampling rate */ int sample_bits; /* data bit size (8/12/16) */ u_long samples; /* The number of samples in this file */ u_long datastart; /* The offset to the wav data */ v_erf = erf; /* Set error reporting function */ if ( wfile == NULL ) return NULL; /* Insufficient memory (class B msg) */ /* * Open the file for reading: */ if ( (wfile->fd = open(wfile->Pathname,O_RDONLY)) < 0 ) { err("%s:\nOpening WAV file %s", sys_errlist[errno], wfile->Pathname); goto errxit; } if ( lseek(wfile->fd,0L,SEEK_SET) != 0L ) { err("%s:\nRewinding WAV file %s", sys_errlist[errno], wfile->Pathname); goto errxit; /* Wav file must be seekable device */ } if ( (e = WaveReadHeader(wfile->fd,&channels,&samplerate,&sample_bits,&samples,&datastart,_v_erf)) != 0 ) { err("%s:\nReading WAV header from %s", emsg, wfile->Pathname); goto errxit; } /* * Copy WAV data over to WAVFILE struct: */ if ( channels == 2 ) wfile->wavinfo.Channels = Stereo; else wfile->wavinfo.Channels = Mono; wfile->wavinfo.SamplingRate = (UInt32) samplerate; wfile->wavinfo.Samples = (UInt32) samples; wfile->wavinfo.DataBits = (UInt16) sample_bits; wfile->wavinfo.DataStart = (UInt32) datastart; wfile->num_samples = wfile->wavinfo.Samples; wfile->rw = 'R'; /* Read mode */ offset = wfile->wavinfo.DataStart - 4; /* * Seek to byte count and read dbytes: */ if ( lseek(wfile->fd,offset,SEEK_SET) != offset ) { err("%s:\nSeeking to WAV data in %s",sys_errlist[errno],wfile->Pathname); goto errxit; /* Seek failure */ } if ( read(wfile->fd,ubuf,4) != 4 ) { err("%s:\nReading dbytes from %s",sys_errlist[errno],wfile->Pathname); goto errxit; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -