2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)aifc.c 1.5 01/10/27 Copyright 1998,1999 Heiko Eissfeldt */
15 * CopyPolicy: GNU Public License 2 applies
16 * Copyright (C) by Heiko Eissfeldt
19 * ---------------------------------------------------------------------
20 * definitions for aifc pcm output
21 * ---------------------------------------------------------------------
31 #include "byteorder.h"
34 typedef UINT4 FOURCC; /* a four character code */
35 typedef struct CHUNKHDR {
36 FOURCC ckid; /* chunk ID */
37 UINT4 dwSize; /* chunk size */
40 #define mmioFOURCC(ch0, ch1, ch2, ch3) \
41 ((UINT4)(unsigned char)(ch3) | ((UINT4)(unsigned char)(ch2) << 8) | \
42 ((UINT4)(unsigned char)(ch1) << 16) | ((UINT4)(unsigned char)(ch0) << 24))
44 #define FOURCC_FORM mmioFOURCC ('F', 'O', 'R', 'M')
45 #define FOURCC_AIFC mmioFOURCC ('A', 'I', 'F', 'C')
46 #define FOURCC_FVER mmioFOURCC ('F', 'V', 'E', 'R')
47 #define FOURCC_COMM mmioFOURCC ('C', 'O', 'M', 'M')
48 #define FOURCC_NONE mmioFOURCC ('N', 'O', 'N', 'E')
49 #define FOURCC_SSND mmioFOURCC ('S', 'S', 'N', 'D')
51 #define NO_COMPRESSION "not compressed"
53 /* brain dead construction from apple involving bigendian 80-bit doubles.
54 Definitely designed not to be portable. Alignment is a nightmare too. */
55 typedef struct AIFCHDR {
59 CHUNKHDR fverChk; /* Version chunk */
60 UINT4 timestamp; /* timestamp identifies version */
62 CHUNKHDR commChk; /* Common chunk */
63 /* from now on, alignment prevents us from using the original types :-(( */
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]; /* sample rate in extended float */
68 unsigned char compressionType[4]; /* AIFC extension */
69 unsigned char compressionNameLen; /* AIFC extension */
70 char compressionName[sizeof(NO_COMPRESSION)]; /* AIFC extension */
72 unsigned char ssndChkid[4]; /* Sound data chunk */
73 unsigned char dwSize[4]; /* size of chunk */
74 unsigned char offset[4]; /* start of 1st sample */
75 unsigned char blocksize[4]; /* aligned sound data block size */
79 static AIFCHDR AifcHdr;
82 static int Format_samplerate(unsigned long rate, unsigned char the_rate[10]);
83 static int InitSound(int audio, long channels, unsigned long rate,
84 long nBitsPerSample, unsigned long expected_bytes );
85 static int ExitSound(int audio, unsigned long nBytesDone);
86 static unsigned long GetHdrSize(void);
87 static unsigned long InSizeToOutSize(unsigned long BytesToDo);
89 struct soundfile aifcsound =
91 InitSound, /* init header method */
92 ExitSound, /* exit header method */
93 GetHdrSize, /* report header size method */
94 /* get sound samples out */
95 (int (*)(int audio, unsigned char *buf, unsigned long BytesToDo))write,
96 InSizeToOutSize, /* compressed? output file size */
97 1 /* needs big endian samples */
100 /* format the sample rate into an
101 bigendian 10-byte IEEE-754 floating point number
103 static int Format_samplerate(unsigned long rate, unsigned char the_rate[10])
108 for (i = 0; (rate & 0xffff) != 0; rate <<= 1, i++) {
109 if ((rate & 0x8000) != 0) {
114 /* set exponent and sign */
116 the_rate[0] = 0x40; /* LSB = sign */
118 /* 16-bit part of mantisse for sample rate */
119 the_rate[3] = rate & 0xff;
120 the_rate[2] = (rate >> 8) & 0xff;
122 /* initialize lower digits of mantisse */
123 the_rate[4] = the_rate[5] = the_rate[6] =
124 the_rate[7] = the_rate[8] = the_rate[9] = 0;
130 static int InitSound(int audio, long channels, unsigned long rate,
131 long nBitsPerSample, unsigned long expected_bytes)
135 fillbytes(&AifcHdr, sizeof(AifcHdr), '\0');
136 AifcHdr.formChk.ckid = cpu_to_be32(FOURCC_FORM);
137 AifcHdr.formChk.dwSize= cpu_to_be32(expected_bytes +
138 offset_of(AIFCHDR,blocksize)+sizeof(AifcHdr.blocksize)
139 - offsetof(AIFCHDR,commChk));
140 AifcHdr.formType = cpu_to_be32(FOURCC_AIFC);
142 AifcHdr.fverChk.ckid = cpu_to_be32(FOURCC_FVER);
143 AifcHdr.fverChk.dwSize= cpu_to_be32(offsetof(AIFCHDR,commChk)
144 - offsetof(AIFCHDR,timestamp));
146 AifcHdr.compressionType[0]='N';
147 AifcHdr.compressionType[1]='O';
148 AifcHdr.compressionType[2]='N';
149 AifcHdr.compressionType[3]='E';
150 AifcHdr.compressionNameLen = sizeof(NO_COMPRESSION)-1;
151 strcpy(AifcHdr.compressionName, NO_COMPRESSION);
152 AifcHdr.timestamp = cpu_to_be32(UINT4_C(0xA2805140)); /* AIFC Version 1 */
154 AifcHdr.commChk.ckid = cpu_to_be32(FOURCC_COMM);
155 AifcHdr.commChk.dwSize= cpu_to_be32(offset_of(AIFCHDR,ssndChkid)
156 - offset_of(AIFCHDR,numChannels));
158 AifcHdr.numChannels[1]= channels;
160 tmp = cpu_to_be32(expected_bytes/(channels * (nBitsPerSample/8)));
161 AifcHdr.numSampleFrames[0] = tmp >> 24;
162 AifcHdr.numSampleFrames[1] = tmp >> 16;
163 AifcHdr.numSampleFrames[2] = tmp >> 8;
164 AifcHdr.numSampleFrames[3] = tmp >> 0;
165 AifcHdr.samplesize[1] = nBitsPerSample;
166 Format_samplerate(rate, AifcHdr.sample_rate);
168 memcpy(AifcHdr.ssndChkid, "SSND", 4);
169 tmp = cpu_to_be32(expected_bytes + offset_of(AIFCHDR,blocksize)+sizeof(AifcHdr.blocksize) - offset_of(AIFCHDR, offset));
170 AifcHdr.dwSize[0] = tmp >> 24;
171 AifcHdr.dwSize[1] = tmp >> 16;
172 AifcHdr.dwSize[2] = tmp >> 8;
173 AifcHdr.dwSize[3] = tmp >> 0;
175 return write (audio, &AifcHdr, sizeof (AifcHdr));
178 static int ExitSound(int audio, unsigned long nBytesDone)
182 AifcHdr.formChk.dwSize= cpu_to_be32(nBytesDone + sizeof(AIFCHDR)
183 - offsetof(AIFCHDR,commChk));
184 tmp = cpu_to_be32(nBytesDone/(
185 AifcHdr.numChannels[1] * AifcHdr.samplesize[1]/ULONG_C(8)));
186 AifcHdr.numSampleFrames[0] = tmp >> 24;
187 AifcHdr.numSampleFrames[1] = tmp >> 16;
188 AifcHdr.numSampleFrames[2] = tmp >> 8;
189 AifcHdr.numSampleFrames[3] = tmp >> 0;
191 /* If an odd number of bytes has been written,
192 extend the chunk with one dummy byte. This is a requirement for AIFC. */
193 if ((nBytesDone & 1) && (lseek(audio, 1L, SEEK_CUR) == -1)) {
198 if (lseek(audio, 0L, SEEK_SET) == -1) {
201 return write (audio, &AifcHdr, sizeof (AifcHdr));
204 static unsigned long GetHdrSize()
206 return sizeof( AifcHdr );
209 static unsigned long InSizeToOutSize(unsigned long BytesToDo)