1 /*--------------------------------------------------------------------------*
2 Project: Revolution SOUNDFILE dynamic link library
3 File: aifffile.c
4
5 Copyright (C)2001-2006 Nintendo All Rights Reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: aifffile.c,v $
14 Revision 1.2 02/09/2006 06:51:39 aka
15 Changed copyright.
16
17
18 *--------------------------------------------------------------------------*/
19 #include <windows.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include "aifffile.h"
23 #include "endian.h"
24
25 u32 * str_form = (u32 *)"FORM";
26 u32 * str_aiff = (u32 *)"AIFF";
27 u32 * str_aifc = (u32 *)"AIFC";
28 u32 * str_fver = (u32 *)"FVER";
29 u32 * str_comm = (u32 *)"COMM";
30 u32 * str_ssnd = (u32 *)"SSND";
31 u32 * str_mark = (u32 *)"MARK";
32 u32 * str_comt = (u32 *)"COMT";
33 u32 * str_inst = (u32 *)"INST";
34 u32 * str_midi = (u32 *)"MIDI";
35 u32 * str_aesd = (u32 *)"AESD";
36 u32 * str_appl = (u32 *)"APPL";
37 u32 * str_name = (u32 *)"NAME";
38 u32 * str_auth = (u32 *)"AUTH";
39 u32 * str_copy = (u32 *)"(c) ";
40 u32 * str_anno = (u32 *)"ANNO";
41
42 /*--------------------------------------------------------------------------*/
aiffCreateHeader(AIFFINFO * aiffinfo,int channels,int samples,int bitsPerSample,int sampleRate)43 void aiffCreateHeader
44 (
45 AIFFINFO *aiffinfo,
46 int channels,
47 int samples,
48 int bitsPerSample,
49 int sampleRate
50 )
51 {
52 aiffinfo->comm.chunk[0] = 'C';
53 aiffinfo->comm.chunk[1] = 'O';
54 aiffinfo->comm.chunk[2] = 'M';
55 aiffinfo->comm.chunk[3] = 'M';
56 aiffinfo->comm.bytes[0] = 0;
57 aiffinfo->comm.bytes[1] = 0;
58 aiffinfo->comm.bytes[2] = 0;
59 aiffinfo->comm.bytes[3] = 18;
60 aiffinfo->comm.channels[0] = (u8)(0xFF & (channels >> 8));
61 aiffinfo->comm.channels[1] = (u8)(0xFF & channels);
62 aiffinfo->comm.samples[0] = (u8)(0xFF & (samples >> 24));
63 aiffinfo->comm.samples[1] = (u8)(0xFF & (samples >> 16));
64 aiffinfo->comm.samples[2] = (u8)(0xFF & (samples >> 8));
65 aiffinfo->comm.samples[3] = (u8)(0xFF & samples);
66 aiffinfo->comm.bitsPerSample[0] = (u8)(0xFF & (bitsPerSample >> 8));
67 aiffinfo->comm.bitsPerSample[1] = (u8)(0xFF & bitsPerSample);
68 aiffinfo->comm.samplesPerSec[0] = 0x40;
69 aiffinfo->comm.samplesPerSec[1] = 0x1E;
70 aiffinfo->comm.samplesPerSec[2] = (u8)(0x7F & sampleRate >> 24);
71 aiffinfo->comm.samplesPerSec[3] = (u8)(0xFF & sampleRate >> 16);
72 aiffinfo->comm.samplesPerSec[4] = (u8)(0xFF & sampleRate >> 8);
73 aiffinfo->comm.samplesPerSec[5] = (u8)(0xFF & sampleRate);
74 aiffinfo->comm.samplesPerSec[6] = 0x00;
75 aiffinfo->comm.samplesPerSec[7] = 0x00;
76 aiffinfo->comm.samplesPerSec[8] = 0x00;
77 aiffinfo->comm.samplesPerSec[9] = 0x00;
78 }
79
80
81 /*--------------------------------------------------------------------------*/
aiffWriteHeader(AIFFINFO * aiffinfo,FILE * outfile,int loopStart,int loopEnd,int bitsPerSample,int samples,int channels)82 void aiffWriteHeader
83 (
84 AIFFINFO *aiffinfo,
85 FILE *outfile,
86 int loopStart,
87 int loopEnd,
88 int bitsPerSample,
89 int samples,
90 int channels
91 )
92 {
93 u32 size;
94
95 switch (bitsPerSample)
96 {
97 case 8:
98
99 size = reverse_endian_32(sizeof(AIFFINFO) +
100 12 + // AIFF SSND, n bytes
101 (samples * channels) + 8);
102 break;
103
104 case 16:
105
106 size = reverse_endian_32(sizeof(AIFFINFO) +
107 12 + // AIFF SSND, n bytes
108 (samples * channels * 2) + 8);
109
110 break;
111 }
112
113 if (loopEnd)
114 size += (sizeof(AIFFMARK) + sizeof(AIFFINST));
115
116 fwrite("FORM", sizeof(char), 4, outfile);
117 fwrite(&size, sizeof(char), 4, outfile);
118 fwrite("AIFF", sizeof(char), 4, outfile);
119 fwrite(&aiffinfo->comm, sizeof(AIFFCOMM), 1, outfile);
120 fwrite("SSND", sizeof(char), 4, outfile);
121
122 switch (bitsPerSample)
123 {
124 case 8:
125
126 size = reverse_endian_32(
127 (samples * // n samples
128 channels) + // n channels
129 8 // fist 8 bytes are 0
130 );
131
132 break;
133
134 case 16:
135
136 size = reverse_endian_32(
137 (samples * // n samples
138 2 * // 2 bytes per sample
139 channels) + // n channels
140 8 // fist 8 bytes are 0
141 );
142
143 break;
144 }
145
146 fwrite(&size, sizeof(char), 4, outfile);
147
148 size = 0;
149
150 fwrite(&size, sizeof(char), 4, outfile);
151 fwrite(&size, sizeof(char), 4, outfile);
152 }
153
154
155 /*--------------------------------------------------------------------------*/
aiffCreateMark(AIFFINFO * aiffinfo,u32 startloop,u32 endloop)156 void aiffCreateMark(AIFFINFO *aiffinfo, u32 startloop, u32 endloop)
157 {
158 aiffinfo->inst.chunk[0] = 'I';
159 aiffinfo->inst.chunk[1] = 'N';
160 aiffinfo->inst.chunk[2] = 'S';
161 aiffinfo->inst.chunk[3] = 'T';
162 aiffinfo->inst.bytes[0] = 0;
163 aiffinfo->inst.bytes[1] = 0;
164 aiffinfo->inst.bytes[2] = 0;
165 aiffinfo->inst.bytes[3] = 20;
166 aiffinfo->inst.normalKey = 64;
167 aiffinfo->inst.detune = 0;
168 aiffinfo->inst.lowKey = 0;
169 aiffinfo->inst.hiKey = 127;
170 aiffinfo->inst.loVel = 0;
171 aiffinfo->inst.hiVel = 127;
172 aiffinfo->inst.gain[0] = 0;
173 aiffinfo->inst.gain[1] = 0;
174 aiffinfo->inst.playMode0[0] = 0;
175 aiffinfo->inst.playMode0[1] = 1;
176 aiffinfo->inst.begLoop0[0] = 0;
177 aiffinfo->inst.begLoop0[1] = 0;
178 aiffinfo->inst.endLoop0[0] = 0;
179 aiffinfo->inst.endLoop0[1] = 1;
180 aiffinfo->inst.playMode1[0] = 0;
181 aiffinfo->inst.playMode1[1] = 1;
182 aiffinfo->inst.begLoop1[0] = 0;
183 aiffinfo->inst.begLoop1[1] = 0;
184 aiffinfo->inst.endLoop1[0] = 0;
185 aiffinfo->inst.endLoop1[1] = 0;
186
187 aiffinfo->mark.chunk[0] = 'M';
188 aiffinfo->mark.chunk[1] = 'A';
189 aiffinfo->mark.chunk[2] = 'R';
190 aiffinfo->mark.chunk[3] = 'K';
191 aiffinfo->mark.bytes[0] = 0;
192 aiffinfo->mark.bytes[1] = 0;
193 aiffinfo->mark.bytes[2] = 0;
194 aiffinfo->mark.bytes[3] = 35;
195 aiffinfo->mark.count[0] = 0;
196 aiffinfo->mark.count[1] = 2;
197 aiffinfo->mark.id0[0] = 0;
198 aiffinfo->mark.id0[1] = 0;
199 aiffinfo->mark.position0[0] = (u8)(0xFF & (startloop >> 24));
200 aiffinfo->mark.position0[1] = (u8)(0xFF & (startloop >> 16));
201 aiffinfo->mark.position0[2] = (u8)(0xFF & (startloop >> 8));
202 aiffinfo->mark.position0[3] = (u8)(0xFF & startloop);
203 aiffinfo->mark.ch0[0] = 0x08;
204 aiffinfo->mark.ch0[1] = 'b';
205 aiffinfo->mark.ch0[2] = 'e';
206 aiffinfo->mark.ch0[3] = 'g';
207 aiffinfo->mark.ch0[4] = ' ';
208 aiffinfo->mark.ch0[5] = 'l';
209 aiffinfo->mark.ch0[6] = 'o';
210 aiffinfo->mark.ch0[7] = 'o';
211 aiffinfo->mark.ch0[8] = 'p';
212 aiffinfo->mark.ch0[9] = 0;
213 aiffinfo->mark.id1[0] = 0;
214 aiffinfo->mark.id1[1] = 1;
215 aiffinfo->mark.position1[0] = (u8)(0xFF & (endloop >> 24));
216 aiffinfo->mark.position1[1] = (u8)(0xFF & (endloop >> 16));
217 aiffinfo->mark.position1[2] = (u8)(0xFF & (endloop >> 8));
218 aiffinfo->mark.position1[3] = (u8)(0xFF & endloop);
219 aiffinfo->mark.ch1[0] = 0x30;
220 aiffinfo->mark.ch1[1] = 0x08;
221 aiffinfo->mark.ch1[2] = 'e';
222 aiffinfo->mark.ch1[3] = 'n';
223 aiffinfo->mark.ch1[4] = 'd';
224 aiffinfo->mark.ch1[5] = ' ';
225 aiffinfo->mark.ch1[6] = 'l';
226 aiffinfo->mark.ch1[7] = 'o';
227 aiffinfo->mark.ch1[8] = 'o';
228 aiffinfo->mark.ch1[9] = 'p';
229 aiffinfo->mark.ch1[10] = 0;
230 }
231
232
233 /*--------------------------------------------------------------------------*/
aiffWriteMark(AIFFINFO * aiffinfo,FILE * outfile)234 void aiffWriteMark(AIFFINFO *aiffinfo, FILE *outfile)
235 {
236 fwrite(&aiffinfo->inst, sizeof(AIFFINST), 1, outfile);
237 fwrite(&aiffinfo->mark, sizeof(AIFFMARK), 1, outfile);
238 }
239
240
241 /*--------------------------------------------------------------------------*/
aiffReadHeader(AIFFINFO * aiffinfo,FILE * infile)242 int aiffReadHeader
243 (
244 AIFFINFO *aiffinfo,
245 FILE *infile
246 )
247 {
248 u32 chunk, length, sample_position;
249
250 if (0 != fseek(infile, 0, SEEK_SET))
251 return FALSE;
252
253 fread(&chunk, 1, sizeof(u32), infile);
254 if (chunk != *str_form)
255 return FALSE;
256
257 fread(&length, 1, sizeof(u32), infile);
258 fread(&chunk, 1, sizeof(u32), infile);
259
260 if (chunk != *str_aiff)
261 return FALSE;
262
263 fread(&chunk, 1, sizeof(u32), infile);
264
265 if (chunk != *str_comm)
266 return FALSE;
267
268 fread(&length, 1, sizeof(u32), infile);
269
270 fread(&aiffinfo->comm.channels, 1, sizeof(u16), infile);
271 fread(&aiffinfo->comm.samples, 1, sizeof(u32), infile);
272 fread(&aiffinfo->comm.bitsPerSample, 1, sizeof(u16), infile);
273 fread(&aiffinfo->comm.samplesPerSec[0], 10, sizeof(u8), infile);
274
275 length = reverse_endian_32(length);
276 length = 18 - length;
277
278 if (length)
279 fseek(infile, length, SEEK_CUR);
280
281 // initialize loop markers to 0
282 aiffinfo->mark.position0[0] =
283 aiffinfo->mark.position0[1] =
284 aiffinfo->mark.position0[2] =
285 aiffinfo->mark.position0[3] =
286 aiffinfo->mark.position1[0] =
287 aiffinfo->mark.position1[1] =
288 aiffinfo->mark.position1[2] =
289 aiffinfo->mark.position1[3] = 0;
290
291 // get the read position up to the sample data, that's what the
292 // caller is expecting.. I know...
293 while (fread(&chunk, 1, sizeof(u32), infile) == 4)
294 {
295 u16 count;
296 u32 i;
297
298 // length of chunk
299 fread(&length, 1, sizeof(u32), infile);
300 length = reverse_endian_32(length);
301
302 if (feof(infile))
303 break;
304
305 switch (chunk)
306 {
307 case CHUNK_SSND:
308
309 // first 8 bytes of samples are garbage
310 fread(&chunk, 1, sizeof(u32), infile);
311 fread(&chunk, 1, sizeof(u32), infile);
312
313 // save the position because we are going to go look for a loop markers
314 sample_position = ftell(infile);
315 fseek(infile, length - 8, SEEK_CUR);
316
317 break;
318
319 case CHUNK_MARK:
320
321 fread(&count, 1, sizeof(u16), infile); // count, n markers
322 count = reverse_endian_16(count);
323 length -= 2;
324
325 i = 0;
326
327 while (count)
328 {
329 u16 id;
330 u32 position;
331 u8 ch;
332
333 fread(&id, 1, sizeof(u16), infile);
334 fread(&position, 1, sizeof(u32), infile);
335
336 id = reverse_endian_16(id);
337 position = reverse_endian_32(position);
338
339 switch (i)
340 {
341 case 0:
342
343 aiffinfo->mark.position0[0] = (u8)(0xFF & (position >> 24));
344 aiffinfo->mark.position0[1] = (u8)(0xFF & (position >> 16));
345 aiffinfo->mark.position0[2] = (u8)(0xFF & (position >> 8));
346 aiffinfo->mark.position0[3] = (u8)(0xFF & position);
347 //printf("begin loop: %d\n", position);
348 break;
349
350 case 1:
351
352 aiffinfo->mark.position1[0] = (u8)(0xFF & (position >> 24));
353 aiffinfo->mark.position1[1] = (u8)(0xFF & (position >> 16));
354 aiffinfo->mark.position1[2] = (u8)(0xFF & (position >> 8));
355 aiffinfo->mark.position1[3] = (u8)(0xFF & position);
356 //printf("end loop: %d\n", position);
357 break;
358 }
359
360 // skip pstring
361 fread(&ch, 1, sizeof(u8), infile);
362 fseek(infile, ch, SEEK_CUR);
363
364 if (ftell(infile) & 1)
365 fread(&ch, 1, sizeof(u8), infile);
366
367 count--;
368 i++;
369 }
370
371 break;
372
373 case CHUNK_INST:
374
375 {
376 u16 playmode;
377
378 // skip some stuff we don't care about
379 fseek(infile, 8, SEEK_CUR);
380 fread(&playmode, 1, sizeof(u16), infile);
381 playmode = reverse_endian_16(playmode);
382
383 if (playmode != 1)
384 {
385 aiffinfo->mark.position0[0] = 0;
386 aiffinfo->mark.position0[1] = 0;
387 aiffinfo->mark.position0[2] = 0;
388 aiffinfo->mark.position0[3] = 0;
389 aiffinfo->mark.position1[0] = 0;
390 aiffinfo->mark.position1[1] = 0;
391 aiffinfo->mark.position1[2] = 0;
392 aiffinfo->mark.position1[3] = 0;
393 }
394
395 fseek(infile, 10, SEEK_CUR);
396 }
397
398 break;
399
400 default:
401
402 fseek(infile, length, SEEK_CUR);
403
404 break;
405 }
406 }
407 // put the read position back to where the samples are
408 fseek(infile, 0, SEEK_SET);
409 fseek(infile, sample_position, SEEK_CUR);
410
411 return TRUE;
412 }
413
414
415 /*--------------------------------------------------------------------------*/
aiffGetChannels(AIFFINFO * aiffinfo)416 int aiffGetChannels(AIFFINFO *aiffinfo)
417 {
418 return (aiffinfo->comm.channels[0] << 8) | aiffinfo->comm.channels[1];
419 }
420
421
422 /*--------------------------------------------------------------------------*/
aiffGetSampleRate(AIFFINFO * aiffinfo)423 int aiffGetSampleRate(AIFFINFO *aiffinfo)
424 {
425 unsigned long ieeeExponent;
426 unsigned long ieeeMantissaHi;
427
428
429 // FIXED: sign must be removed from exponent, NOT mantissa.
430
431
432 ieeeExponent = (aiffinfo->comm.samplesPerSec[0] << 8) | aiffinfo->comm.samplesPerSec[1];
433
434 ieeeMantissaHi = ( (aiffinfo->comm.samplesPerSec[2] << 24) |
435 (aiffinfo->comm.samplesPerSec[3] << 16) |
436 (aiffinfo->comm.samplesPerSec[4] << 8) |
437 aiffinfo->comm.samplesPerSec[5] );
438
439 ieeeExponent &= 0x7FFF; // remove sign bit
440
441 return(ieeeMantissaHi >> (16414 - ieeeExponent));
442
443 }
444
445
446 /*--------------------------------------------------------------------------*/
aiffGetSamples(AIFFINFO * aiffinfo)447 int aiffGetSamples(AIFFINFO *aiffinfo)
448 {
449 return (aiffinfo->comm.samples[0] << 24) |
450 (aiffinfo->comm.samples[1] << 16) |
451 (aiffinfo->comm.samples[2] << 8) |
452 aiffinfo->comm.samples[3];
453 }
454
455
456 /*--------------------------------------------------------------------------*/
aiffGetBitsPerSample(AIFFINFO * aiffinfo)457 int aiffGetBitsPerSample(AIFFINFO *aiffinfo)
458 {
459 return (aiffinfo->comm.bitsPerSample[0] << 8) |
460 aiffinfo->comm.bitsPerSample[1];
461 }
462
463
464 /*--------------------------------------------------------------------------*/
aiffGetLoopStart(AIFFINFO * aiffinfo)465 int aiffGetLoopStart(AIFFINFO *aiffinfo)
466 {
467 return (aiffinfo->mark.position0[0] << 24) |
468 (aiffinfo->mark.position0[1] << 16) |
469 (aiffinfo->mark.position0[2] << 8) |
470 aiffinfo->mark.position0[3];
471 }
472
473
474 /*--------------------------------------------------------------------------*/
aiffGetLoopEnd(AIFFINFO * aiffinfo)475 int aiffGetLoopEnd(AIFFINFO *aiffinfo)
476 {
477 return ((aiffinfo->mark.position1[0] << 24) |
478 (aiffinfo->mark.position1[1] << 16) |
479 (aiffinfo->mark.position1[2] << 8) |
480 aiffinfo->mark.position1[3]);
481 }
482