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