patch: make *outfile extern
[platform/upstream/cdrkit.git] / icedax / aiff.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 /* @(#)aiff.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 aiff pcm output
21  * ---------------------------------------------------------------------
22  */
23
24 #include "config.h"
25 #include <stdio.h>
26 #include <unixstd.h>
27 #include <strdefs.h>
28 #include <standard.h>
29 #include <schily.h>
30 #include "mytype.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_AIFF     mmioFOURCC ('A', 'I', 'F', 'F')
46 #define FOURCC_COMM     mmioFOURCC ('C', 'O', 'M', 'M')
47 #define FOURCC_SSND     mmioFOURCC ('S', 'S', 'N', 'D')
48
49 typedef struct AIFFHDR {
50   CHUNKHDR      formChk;
51   FOURCC        formType;
52
53   CHUNKHDR      commChk;                /* Common chunk */
54   /* from now on, alignment prevents us from using the original types :-(( */
55   unsigned char numChannels[2];         /* Audio Channels */
56   unsigned char numSampleFrames[4];     /* # of samples */
57   unsigned char samplesize[2];          /* bits per sample */
58   unsigned char sample_rate[10];        /* sample rate in extended float */
59
60   unsigned char ssndChkid[4];           /* Sound data chunk */
61   unsigned char dwSize[4];              /* size of chunk */
62   unsigned char offset[4];              /* start of 1st sample */
63   unsigned char blocksize[4];           /* aligned sound data block size */
64 } AIFFHDR;
65
66 static AIFFHDR AiffHdr;
67
68 /* Prototypes */
69 static int Format_samplerate(unsigned long rate, unsigned char the_rate[10]);
70 static int InitSound(int audio, long channels, unsigned long rate, 
71                                                         long nBitsPerSample, unsigned long expected_bytes);
72 static int ExitSound(int audio, unsigned long nBytesDone);
73 static unsigned long GetHdrSize(void);
74 static unsigned long InSizeToOutSize(unsigned long BytesToDo);
75
76
77 /* format the sample rate into an
78    bigendian 10-byte IEEE-754 floating point number
79  */
80 static int Format_samplerate(unsigned long rate, unsigned char the_rate[10])
81 {
82   int i;
83
84   /* normalize rate */
85   for (i = 0; (rate & 0xffff) != 0; rate <<= 1, i++) {
86     if ((rate & 0x8000) != 0) {
87       break;
88     }
89   }
90
91   /* set exponent and sign */
92   the_rate[1] = 14-i;
93   the_rate[0] = 0x40;           /* LSB = sign */
94
95   /* 16-bit part of mantisse for sample rate */
96   the_rate[3] = rate & 0xff;
97   the_rate[2] = (rate >> 8) & 0xff;
98
99   /* initialize lower digits of mantisse */
100   the_rate[4] = the_rate[5] = the_rate[6] =
101   the_rate[7] = the_rate[8] = the_rate[9] = 0;
102
103   return 0;
104 }
105
106 static int InitSound(int audio, long channels, unsigned long rate, 
107                      long nBitsPerSample, unsigned long expected_bytes)
108 {
109   UINT4 tmp;
110
111   fillbytes(&AiffHdr, sizeof(AiffHdr), '\0');
112   AiffHdr.formChk.ckid  = cpu_to_be32(FOURCC_FORM);
113   AiffHdr.formChk.dwSize= cpu_to_be32(expected_bytes +
114                         offset_of(AIFFHDR,blocksize)+sizeof(AiffHdr.blocksize)
115                         - offsetof(AIFFHDR,formType));
116   AiffHdr.formType      = cpu_to_be32(FOURCC_AIFF);
117
118   AiffHdr.commChk.ckid  = cpu_to_be32(FOURCC_COMM);
119   AiffHdr.commChk.dwSize= cpu_to_be32(offset_of(AIFFHDR,ssndChkid)
120                                         - offset_of(AIFFHDR,numChannels));
121
122   AiffHdr.numChannels[1]= channels;
123   tmp = cpu_to_be32(expected_bytes/(channels * (nBitsPerSample/8)));
124   AiffHdr.numSampleFrames[0] = tmp >> 24;
125   AiffHdr.numSampleFrames[1] = tmp >> 16;
126   AiffHdr.numSampleFrames[2] = tmp >> 8;
127   AiffHdr.numSampleFrames[3] = tmp >> 0;
128   AiffHdr.samplesize[1] = nBitsPerSample;
129   Format_samplerate(rate, AiffHdr.sample_rate);
130
131   memcpy(AiffHdr.ssndChkid, "SSND", 4);
132   tmp = cpu_to_be32(expected_bytes + offset_of(AIFFHDR,blocksize)+sizeof(AiffHdr.blocksize) - offset_of(AIFFHDR, offset));
133   AiffHdr.dwSize[0] = tmp >> 24;
134   AiffHdr.dwSize[1] = tmp >> 16;
135   AiffHdr.dwSize[2] = tmp >> 8;
136   AiffHdr.dwSize[3] = tmp >> 0;
137
138   return write (audio, &AiffHdr, sizeof (AiffHdr));
139 }
140
141 static int ExitSound(int audio, unsigned long nBytesDone )
142 {
143   UINT4 tmp;
144
145   AiffHdr.formChk.dwSize= cpu_to_be32(nBytesDone + sizeof(AIFFHDR)
146                                         - offsetof(AIFFHDR,commChk));
147   tmp = cpu_to_be32(nBytesDone/(
148         AiffHdr.numChannels[1] * AiffHdr.samplesize[1]/ULONG_C(8)));
149   AiffHdr.numSampleFrames[0] = tmp >> 24;
150   AiffHdr.numSampleFrames[1] = tmp >> 16;
151   AiffHdr.numSampleFrames[2] = tmp >> 8;
152   AiffHdr.numSampleFrames[3] = tmp >> 0;
153
154   /* If an odd number of bytes has been written,
155      extend the chunk with one dummy byte. This is a requirement for AIFF. */
156   if ((nBytesDone & 1) && (lseek(audio, 1L, SEEK_CUR) == -1)) {
157     return 0;
158   }
159
160   /* goto beginning */
161   if (lseek(audio, 0L, SEEK_SET) == -1) {
162     return 0;
163   }
164   return write (audio, &AiffHdr, sizeof (AiffHdr));
165 }
166
167 static unsigned long GetHdrSize()
168 {
169   return sizeof( AiffHdr );
170 }
171
172 static unsigned long InSizeToOutSize(unsigned long BytesToDo)
173 {
174         return BytesToDo;
175 }
176
177 struct soundfile aiffsound =
178 {
179         InitSound,              /* init header method */
180         ExitSound,              /* exit header method */
181         GetHdrSize,             /* report header size method */
182         /* get sound samples out */
183         (int (*)(int audio, unsigned char *buf, unsigned long BytesToDo))write,
184         InSizeToOutSize,        /* compressed? output file size */
185         1                                               /* needs big endian samples */
186 };
187
188