1 /* @(#)aiff.c	1.15 16/02/14 Copyright 1998,1999 Heiko Eissfeldt, Copyright 2006-2010 J. Schilling */
2 #include "config.h"
3 #ifndef lint
4 static	UConst char sccsid[] =
5 "@(#)aiff.c	1.15 16/02/14 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  * definitions for aiff pcm output
13  */
14 /*
15  * The contents of this file are subject to the terms of the
16  * Common Development and Distribution License, Version 1.0 only
17  * (the "License").  You may not use this file except in compliance
18  * with the License.
19  *
20  * See the file CDDL.Schily.txt in this distribution for details.
21  * A copy of the CDDL is also available via the Internet at
22  * http://www.opensource.org/licenses/cddl1.txt
23  *
24  * When distributing Covered Code, include this CDDL HEADER in each
25  * file and include the License file CDDL.Schily.txt from this distribution.
26  */
27 
28 #include "config.h"
29 #include <schily/stdio.h>
30 #include <schily/unistd.h>
31 #include <schily/string.h>
32 #include <schily/standard.h>
33 #include <schily/schily.h>
34 #include "mytype.h"
35 #include "byteorder.h"
36 #include "sndfile.h"
37 #include "global.h"
38 
39 typedef UINT4 FOURCC;    /* a four character code */
40 typedef struct CHUNKHDR {
41 	FOURCC	ckid;	/* chunk ID */
42 	UINT4	dwSize;	/* chunk size */
43 } CHUNKHDR;
44 
45 #define	mmioFOURCC(ch0, ch1, ch2, ch3) \
46 		((UINT4)(unsigned char)(ch3) | \
47 		((UINT4)(unsigned char)(ch2) << 8) | \
48 		((UINT4)(unsigned char)(ch1) << 16) | \
49 		((UINT4)(unsigned char)(ch0) << 24))
50 
51 #define	FOURCC_FORM	mmioFOURCC('F', 'O', 'R', 'M')
52 #define	FOURCC_AIFF	mmioFOURCC('A', 'I', 'F', 'F')
53 #define	FOURCC_COMM	mmioFOURCC('C', 'O', 'M', 'M')
54 #define	FOURCC_SSND	mmioFOURCC('S', 'S', 'N', 'D')
55 
56 typedef struct AIFFHDR {
57 	CHUNKHDR	formChk;
58 	FOURCC		formType;
59 
60 	CHUNKHDR	commChk;	/* Common chunk */
61 	/*
62 	 * from now on, alignment prevents us from using the original types :-(
63 	 */
64 	unsigned char	numChannels[2];		/* Audio Channels */
65 	unsigned char	numSampleFrames[4];	/* # of samples */
66 	unsigned char	samplesize[2];		/* bits per sample */
67 	unsigned char	sample_rate[10];	/* samplerate in extd. float */
68 
69 	unsigned char	ssndChkid[4];	/* Sound data chunk */
70 	unsigned char	dwSize[4];	/* size of chunk */
71 	unsigned char	offset[4];	/* start of 1st sample */
72 	unsigned char	blocksize[4];	/* aligned sound data block size */
73 } AIFFHDR;
74 
75 LOCAL AIFFHDR AiffHdr;
76 
77 LOCAL int	Format_samplerate	__PR((Ulong rate,
78 						Uchar the_rate[10]));
79 LOCAL int	InitSound	__PR((int audio, long channels,
80 					Ulong rate,
81 					long nBitsPerSample,
82 					Ulong expected_bytes));
83 LOCAL int	ExitSound	__PR((int audio, Ulong nBytesDone));
84 LOCAL Ulong	GetHdrSize	__PR((void));
85 LOCAL Ulong	InSizeToOutSize	__PR((Ulong BytesToDo));
86 
87 
88 /*
89  * format the sample rate into an
90  * bigendian 10-byte IEEE-754 floating point number
91  */
92 LOCAL int
Format_samplerate(rate,the_rate)93 Format_samplerate(rate, the_rate)
94 	Ulong	rate;
95 	Uchar	the_rate[10];
96 {
97 	int	i;
98 
99 	/*
100 	 * normalize rate
101 	 */
102 	for (i = 0; (rate & 0xffff) != 0; rate <<= 1, i++) {
103 		if ((rate & 0x8000) != 0) {
104 			break;
105 		}
106 	}
107 
108 	/*
109 	 * set exponent and sign
110 	 */
111 	the_rate[1] = 14-i;
112 	the_rate[0] = 0x40;	/* LSB = sign */
113 
114 	/*
115 	 * 16-bit part of mantisse for sample rate
116 	 */
117 	the_rate[3] = rate & 0xff;
118 	the_rate[2] = (rate >> 8) & 0xff;
119 
120 	/*
121 	 * initialize lower digits of mantisse
122 	 */
123 	the_rate[4] = the_rate[5] = the_rate[6] =
124 	the_rate[7] = the_rate[8] = the_rate[9] = 0;
125 
126 	return (0);
127 }
128 
129 LOCAL int
InitSound(audio,channels,rate,nBitsPerSample,expected_bytes)130 InitSound(audio, channels, rate, nBitsPerSample, expected_bytes)
131 	int	audio;
132 	long	channels;
133 	Ulong	rate;
134 	long	nBitsPerSample;
135 	Ulong	expected_bytes;
136 {
137 	UINT4	tmp;
138 
139 	fillbytes(&AiffHdr, sizeof (AiffHdr), '\0');
140 	AiffHdr.formChk.ckid  = cpu_to_be32(FOURCC_FORM);
141 	AiffHdr.formChk.dwSize = cpu_to_be32(expected_bytes +
142 					offsetof(AIFFHDR, blocksize) +
143 					sizeof (AiffHdr.blocksize)
144 			- offsetof(AIFFHDR, formType));
145 	AiffHdr.formType	= cpu_to_be32(FOURCC_AIFF);
146 
147 	AiffHdr.commChk.ckid	= cpu_to_be32(FOURCC_COMM);
148 	AiffHdr.commChk.dwSize	= cpu_to_be32(offsetof(AIFFHDR, ssndChkid)
149 					- offsetof(AIFFHDR, numChannels));
150 
151 	AiffHdr.numChannels[1]	   = channels;
152 	tmp = cpu_to_be32(expected_bytes/(channels * (nBitsPerSample/8)));
153 	AiffHdr.numSampleFrames[0] = tmp >> 24;
154 	AiffHdr.numSampleFrames[1] = tmp >> 16;
155 	AiffHdr.numSampleFrames[2] = tmp >> 8;
156 	AiffHdr.numSampleFrames[3] = tmp >> 0;
157 	AiffHdr.samplesize[1] = nBitsPerSample;
158 	Format_samplerate(rate, AiffHdr.sample_rate);
159 
160 	memcpy(AiffHdr.ssndChkid, "SSND", 4);
161 	tmp = cpu_to_be32(expected_bytes + offsetof(AIFFHDR, blocksize) +
162 		sizeof (AiffHdr.blocksize) - offsetof(AIFFHDR, offset));
163 	AiffHdr.dwSize[0] = tmp >> 24;
164 	AiffHdr.dwSize[1] = tmp >> 16;
165 	AiffHdr.dwSize[2] = tmp >> 8;
166 	AiffHdr.dwSize[3] = tmp >> 0;
167 
168 	global.md5offset = sizeof (AiffHdr);
169 
170 	return (write(audio, &AiffHdr, sizeof (AiffHdr)));
171 }
172 
173 LOCAL int
ExitSound(audio,nBytesDone)174 ExitSound(audio, nBytesDone)
175 	int	audio;
176 	Ulong	nBytesDone;
177 {
178 	UINT4	tmp;
179 
180 	AiffHdr.formChk.dwSize = cpu_to_be32(nBytesDone + sizeof (AIFFHDR)
181 					- offsetof(AIFFHDR, commChk));
182 	tmp = cpu_to_be32(nBytesDone/(
183 		AiffHdr.numChannels[1] * AiffHdr.samplesize[1]/ULONG_C(8)));
184 	AiffHdr.numSampleFrames[0] = tmp >> 24;
185 	AiffHdr.numSampleFrames[1] = tmp >> 16;
186 	AiffHdr.numSampleFrames[2] = tmp >> 8;
187 	AiffHdr.numSampleFrames[3] = tmp >> 0;
188 
189 	/*
190 	 * If an odd number of bytes has been written,
191 	 * extend the chunk with one dummy byte.
192 	 * This is a requirement for AIFF.
193 	 */
194 	if ((nBytesDone & 1) && (lseek(audio, 1L, SEEK_CUR) == -1)) {
195 		return (0);
196 	}
197 
198 	/*
199 	 * goto beginning
200 	 */
201 	if (lseek(audio, 0L, SEEK_SET) == -1) {
202 		return (0);
203 	}
204 	return (write(audio, &AiffHdr, sizeof (AiffHdr)));
205 }
206 
207 LOCAL Ulong
GetHdrSize()208 GetHdrSize()
209 {
210 	return (sizeof (AiffHdr));
211 }
212 
213 LOCAL Ulong
InSizeToOutSize(BytesToDo)214 InSizeToOutSize(BytesToDo)
215 	Ulong	BytesToDo;
216 {
217 	return (BytesToDo);
218 }
219 
220 struct soundfile aiffsound =
221 {
222 	InitSound,		/* init header method */
223 	ExitSound,		/* exit header method */
224 	GetHdrSize,		/* report header size method */
225 	(int (*) __PR((int audio,
226 		Uchar *buf,
227 		size_t BytesToDo))) write, /* get sound samples out */
228 	InSizeToOutSize,	/* compressed? output file size */
229 	1,			/* needs big endian samples */
230 	"AIFF"
231 };
232