1 /* @(#)aifc.c	1.16 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 "@(#)aifc.c	1.16 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 aifc 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/standard.h>
31 #include <schily/unistd.h>
32 #include <schily/string.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_AIFC	mmioFOURCC('A', 'I', 'F', 'C')
53 #define	FOURCC_FVER	mmioFOURCC('F', 'V', 'E', 'R')
54 #define	FOURCC_COMM	mmioFOURCC('C', 'O', 'M', 'M')
55 #define	FOURCC_NONE	mmioFOURCC('N', 'O', 'N', 'E')
56 #define	FOURCC_SSND	mmioFOURCC('S', 'S', 'N', 'D')
57 
58 #define	NO_COMPRESSION	"not compressed"
59 
60 /*
61  * brain dead construction from apple involving bigendian 80-bit doubles.
62  * Definitely designed not to be portable. Alignment is a nightmare too.
63  */
64 typedef struct AIFCHDR {
65 	CHUNKHDR	formChk;
66 	FOURCC		formType;
67 
68 	CHUNKHDR	fverChk;	/* Version chunk */
69 	UINT4		timestamp;	/* timestamp identifies version */
70 
71 	CHUNKHDR	commChk;	/* Common chunk */
72 	/*
73 	 * from now on, alignment prevents us from using the original types :-(
74 	 */
75 	unsigned char	numChannels[2];		/* Audio Channels */
76 	unsigned char	numSampleFrames[4];	/* # of samples */
77 	unsigned char	samplesize[2];		/* bits per sample */
78 	unsigned char	sample_rate[10];	/* samplerate in extd. float */
79 	unsigned char	compressionType[4];	/* AIFC extension */
80 	unsigned char	compressionNameLen;	/* AIFC extension */
81 	char		compressionName[sizeof (NO_COMPRESSION)]; /* AIFC e. */
82 
83 	unsigned char	ssndChkid[4];	/* Sound data chunk */
84 	unsigned char	dwSize[4];	/* size of chunk */
85 	unsigned char	offset[4];	/* start of 1st sample */
86 	unsigned char	blocksize[4];	/* aligned sound data block size */
87 
88 } AIFCHDR;
89 
90 LOCAL	AIFCHDR	AifcHdr;
91 
92 LOCAL int	Format_samplerate __PR((Ulong rate, Uchar the_rate[10]));
93 LOCAL int	InitSound	__PR((int audio, long channels, Ulong rate,
94 					long nBitsPerSample,
95 					Ulong expected_bytes));
96 LOCAL int	ExitSound	__PR((int audio, Ulong nBytesDone));
97 LOCAL Ulong	GetHdrSize	__PR((void));
98 LOCAL Ulong	InSizeToOutSize	__PR((Ulong BytesToDo));
99 
100 
101 /*
102  * format the sample rate into an
103  * bigendian 10-byte IEEE-754 floating point number
104  */
105 LOCAL int
Format_samplerate(rate,the_rate)106 Format_samplerate(rate, the_rate)
107 	Ulong	rate;
108 	Uchar	the_rate[10];
109 {
110 	int	i;
111 
112 	/*
113 	 * normalize rate
114 	 */
115 	for (i = 0; (rate & 0xffff) != 0; rate <<= 1, i++) {
116 		if ((rate & 0x8000) != 0) {
117 			break;
118 		}
119 	}
120 
121 	/*
122 	 * set exponent and sign
123 	 */
124 	the_rate[1] = 14-i;
125 	the_rate[0] = 0x40;		/* LSB = sign */
126 
127 	/*
128 	 * 16-bit part of mantisse for sample rate
129 	 */
130 	the_rate[3] = rate & 0xff;
131 	the_rate[2] = (rate >> 8) & 0xff;
132 
133 	/*
134 	 * initialize lower digits of mantisse
135 	 */
136 	the_rate[4] = the_rate[5] = the_rate[6] =
137 	the_rate[7] = the_rate[8] = the_rate[9] = 0;
138 
139 	return (0);
140 }
141 
142 LOCAL int
InitSound(audio,channels,rate,nBitsPerSample,expected_bytes)143 InitSound(audio, channels, rate, nBitsPerSample, expected_bytes)
144 	int	audio;
145 	long	channels;
146 	Ulong	rate;
147 	long	nBitsPerSample;
148 	Ulong	expected_bytes;
149 {
150 	UINT4	tmp;
151 
152 	fillbytes(&AifcHdr, sizeof (AifcHdr), '\0');
153 	AifcHdr.formChk.ckid	= cpu_to_be32(FOURCC_FORM);
154 	AifcHdr.formChk.dwSize	= cpu_to_be32(expected_bytes +
155 					offsetof(AIFCHDR, blocksize) +
156 					sizeof (AifcHdr.blocksize) -
157 					offsetof(AIFCHDR, commChk));
158 	AifcHdr.formType	= cpu_to_be32(FOURCC_AIFC);
159 
160 	AifcHdr.fverChk.ckid	= cpu_to_be32(FOURCC_FVER);
161 	AifcHdr.fverChk.dwSize	= cpu_to_be32(offsetof(AIFCHDR, commChk)
162 					- offsetof(AIFCHDR, timestamp));
163 
164 	AifcHdr.compressionType[0] = 'N';
165 	AifcHdr.compressionType[1] = 'O';
166 	AifcHdr.compressionType[2] = 'N';
167 	AifcHdr.compressionType[3] = 'E';
168 	AifcHdr.compressionNameLen = sizeof (NO_COMPRESSION)-1;
169 	strcpy(AifcHdr.compressionName, NO_COMPRESSION);
170 	/*
171 	 * AIFC Version 1
172 	 */
173 	AifcHdr.timestamp	= cpu_to_be32(UINT4_C(0xA2805140));
174 
175 	AifcHdr.commChk.ckid	= cpu_to_be32(FOURCC_COMM);
176 	AifcHdr.commChk.dwSize	= cpu_to_be32(offsetof(AIFCHDR, ssndChkid)
177 					- offsetof(AIFCHDR, numChannels));
178 
179 	AifcHdr.numChannels[1] = channels;
180 
181 	tmp = cpu_to_be32(expected_bytes/(channels * (nBitsPerSample/8)));
182 	AifcHdr.numSampleFrames[0] = tmp >> 24;
183 	AifcHdr.numSampleFrames[1] = tmp >> 16;
184 	AifcHdr.numSampleFrames[2] = tmp >> 8;
185 	AifcHdr.numSampleFrames[3] = tmp >> 0;
186 	AifcHdr.samplesize[1]	= nBitsPerSample;
187 	Format_samplerate(rate, AifcHdr.sample_rate);
188 
189 	memcpy(AifcHdr.ssndChkid, "SSND", 4);
190 	tmp = cpu_to_be32(expected_bytes + offsetof(AIFCHDR, blocksize) +
191 		sizeof (AifcHdr.blocksize) - offsetof(AIFCHDR, offset));
192 	AifcHdr.dwSize[0] = tmp >> 24;
193 	AifcHdr.dwSize[1] = tmp >> 16;
194 	AifcHdr.dwSize[2] = tmp >> 8;
195 	AifcHdr.dwSize[3] = tmp >> 0;
196 
197 	global.md5offset = sizeof (AifcHdr);
198 
199 	return (write(audio, &AifcHdr, sizeof (AifcHdr)));
200 }
201 
202 LOCAL int
ExitSound(audio,nBytesDone)203 ExitSound(audio, nBytesDone)
204 	int	audio;
205 	Ulong	nBytesDone;
206 {
207 	UINT4	tmp;
208 
209 	AifcHdr.formChk.dwSize = cpu_to_be32(nBytesDone + sizeof (AIFCHDR)
210 					- offsetof(AIFCHDR, commChk));
211 	tmp = cpu_to_be32(nBytesDone/(AifcHdr.numChannels[1] *
212 			    AifcHdr.samplesize[1]/ULONG_C(8)));
213 	AifcHdr.numSampleFrames[0] = tmp >> 24;
214 	AifcHdr.numSampleFrames[1] = tmp >> 16;
215 	AifcHdr.numSampleFrames[2] = tmp >> 8;
216 	AifcHdr.numSampleFrames[3] = tmp >> 0;
217 
218 	/*
219 	 * If an odd number of bytes has been written,
220 	 * extend the chunk with one dummy byte.
221 	 * This is a requirement for AIFC.
222 	 */
223 	if ((nBytesDone & 1) && (lseek(audio, 1L, SEEK_CUR) == -1)) {
224 		return (0);
225 	}
226 
227 	/*
228 	 * goto beginning
229 	 */
230 	if (lseek(audio, 0L, SEEK_SET) == -1) {
231 		return (0);
232 	}
233 	return (write(audio, &AifcHdr, sizeof (AifcHdr)));
234 }
235 
236 LOCAL Ulong
GetHdrSize()237 GetHdrSize()
238 {
239 	return (sizeof (AifcHdr));
240 }
241 
242 LOCAL Ulong
InSizeToOutSize(BytesToDo)243 InSizeToOutSize(BytesToDo)
244 	Ulong	BytesToDo;
245 {
246 	return (BytesToDo);
247 }
248 
249 struct soundfile aifcsound = {
250 	InitSound,		/* init header method */
251 	ExitSound,		/* exit header method */
252 	GetHdrSize,		/* report header size method */
253 	(int (*) __PR((int audio,
254 		Uchar *buf,
255 		size_t BytesToDo))) write, /* get sound samples out */
256 	InSizeToOutSize,	/* compressed? output file size */
257 	1,			/* needs big endian samples */
258 	"AIFC"
259 };
260