⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wav.c

📁 Audacity是一款用於錄音和編輯聲音的、免費的開放源碼軟體。它可以執行於Mac OS X、Microsoft Windows、GNU/Linux和其它作業系統
💻 C
📖 第 1 页 / 共 3 页
字号:
/*** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.com>** Copyright (C) 2004 David Viens <davidv@plogue.com>**** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU Lesser General Public License as published by** the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.**** You should have received a copy of the GNU Lesser General Public License** along with this program; if not, write to the Free Software** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#include	<stdio.h>#include	<stdlib.h>#include	<string.h>#include	<ctype.h>#include	<time.h>#include	"sndfile.h"#include	"config.h"#include	"sfendian.h"#include	"common.h"#include	"wav_w64.h"/*------------------------------------------------------------------------------ * Macros to handle big/little endian issues. */#define RIFF_MARKER	 (MAKE_MARKER ('R', 'I', 'F', 'F'))#define WAVE_MARKER	 (MAKE_MARKER ('W', 'A', 'V', 'E'))#define fmt_MARKER	 (MAKE_MARKER ('f', 'm', 't', ' '))#define data_MARKER	 (MAKE_MARKER ('d', 'a', 't', 'a'))#define fact_MARKER	 (MAKE_MARKER ('f', 'a', 'c', 't'))#define PEAK_MARKER	 (MAKE_MARKER ('P', 'E', 'A', 'K'))#define cue_MARKER	 (MAKE_MARKER ('c', 'u', 'e', ' '))#define LIST_MARKER	 (MAKE_MARKER ('L', 'I', 'S', 'T'))#define slnt_MARKER	 (MAKE_MARKER ('s', 'l', 'n', 't'))#define wavl_MARKER	 (MAKE_MARKER ('w', 'a', 'v', 'l'))#define INFO_MARKER	 (MAKE_MARKER ('I', 'N', 'F', 'O'))#define plst_MARKER	 (MAKE_MARKER ('p', 'l', 's', 't'))#define adtl_MARKER	 (MAKE_MARKER ('a', 'd', 't', 'l'))#define labl_MARKER	 (MAKE_MARKER ('l', 'a', 'b', 'l'))#define ltxt_MARKER	 (MAKE_MARKER ('l', 't', 'x', 't'))#define note_MARKER	 (MAKE_MARKER ('n', 'o', 't', 'e'))#define smpl_MARKER	 (MAKE_MARKER ('s', 'm', 'p', 'l'))#define bext_MARKER	 (MAKE_MARKER ('b', 'e', 'x', 't'))#define MEXT_MARKER	 (MAKE_MARKER ('M', 'E', 'X', 'T'))#define DISP_MARKER	 (MAKE_MARKER ('D', 'I', 'S', 'P'))#define acid_MARKER	 (MAKE_MARKER ('a', 'c', 'i', 'd'))#define strc_MARKER	 (MAKE_MARKER ('s', 't', 'r', 'c'))#define PAD_MARKER	 (MAKE_MARKER ('P', 'A', 'D', ' '))#define afsp_MARKER	 (MAKE_MARKER ('a', 'f', 's', 'p'))#define clm_MARKER	 (MAKE_MARKER ('c', 'l', 'm', ' '))#define ISFT_MARKER	 (MAKE_MARKER ('I', 'S', 'F', 'T'))#define ICRD_MARKER	 (MAKE_MARKER ('I', 'C', 'R', 'D'))#define ICOP_MARKER	 (MAKE_MARKER ('I', 'C', 'O', 'P'))#define IARL_MARKER	 (MAKE_MARKER ('I', 'A', 'R', 'L'))#define IART_MARKER	 (MAKE_MARKER ('I', 'A', 'R', 'T'))#define INAM_MARKER	 (MAKE_MARKER ('I', 'N', 'A', 'M'))#define IENG_MARKER	 (MAKE_MARKER ('I', 'E', 'N', 'G'))#define IART_MARKER	 (MAKE_MARKER ('I', 'A', 'R', 'T'))#define ICOP_MARKER	 (MAKE_MARKER ('I', 'C', 'O', 'P'))#define IPRD_MARKER	 (MAKE_MARKER ('I', 'P', 'R', 'D'))#define ISRC_MARKER	 (MAKE_MARKER ('I', 'S', 'R', 'C'))#define ISBJ_MARKER	 (MAKE_MARKER ('I', 'S', 'B', 'J'))#define ICMT_MARKER	 (MAKE_MARKER ('I', 'C', 'M', 'T'))/* Weird WAVPACK marker which can show up at the start of the DATA section. */#define wvpk_MARKER (MAKE_MARKER ('w', 'v', 'p', 'k'))#define OggS_MARKER (MAKE_MARKER ('O', 'g', 'g', 'S'))enum{	HAVE_RIFF	= 0x01,	HAVE_WAVE	= 0x02,	HAVE_fmt	= 0x04,	HAVE_fact	= 0x08,	HAVE_PEAK	= 0x10,	HAVE_data	= 0x20,	HAVE_other	= 0x80000000} ;/*  known WAVEFORMATEXTENSIBLE GUIDS  */static const EXT_SUBFORMAT MSGUID_SUBTYPE_PCM ={	0x00000001, 0x0000, 0x0010, {	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }} ;static const EXT_SUBFORMAT MSGUID_SUBTYPE_MS_ADPCM ={	0x00000002, 0x0000, 0x0010, {	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }} ;static const EXT_SUBFORMAT MSGUID_SUBTYPE_IEEE_FLOAT ={	0x00000003, 0x0000, 0x0010, {	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }} ;static const EXT_SUBFORMAT MSGUID_SUBTYPE_ALAW ={	0x00000006, 0x0000, 0x0010, {	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }} ;static const EXT_SUBFORMAT MSGUID_SUBTYPE_MULAW ={	0x00000007, 0x0000, 0x0010, {	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }} ;#if 0/* maybe interesting one day to read the following through sf_read_raw *//* http://www.bath.ac.uk/~masrwd/pvocex/pvocex.html */static const EXT_SUBFORMAT MSGUID_SUBTYPE_PVOCEX ={	0x8312B9C2, 0x2E6E, 0x11d4, {	0xA8, 0x24, 0xDE, 0x5B, 0x96, 0xC3, 0xAB, 0x21 }} ;#endif/*------------------------------------------------------------------------------** Private static functions.*/static int	wav_read_header	 (SF_PRIVATE *psf, int *blockalign, int *framesperblock) ;static int	wav_write_header (SF_PRIVATE *psf, int calc_length) ;static void wavex_write_guid (SF_PRIVATE *psf, const EXT_SUBFORMAT * subformat) ;static int	wavex_write_header (SF_PRIVATE *psf, int calc_length) ;static int	wav_write_tailer (SF_PRIVATE *psf) ;static void wav_write_strings (SF_PRIVATE *psf, int location) ;static int	wav_command (SF_PRIVATE *psf, int command, void *data, int datasize) ;static int	wav_close (SF_PRIVATE *psf) ;static int 	wav_subchunk_parse	 (SF_PRIVATE *psf, int chunk) ;static int	wav_read_smpl_chunk (SF_PRIVATE *psf, unsigned int chunklen) ;static int	wav_read_acid_chunk (SF_PRIVATE *psf, unsigned int chunklen) ;static int wavex_write_guid_equal (const EXT_SUBFORMAT * first, const EXT_SUBFORMAT * second) ;/*------------------------------------------------------------------------------** Public function.*/intwav_open	 (SF_PRIVATE *psf){	int	format, subformat, error, blockalign = 0, framesperblock = 0 ;	if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))	{	if ((error = wav_read_header (psf, &blockalign, &framesperblock)))			return error ;		} ;	subformat = psf->sf.format & SF_FORMAT_SUBMASK ;	if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)	{	if (psf->is_pipe)			return SFE_NO_PIPE_WRITE ;		format = psf->sf.format & SF_FORMAT_TYPEMASK ;		if (format != SF_FORMAT_WAV && format != SF_FORMAT_WAVEX)			return	SFE_BAD_OPEN_FORMAT ;		psf->endian = SF_ENDIAN_LITTLE ;	/* All WAV files are little endian. */		psf->blockwidth = psf->bytewidth * psf->sf.channels ;		if (psf->mode != SFM_RDWR || psf->filelength < 44)		{	psf->filelength = 0 ;			psf->datalength = 0 ;			psf->dataoffset = 0 ;			psf->sf.frames = 0 ;			} ;		if (subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM)		{	blockalign = wav_w64_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ;			framesperblock = -1 ; /* Corrected later. */			} ;		psf->str_flags = SF_STR_ALLOW_START | SF_STR_ALLOW_END ;		/* By default, add the peak chunk to floating point files. Default behaviour		** can be switched off using sf_command (SFC_SET_PEAK_CHUNK, SF_FALSE).		*/		if (psf->mode == SFM_WRITE && (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE))		{	psf->pchunk = calloc (1, sizeof (PEAK_CHUNK) * psf->sf.channels * sizeof (PEAK_POS)) ;			if (psf->pchunk == NULL)				return SFE_MALLOC_FAILED ;			psf->has_peak = SF_TRUE ;			psf->peak_loc = SF_PEAK_START ;			} ;		psf->write_header = (format == SF_FORMAT_WAV) ? wav_write_header : wavex_write_header ;		} ;	psf->close = wav_close ;	psf->command = wav_command ;	switch (subformat)	{	case SF_FORMAT_PCM_U8 :		case SF_FORMAT_PCM_16 :		case SF_FORMAT_PCM_24 :		case SF_FORMAT_PCM_32 :					error = pcm_init (psf) ;					break ;		case SF_FORMAT_ULAW :					error = ulaw_init (psf) ;					break ;		case SF_FORMAT_ALAW :					error = alaw_init (psf) ;					break ;		/* Lite remove start */		case SF_FORMAT_FLOAT :					error = float32_init (psf) ;					break ;		case SF_FORMAT_DOUBLE :					error = double64_init (psf) ;					break ;		case SF_FORMAT_IMA_ADPCM :					error = wav_w64_ima_init (psf, blockalign, framesperblock) ;					break ;		case SF_FORMAT_MS_ADPCM :					error = wav_w64_msadpcm_init (psf, blockalign, framesperblock) ;					break ;		/* Lite remove end */		case SF_FORMAT_GSM610 :					error = gsm610_init (psf) ;					break ;		default : 	return SFE_UNIMPLEMENTED ;		} ;	if (psf->mode == SFM_WRITE || (psf->mode == SFM_RDWR && psf->filelength == 0))		return psf->write_header (psf, SF_FALSE) ;	return error ;} /* wav_open *//*=========================================================================** Private functions.*/static intwav_read_header	 (SF_PRIVATE *psf, int *blockalign, int *framesperblock){	WAV_FMT		wav_fmt ;	FACT_CHUNK	fact_chunk ;	int			dword, marker, RIFFsize, done = 0 ;	int			parsestage = 0, error, format = 0 ;	char		*cptr ;	/* Set position to start of file to begin reading header. */	psf_binheader_readf (psf, "p", 0) ;	while (! done)	{	psf_binheader_readf (psf, "m", &marker) ;		switch (marker)		{	case RIFF_MARKER :					if (parsestage)						return SFE_WAV_NO_RIFF ;					parsestage |= HAVE_RIFF ;					psf_binheader_readf (psf, "e4", &RIFFsize) ;					if (psf->fileoffset > 0 && psf->filelength > RIFFsize + 8)					{	/* Set file length. */						psf->filelength = RIFFsize + 8 ;						psf_log_printf (psf, "RIFF : %u\n", RIFFsize) ;						}					else if (psf->filelength < RIFFsize + 2 * SIGNED_SIZEOF (dword))					{	psf_log_printf (psf, "RIFF : %u (should be %D)\n", RIFFsize, psf->filelength - 2 * SIGNED_SIZEOF (dword)) ;						RIFFsize = dword ;						}					else						psf_log_printf (psf, "RIFF : %u\n", RIFFsize) ;					break ;			case WAVE_MARKER :					if ((parsestage & HAVE_RIFF) != HAVE_RIFF)						return SFE_WAV_NO_WAVE ;					parsestage |= HAVE_WAVE ;					psf_log_printf (psf, "WAVE\n") ;					break ;			case fmt_MARKER :					if ((parsestage & (HAVE_RIFF | HAVE_WAVE)) != (HAVE_RIFF | HAVE_WAVE))						return SFE_WAV_NO_FMT ;					/* If this file has a SECOND fmt chunk, I don't want to know about it. */					if (parsestage & HAVE_fmt)						break ;					parsestage |= HAVE_fmt ;					psf_binheader_readf (psf, "e4", &dword) ;					psf_log_printf (psf, "fmt  : %d\n", dword) ;					if ((error = wav_w64_read_fmt_chunk (psf, &wav_fmt, dword)))						return error ;					format = wav_fmt.format ;					break ;			case data_MARKER :					if ((parsestage & (HAVE_RIFF | HAVE_WAVE | HAVE_fmt)) != (HAVE_RIFF | HAVE_WAVE | HAVE_fmt))						return SFE_WAV_NO_DATA ;					if (psf->mode == SFM_RDWR && (parsestage & HAVE_other) != 0)						return SFE_RDWR_BAD_HEADER ;					parsestage |= HAVE_data ;					psf_binheader_readf (psf, "e4", &dword) ;					psf->datalength = dword ;					psf->dataoffset = psf_ftell (psf) ;					if (dword == 0 && RIFFsize == 8 && psf->filelength > 44)					{	psf_log_printf (psf, "*** Looks like a WAV file which wasn't closed properly. Fixing it.\n") ;						psf->datalength = dword = psf->filelength - psf->dataoffset ;						} ;					if (psf->datalength > psf->filelength - psf->dataoffset)					{	psf_log_printf (psf, "data : %D (should be %D)\n", psf->datalength, psf->filelength - psf->dataoffset) ;						psf->datalength = psf->filelength - psf->dataoffset ;						}					else						psf_log_printf (psf, "data : %D\n", psf->datalength) ;					/* Only set dataend if there really is data at the end. */					if (psf->datalength + psf->dataoffset < psf->filelength)						psf->dataend = psf->datalength + psf->dataoffset ;					if (format == WAVE_FORMAT_MS_ADPCM && psf->datalength % 2)					{	psf->datalength ++ ;						psf_log_printf (psf, "*** Data length odd. Increasing it by 1.\n") ;						} ;					if (! psf->sf.seekable)						break ;					/* Seek past data and continue reading header. */					psf_fseek (psf, psf->datalength, SEEK_CUR) ;					dword = psf_ftell (psf) ;					if (dword != (sf_count_t) (psf->dataoffset + psf->datalength))						psf_log_printf (psf, "*** psf_fseek past end error ***\n", dword, psf->dataoffset + psf->datalength) ;					break ;			case fact_MARKER :					if ((parsestage & (HAVE_RIFF | HAVE_WAVE)) != (HAVE_RIFF | HAVE_WAVE))						return SFE_WAV_BAD_FACT ;					parsestage |= HAVE_fact ;					if ((parsestage & HAVE_fmt) != HAVE_fmt)						psf_log_printf (psf, "*** Should have 'fmt ' chunk before 'fact'\n") ;					psf_binheader_readf (psf, "e44", &dword, & (fact_chunk.frames)) ;					if (dword > SIGNED_SIZEOF (fact_chunk))						psf_binheader_readf (psf, "j", (int) (dword - SIGNED_SIZEOF (fact_chunk))) ;					if (dword)						psf_log_printf (psf, "%M : %d\n", marker, dword) ;					else						psf_log_printf (psf, "%M : %d (should not be zero)\n", marker, dword) ;					psf_log_printf (psf, "  frames  : %d\n", fact_chunk.frames) ;					break ;			case PEAK_MARKER :					if ((parsestage & (HAVE_RIFF | HAVE_WAVE | HAVE_fmt)) != (HAVE_RIFF | HAVE_WAVE | HAVE_fmt))						return SFE_WAV_PEAK_B4_FMT ;					parsestage |= HAVE_PEAK ;					psf_binheader_readf (psf, "e4", &dword) ;					psf_log_printf (psf, "%M : %d\n", marker, dword) ;					if (dword != SIGNED_SIZEOF (PEAK_CHUNK) + psf->sf.channels * SIGNED_SIZEOF (PEAK_POS))					{	psf_binheader_readf (psf, "j", dword) ;						psf_log_printf (psf, "*** File PEAK chunk size doesn't fit with number of channels.\n") ;						return SFE_WAV_BAD_PEAK ;						} ;					psf->pchunk = calloc (1, sizeof (PEAK_CHUNK) * psf->sf.channels * sizeof (PEAK_POS)) ;					if (psf->pchunk == NULL)						return SFE_MALLOC_FAILED ;					/* read in rest of PEAK chunk. */					psf_binheader_readf (psf, "e44", & (psf->pchunk->version), & (psf->pchunk->timestamp)) ;					if (psf->pchunk->version != 1)						psf_log_printf (psf, "  version    : %d *** (should be version 1)\n", psf->pchunk->version) ;					else						psf_log_printf (psf, "  version    : %d\n", psf->pchunk->version) ;					psf_log_printf (psf, "  time stamp : %d\n", psf->pchunk->timestamp) ;					psf_log_printf (psf, "    Ch   Position       Value\n") ;					cptr = psf->u.cbuf ;					for (dword = 0 ; dword < psf->sf.channels ; dword++)					{	psf_binheader_readf (psf, "ef4", & (psf->pchunk->peaks [dword].value),														& (psf->pchunk->peaks [dword].position)) ;						LSF_SNPRINTF (cptr, sizeof (psf->u.cbuf), "    %2d   %-12d   %g\n",								dword, psf->pchunk->peaks [dword].position, psf->pchunk->peaks [dword].value) ;						cptr [sizeof (psf->u.cbuf) - 1] = 0 ;						psf_log_printf (psf, cptr) ;						} ;					psf->has_peak = SF_TRUE ; /* Found PEAK chunk. */					psf->peak_loc = ((parsestage & HAVE_data) == 0) ? SF_PEAK_START : SF_PEAK_END ;					break ;			case cue_MARKER :					parsestage |= HAVE_other ;					{	int bytesread, cue_count ;						int id, position, chunk_id, chunk_start, block_start, offset ;						bytesread = psf_binheader_readf (psf, "e44", &dword, &cue_count) ;						bytesread -= 4 ; /* Remove bytes for first dword. */						psf_log_printf (psf, "%M : %u\n  Count : %d\n", marker, dword, cue_count) ;						while (cue_count)						{	bytesread += psf_binheader_readf (psf, "e444444", &id, &position,									&chunk_id, &chunk_start, &block_start, &offset) ;							psf_log_printf (psf, "   Cue ID : %2d"												 "  Pos : %5u  Chunk : %M"												 "  Chk Start : %d  Blk Start : %d"												 "  Offset : %5d\n",									id, position, chunk_id, chunk_start, block_start, offset) ;							cue_count -- ;							} ;						if (bytesread != dword)						{	psf_log_printf (psf, "**** Chunk size weirdness (%d != %d)\n", dword, bytesread) ;							psf_binheader_readf (psf, "j", dword - bytesread) ;							} ;						} ;					break ;			case smpl_MARKER :					parsestage |= HAVE_other ;					psf_binheader_readf (psf, "e4", &dword) ;					psf_log_printf (psf, "smpl : %u\n", dword) ;					if ((error = wav_read_smpl_chunk (psf, dword)))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -