Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / icedax / aifc.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)aifc.c   1.5 01/10/27 Copyright 1998,1999 Heiko Eissfeldt */
14 /***
15  * CopyPolicy: GNU Public License 2 applies
16  * Copyright (C) by Heiko Eissfeldt
17  *
18  *
19  * ---------------------------------------------------------------------
20  *  definitions for aifc pcm output
21  * ---------------------------------------------------------------------
22  */
23
24 #include "config.h"
25 #include "mytype.h"
26 #include <stdio.h>
27 #include <standard.h>
28 #include <unixstd.h>
29 #include <strdefs.h>
30 #include <schily.h>
31 #include "byteorder.h"
32 #include "sndfile.h"
33
34 typedef UINT4 FOURCC;    /* a four character code */
35 typedef struct CHUNKHDR {
36   FOURCC        ckid;          /* chunk ID */
37   UINT4         dwSize; /* chunk size */
38 } CHUNKHDR;
39
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))
43
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')
50
51 #define NO_COMPRESSION  "not compressed"
52
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 {
56   CHUNKHDR      formChk;
57   FOURCC        formType;
58
59   CHUNKHDR      fverChk;                /* Version chunk */
60   UINT4         timestamp;              /* timestamp identifies version */
61
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 */
71
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 */
76
77 } AIFCHDR;
78
79 static AIFCHDR AifcHdr;
80
81 /* Prototypes */
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);
88
89 struct soundfile aifcsound =
90 {
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 */
98 };
99
100 /* format the sample rate into an
101    bigendian 10-byte IEEE-754 floating point number
102  */
103 static int Format_samplerate(unsigned long rate, unsigned char the_rate[10])
104 {
105   int i;
106
107   /* normalize rate */
108   for (i = 0; (rate & 0xffff) != 0; rate <<= 1, i++) {
109     if ((rate & 0x8000) != 0) {
110       break;
111     }
112   }
113
114   /* set exponent and sign */
115   the_rate[1] = 14-i;
116   the_rate[0] = 0x40;           /* LSB = sign */
117
118   /* 16-bit part of mantisse for sample rate */
119   the_rate[3] = rate & 0xff;
120   the_rate[2] = (rate >> 8) & 0xff;
121
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;
125
126   return 0;
127 }
128
129
130 static int InitSound(int audio, long channels, unsigned long rate, 
131                      long nBitsPerSample, unsigned long expected_bytes)
132 {
133   UINT4 tmp;
134
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);
141
142   AifcHdr.fverChk.ckid  = cpu_to_be32(FOURCC_FVER);
143   AifcHdr.fverChk.dwSize= cpu_to_be32(offsetof(AIFCHDR,commChk)
144                                         - offsetof(AIFCHDR,timestamp));
145
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 */
153
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));
157
158   AifcHdr.numChannels[1]= channels;
159
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);
167
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;
174
175   return write (audio, &AifcHdr, sizeof (AifcHdr));
176 }
177
178 static int ExitSound(int audio, unsigned long nBytesDone)
179 {
180   UINT4 tmp;
181
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;
190
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)) {
194     return 0;
195   }
196
197   /* goto beginning */
198   if (lseek(audio, 0L, SEEK_SET) == -1) {
199     return 0;
200   }
201   return write (audio, &AifcHdr, sizeof (AifcHdr));
202 }
203
204 static unsigned long GetHdrSize()
205 {
206   return sizeof( AifcHdr );
207 }
208
209 static unsigned long InSizeToOutSize(unsigned long  BytesToDo)
210 {
211         return BytesToDo;
212 }
213