1 /* @(#)wav.c	1.14 10/01/31 Copyright 1998,1999 Heiko Eissfeldt, Copyright 2006-2010 J. Schilling */
2 #include "config.h"
3 #ifndef lint
4 static	UConst char sccsid[] =
5 "@(#)wav.c	1.14 10/01/31 Copyright 1998,1999 Heiko Eissfeldt, Copyright 2006-2010 J. Schilling";
6 
7 #endif
8 /*
9  * Copyright (C) by Heiko Eissfeldt
10  * Copyright (c) 2006-2010 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include "config.h"
27 #include <schily/stdio.h>
28 #include <schily/standard.h>
29 #include <schily/unistd.h>
30 #include "mytype.h"
31 #include "byteorder.h"
32 #include "sndfile.h"
33 #include "global.h"
34 
35 /*
36  * ---------------------------------------------------------------------
37  *  definitions for RIFF-output (from windows MMSYSTEM)
38  * ---------------------------------------------------------------------
39  */
40 
41 typedef unsigned int FOURCC;	/* a four character code */
42 
43 typedef struct CHUNKHDR {
44 	FOURCC		ckid;		/* chunk ID */
45 	unsigned int	dwSize; 	/* chunk size */
46 } CHUNKHDR;
47 
48 /*
49  * flags for 'wFormatTag' field of WAVEFORMAT
50  */
51 #define	WAVE_FORMAT_PCM	1
52 
53 /*
54  * specific waveform format structure for PCM data
55  */
56 typedef struct pcmwaveformat_tag {
57 	unsigned short	wFormatTag;	/* format type */
58 	unsigned short	nChannels;	/* number of channels (i.e. mono, stereo, etc.) */
59 	unsigned int	nSamplesPerSec;	/* sample rate */
60 	unsigned int	nAvgBytesPerSec; /* for buffer size estimate */
61 	unsigned short	nBlockAlign;	/* block size of data */
62 	unsigned short	wBitsPerSample;
63 } PCMWAVEFORMAT;
64 typedef PCMWAVEFORMAT *PPCMWAVEFORMAT;
65 
66 
67 /*
68  * MMIO macros
69  */
70 #define	mmioFOURCC(ch0, ch1, ch2, ch3) \
71 	((unsigned int)(unsigned char)(ch0) | \
72 	((unsigned int)(unsigned char)(ch1) << 8) | \
73 	((unsigned int)(unsigned char)(ch2) << 16) | \
74 	((unsigned int)(unsigned char)(ch3) << 24))
75 
76 #define	FOURCC_RIFF	mmioFOURCC('R', 'I', 'F', 'F')
77 #define	FOURCC_LIST	mmioFOURCC('L', 'I', 'S', 'T')
78 #define	FOURCC_WAVE	mmioFOURCC('W', 'A', 'V', 'E')
79 #define	FOURCC_FMT	mmioFOURCC('f', 'm', 't', ' ')
80 #define	FOURCC_DATA	mmioFOURCC('d', 'a', 't', 'a')
81 
82 
83 /*
84  * simplified Header for standard WAV files
85  */
86 typedef struct WAVEHDR {
87 	CHUNKHDR	chkRiff;
88 	FOURCC		fccWave;
89 	CHUNKHDR	chkFmt;
90 	unsigned short	wFormatTag;	/* format type */
91 	unsigned short	nChannels;	/* number of channels (i.e. mono, stereo, etc.) */
92 	unsigned int	nSamplesPerSec;	/* sample rate */
93 	unsigned int	nAvgBytesPerSec; /* for buffer estimation */
94 	unsigned short	nBlockAlign;	/* block size of data */
95 	unsigned short	wBitsPerSample;
96 	CHUNKHDR	chkData;
97 } WAVEHDR;
98 
99 #define	IS_STD_WAV_HEADER(waveHdr)	\
100 	(waveHdr.chkRiff.ckid == FOURCC_RIFF && \
101 	waveHdr.fccWave == FOURCC_WAVE && \
102 	waveHdr.chkFmt.ckid == FOURCC_FMT && \
103 	waveHdr.chkData.ckid == FOURCC_DATA && \
104 	waveHdr.wFormatTag == WAVE_FORMAT_PCM)
105 
106 LOCAL WAVEHDR	waveHdr;
107 
108 LOCAL int	_InitSound	__PR((int audio, long channels, Ulong rate,
109 					long nBitsPerSample,
110 					Ulong expected_bytes));
111 LOCAL int	_ExitSound	__PR((int audio, Ulong nBytesDone));
112 LOCAL Ulong	_GetHdrSize	__PR((void));
113 LOCAL Ulong	InSizeToOutSize	__PR((Ulong BytesToDo));
114 
115 
116 LOCAL int
_InitSound(audio,channels,rate,nBitsPerSample,expected_bytes)117 _InitSound(audio, channels, rate, nBitsPerSample, expected_bytes)
118 	int	audio;
119 	long	channels;
120 	Ulong	rate;
121 	long	nBitsPerSample;
122 	Ulong	expected_bytes;
123 {
124 	Ulong	nBlockAlign = channels * ((nBitsPerSample + 7) / 8);
125 	Ulong	nAvgBytesPerSec = nBlockAlign * rate;
126 	Ulong	temp = expected_bytes +
127 				sizeof (WAVEHDR) - sizeof (CHUNKHDR);
128 
129 	waveHdr.chkRiff.ckid	= cpu_to_le32(FOURCC_RIFF);
130 	waveHdr.fccWave		= cpu_to_le32(FOURCC_WAVE);
131 	waveHdr.chkFmt.ckid	= cpu_to_le32(FOURCC_FMT);
132 	waveHdr.chkFmt.dwSize	= cpu_to_le32(sizeof (PCMWAVEFORMAT));
133 	waveHdr.wFormatTag	= cpu_to_le16(WAVE_FORMAT_PCM);
134 	waveHdr.nChannels	= cpu_to_le16(channels);
135 	waveHdr.nSamplesPerSec	= cpu_to_le32(rate);
136 	waveHdr.nBlockAlign	= cpu_to_le16(nBlockAlign);
137 	waveHdr.nAvgBytesPerSec	= cpu_to_le32(nAvgBytesPerSec);
138 	waveHdr.wBitsPerSample	= cpu_to_le16(nBitsPerSample);
139 	waveHdr.chkData.ckid	= cpu_to_le32(FOURCC_DATA);
140 	waveHdr.chkRiff.dwSize	= cpu_to_le32(temp);
141 	waveHdr.chkData.dwSize	= cpu_to_le32(expected_bytes);
142 
143 	global.md5offset = sizeof (waveHdr);
144 
145 	return (write(audio, &waveHdr, sizeof (waveHdr)));
146 }
147 
148 LOCAL int
_ExitSound(audio,nBytesDone)149 _ExitSound(audio, nBytesDone)
150 	int	audio;
151 	Ulong	nBytesDone;
152 {
153 	Ulong	temp = nBytesDone +
154 				sizeof (WAVEHDR) - sizeof (CHUNKHDR);
155 
156 	waveHdr.chkRiff.dwSize = cpu_to_le32(temp);
157 	waveHdr.chkData.dwSize = cpu_to_le32(nBytesDone);
158 
159 	/*
160 	 * goto beginning
161 	 */
162 	if (lseek(audio, 0L, SEEK_SET) == -1) {
163 		return (0);
164 	}
165 	return (write(audio, &waveHdr, sizeof (waveHdr)));
166 }
167 
168 LOCAL Ulong
_GetHdrSize()169 _GetHdrSize()
170 {
171 	return (sizeof (waveHdr));
172 }
173 
174 LOCAL Ulong
InSizeToOutSize(BytesToDo)175 InSizeToOutSize(BytesToDo)
176 	Ulong	BytesToDo;
177 {
178 	return (BytesToDo);
179 }
180 
181 struct soundfile wavsound =
182 {
183 	_InitSound,		/* init header method */
184 	_ExitSound,		/* exit header method */
185 	_GetHdrSize,		/* report header size method */
186 	(int (*) __PR((int audio,
187 		Uchar *buf,
188 		size_t BytesToDo))) write, /* get sound samples out */
189 	InSizeToOutSize,	/* compressed? output file size */
190 	0,			/* needs big endian samples */
191 	"WAVE"
192 };
193