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