1 /*--------------------------------------------------------------------------*
2 Project: Revolution SOUNDFILE dynamic link library
3 File: aifffile.c
4
5 Copyright (C)2001-2009 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.3 2009/03/30 07:44:45 aka
15 Copied from SDK_3_2_DEV_BRANCH.
16
17 Revision 1.2.40.1 2009/03/30 04:39:49 aka
18 Cleaned up.
19
20 Revision 1.2 2006/02/09 06:51:39 aka
21 Changed copyright.
22
23 *--------------------------------------------------------------------------*/
24
25 #include <windows.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include "aifffile.h"
29 #include "endian.h"
30
31
32 u32 * str_form = (u32 *)"FORM";
33 u32 * str_aiff = (u32 *)"AIFF";
34 u32 * str_aifc = (u32 *)"AIFC";
35 u32 * str_fver = (u32 *)"FVER";
36 u32 * str_comm = (u32 *)"COMM";
37 u32 * str_ssnd = (u32 *)"SSND";
38 u32 * str_mark = (u32 *)"MARK";
39 u32 * str_comt = (u32 *)"COMT";
40 u32 * str_inst = (u32 *)"INST";
41 u32 * str_midi = (u32 *)"MIDI";
42 u32 * str_aesd = (u32 *)"AESD";
43 u32 * str_appl = (u32 *)"APPL";
44 u32 * str_name = (u32 *)"NAME";
45 u32 * str_auth = (u32 *)"AUTH";
46 u32 * str_copy = (u32 *)"(c) ";
47 u32 * str_anno = (u32 *)"ANNO";
48
49
50 /*---------------------------------------------------------------------------*
51 Name: aiffCreateHeader
52
53 Description: create an Aiff file header.
54
55 Arguments: aiffinfo pointer of an AIFFINFO structure.
56 channels num of channels.
57 samples num of samples.
58 bitPerSample bit width per a sample.
59 sampleRate sampling frequency.
60
61 Returns: none.
62 *---------------------------------------------------------------------------*/
63
aiffCreateHeader(AIFFINFO * aiffinfo,int channels,int samples,int bitsPerSample,int sampleRate)64 void aiffCreateHeader
65 (
66 AIFFINFO *aiffinfo,
67 int channels,
68 int samples,
69 int bitsPerSample,
70 int sampleRate
71 )
72 {
73 aiffinfo->comm.chunk[0] = 'C';
74 aiffinfo->comm.chunk[1] = 'O';
75 aiffinfo->comm.chunk[2] = 'M';
76 aiffinfo->comm.chunk[3] = 'M';
77 aiffinfo->comm.bytes[0] = 0;
78 aiffinfo->comm.bytes[1] = 0;
79 aiffinfo->comm.bytes[2] = 0;
80 aiffinfo->comm.bytes[3] = 18;
81 aiffinfo->comm.channels[0] = (u8)(0xFF & (channels >> 8));
82 aiffinfo->comm.channels[1] = (u8)(0xFF & channels);
83 aiffinfo->comm.samples[0] = (u8)(0xFF & (samples >> 24));
84 aiffinfo->comm.samples[1] = (u8)(0xFF & (samples >> 16));
85 aiffinfo->comm.samples[2] = (u8)(0xFF & (samples >> 8));
86 aiffinfo->comm.samples[3] = (u8)(0xFF & samples);
87 aiffinfo->comm.bitsPerSample[0] = (u8)(0xFF & (bitsPerSample >> 8));
88 aiffinfo->comm.bitsPerSample[1] = (u8)(0xFF & bitsPerSample);
89 aiffinfo->comm.samplesPerSec[0] = 0x40;
90 aiffinfo->comm.samplesPerSec[1] = 0x1E;
91 aiffinfo->comm.samplesPerSec[2] = (u8)(0x7F & sampleRate >> 24);
92 aiffinfo->comm.samplesPerSec[3] = (u8)(0xFF & sampleRate >> 16);
93 aiffinfo->comm.samplesPerSec[4] = (u8)(0xFF & sampleRate >> 8);
94 aiffinfo->comm.samplesPerSec[5] = (u8)(0xFF & sampleRate);
95 aiffinfo->comm.samplesPerSec[6] = 0x00;
96 aiffinfo->comm.samplesPerSec[7] = 0x00;
97 aiffinfo->comm.samplesPerSec[8] = 0x00;
98 aiffinfo->comm.samplesPerSec[9] = 0x00;
99 }
100
101
102 /*---------------------------------------------------------------------------*
103 Name: aiffWriteHeader
104
105 Description: output an Aiff file header.
106
107 Arguments: aiffinfo pointer of an AIFFINFO structure.
108 outfile pointer of a FILE object.
109 channels num of channels.
110 samples num of samples.
111 bitPerSample bit width per a sample.
112 loopEnd position of loop end
113
114 Returns: none.
115 *---------------------------------------------------------------------------*/
116
aiffWriteHeader(AIFFINFO * aiffinfo,FILE * outfile,int channels,int samples,int bitsPerSample,int loopEnd)117 void aiffWriteHeader
118 (
119 AIFFINFO *aiffinfo,
120 FILE *outfile,
121 int channels,
122 int samples,
123 int bitsPerSample,
124 int loopEnd
125 )
126 {
127 u32 size;
128 u32 data;
129
130 size = sizeof(AIFFCOMM); // common chunk
131 size += 12; // sound data chunk (header only)
132
133 switch (bitsPerSample)
134 {
135 case 8:
136
137 data = (samples * channels) + 8; // first 8 bytes are 0
138
139 break;
140
141 case 16:
142
143 data = (samples * channels * 2) + 8; // first 8 bytes are 0
144
145 break;
146 }
147
148 size += data; // Sound Data Chunk (data part)
149
150 if (loopEnd)
151 {
152 size += sizeof(AIFFMARK); // marker chunk
153 size += sizeof(AIFFINST); // instrument chunk
154 }
155
156 size = reverse_endian_32(size);
157
158 fwrite("FORM", sizeof(char), 4, outfile);
159 fwrite(&size, sizeof(char), 4, outfile);
160 fwrite("AIFF", sizeof(char), 4, outfile);
161 fwrite(&aiffinfo->comm, sizeof(AIFFCOMM), 1, outfile);
162 fwrite("SSND", sizeof(char), 4, outfile);
163
164 size = reverse_endian_32(data);
165
166 fwrite(&size, sizeof(char), 4, outfile);
167
168 size = 0;
169
170 fwrite(&size, sizeof(char), 4, outfile);
171 fwrite(&size, sizeof(char), 4, outfile);
172 }
173
174
175 /*---------------------------------------------------------------------------*
176 Name: aiffCreateMark
177
178 Description: create an instrument chunk and a marker chunk.
179
180 Arguments: aiffinfo pointer of an AIFFINFO structure.
181 looopStart position of loop start
182 loopEnd position of loop end
183
184 Returns: none.
185 *---------------------------------------------------------------------------*/
186
aiffCreateMark(AIFFINFO * aiffinfo,u32 loopStart,u32 loopEnd)187 void aiffCreateMark(AIFFINFO *aiffinfo, u32 loopStart, u32 loopEnd)
188 {
189 aiffinfo->inst.chunk[0] = 'I';
190 aiffinfo->inst.chunk[1] = 'N';
191 aiffinfo->inst.chunk[2] = 'S';
192 aiffinfo->inst.chunk[3] = 'T';
193 aiffinfo->inst.bytes[0] = 0;
194 aiffinfo->inst.bytes[1] = 0;
195 aiffinfo->inst.bytes[2] = 0;
196 aiffinfo->inst.bytes[3] = 20;
197 aiffinfo->inst.normalKey = 64;
198 aiffinfo->inst.detune = 0;
199 aiffinfo->inst.lowKey = 0;
200 aiffinfo->inst.hiKey = 127;
201 aiffinfo->inst.loVel = 0;
202 aiffinfo->inst.hiVel = 127;
203 aiffinfo->inst.gain[0] = 0;
204 aiffinfo->inst.gain[1] = 0;
205 aiffinfo->inst.playMode0[0] = 0;
206 aiffinfo->inst.playMode0[1] = 1;
207 aiffinfo->inst.begLoop0[0] = 0;
208 aiffinfo->inst.begLoop0[1] = 0;
209 aiffinfo->inst.endLoop0[0] = 0;
210 aiffinfo->inst.endLoop0[1] = 1;
211 aiffinfo->inst.playMode1[0] = 0;
212 aiffinfo->inst.playMode1[1] = 0;
213 aiffinfo->inst.begLoop1[0] = 0;
214 aiffinfo->inst.begLoop1[1] = 0;
215 aiffinfo->inst.endLoop1[0] = 0;
216 aiffinfo->inst.endLoop1[1] = 0;
217
218 aiffinfo->mark.chunk[0] = 'M';
219 aiffinfo->mark.chunk[1] = 'A';
220 aiffinfo->mark.chunk[2] = 'R';
221 aiffinfo->mark.chunk[3] = 'K';
222 aiffinfo->mark.bytes[0] = 0;
223 aiffinfo->mark.bytes[1] = 0;
224 aiffinfo->mark.bytes[2] = 0;
225 aiffinfo->mark.bytes[3] = 34;
226 aiffinfo->mark.count[0] = 0;
227 aiffinfo->mark.count[1] = 2;
228 aiffinfo->mark.id0[0] = 0;
229 aiffinfo->mark.id0[1] = 0;
230 aiffinfo->mark.position0[0] = (u8)(0xFF & (loopStart >> 24));
231 aiffinfo->mark.position0[1] = (u8)(0xFF & (loopStart >> 16));
232 aiffinfo->mark.position0[2] = (u8)(0xFF & (loopStart >> 8));
233 aiffinfo->mark.position0[3] = (u8)(0xFF & (loopStart));
234 aiffinfo->mark.ch0[0] = 0x08;
235 aiffinfo->mark.ch0[1] = 'b';
236 aiffinfo->mark.ch0[2] = 'e';
237 aiffinfo->mark.ch0[3] = 'g';
238 aiffinfo->mark.ch0[4] = ' ';
239 aiffinfo->mark.ch0[5] = 'l';
240 aiffinfo->mark.ch0[6] = 'o';
241 aiffinfo->mark.ch0[7] = 'o';
242 aiffinfo->mark.ch0[8] = 'p';
243 aiffinfo->mark.ch0[9] = 0;
244 aiffinfo->mark.id1[0] = 0;
245 aiffinfo->mark.id1[1] = 1;
246 aiffinfo->mark.position1[0] = (u8)(0xFF & (loopEnd >> 24));
247 aiffinfo->mark.position1[1] = (u8)(0xFF & (loopEnd >> 16));
248 aiffinfo->mark.position1[2] = (u8)(0xFF & (loopEnd >> 8));
249 aiffinfo->mark.position1[3] = (u8)(0xFF & (loopEnd));
250 aiffinfo->mark.ch1[0] = 0x08;
251 aiffinfo->mark.ch1[1] = 'e';
252 aiffinfo->mark.ch1[2] = 'n';
253 aiffinfo->mark.ch1[3] = 'd';
254 aiffinfo->mark.ch1[4] = ' ';
255 aiffinfo->mark.ch1[5] = 'l';
256 aiffinfo->mark.ch1[6] = 'o';
257 aiffinfo->mark.ch1[7] = 'o';
258 aiffinfo->mark.ch1[8] = 'p';
259 aiffinfo->mark.ch1[9] = 0;
260 }
261
262
263 /*---------------------------------------------------------------------------*
264 Name: aiffWriteMark
265
266 Description: output an instrument chunk and a marker chunk.
267
268 Arguments: aiffinfo pointer of an AIFFINFO structure.
269 outfile pointer of a FILE object.
270
271 Returns: none.
272 *---------------------------------------------------------------------------*/
273
aiffWriteMark(AIFFINFO * aiffinfo,FILE * outfile)274 void aiffWriteMark(AIFFINFO *aiffinfo, FILE *outfile)
275 {
276 fwrite(&aiffinfo->inst, sizeof(AIFFINST), 1, outfile);
277 fwrite(&aiffinfo->mark, sizeof(AIFFMARK), 1, outfile);
278 }
279
280
281 /*---------------------------------------------------------------------------*
282 Name: aiffReadHeader
283
284 Description: get & parse an Aiff file header.
285
286 Arguments: aiffinfo pointer of an AIFFINFO structure.
287 infile pointer of a FILE object.
288
289 Returns: none.
290 *---------------------------------------------------------------------------*/
291
aiffReadHeader(AIFFINFO * aiffinfo,FILE * infile)292 int aiffReadHeader
293 (
294 AIFFINFO *aiffinfo,
295 FILE *infile
296 )
297 {
298 u32 chunk, length, sample_position;
299
300 if (0 != fseek(infile, 0, SEEK_SET))
301 {
302 return FALSE;
303 }
304
305 fread(&chunk, 1, sizeof(u32), infile);
306 if (chunk != *str_form)
307 {
308 return FALSE;
309 }
310
311 fread(&length, 1, sizeof(u32), infile);
312 fread(&chunk, 1, sizeof(u32), infile);
313
314 if (chunk != *str_aiff)
315 {
316 return FALSE;
317 }
318
319 fread(&chunk, 1, sizeof(u32), infile);
320
321 if (chunk != *str_comm)
322 {
323 return FALSE;
324 }
325
326 fread(&length, 1, sizeof(u32), infile);
327
328 fread(&aiffinfo->comm.channels, 1, sizeof(u16), infile);
329 fread(&aiffinfo->comm.samples, 1, sizeof(u32), infile);
330 fread(&aiffinfo->comm.bitsPerSample, 1, sizeof(u16), infile);
331 fread(&aiffinfo->comm.samplesPerSec[0], 10, sizeof(u8), infile);
332
333 length = reverse_endian_32(length);
334 length = 18 - length;
335
336 if (length)
337 {
338 fseek(infile, length, SEEK_CUR);
339 }
340
341 // initialize loop markers to 0
342 aiffinfo->mark.position0[0] =
343 aiffinfo->mark.position0[1] =
344 aiffinfo->mark.position0[2] =
345 aiffinfo->mark.position0[3] =
346 aiffinfo->mark.position1[0] =
347 aiffinfo->mark.position1[1] =
348 aiffinfo->mark.position1[2] =
349 aiffinfo->mark.position1[3] = 0;
350
351 // get the read position up to the sample data, that's what the
352 // caller is expecting.. I know...
353 while (fread(&chunk, 1, sizeof(u32), infile) == 4)
354 {
355 u16 count;
356 u32 i;
357
358 // length of chunk
359 fread(&length, 1, sizeof(u32), infile);
360 length = reverse_endian_32(length);
361
362 if (feof(infile))
363 {
364 break;
365 }
366
367 switch (chunk)
368 {
369 case CHUNK_SSND:
370
371 // first 8 bytes of samples are garbage
372 fread(&chunk, 1, sizeof(u32), infile);
373 fread(&chunk, 1, sizeof(u32), infile);
374
375 // save the position because we are going to go look for a loop markers
376 sample_position = ftell(infile);
377 fseek(infile, length - 8, SEEK_CUR);
378
379 break;
380
381 case CHUNK_MARK:
382
383 fread(&count, 1, sizeof(u16), infile); // count, n markers
384 count = reverse_endian_16(count);
385 length -= 2;
386
387 i = 0;
388
389 while (count)
390 {
391 u16 id;
392 u32 position;
393 u8 ch;
394
395 fread(&id, 1, sizeof(u16), infile);
396 fread(&position, 1, sizeof(u32), infile);
397
398 id = reverse_endian_16(id);
399 position = reverse_endian_32(position);
400
401 switch (i)
402 {
403 case 0:
404
405 aiffinfo->mark.position0[0] = (u8)(0xFF & (position >> 24));
406 aiffinfo->mark.position0[1] = (u8)(0xFF & (position >> 16));
407 aiffinfo->mark.position0[2] = (u8)(0xFF & (position >> 8));
408 aiffinfo->mark.position0[3] = (u8)(0xFF & position);
409 break;
410
411 case 1:
412
413 aiffinfo->mark.position1[0] = (u8)(0xFF & (position >> 24));
414 aiffinfo->mark.position1[1] = (u8)(0xFF & (position >> 16));
415 aiffinfo->mark.position1[2] = (u8)(0xFF & (position >> 8));
416 aiffinfo->mark.position1[3] = (u8)(0xFF & position);
417 break;
418 }
419
420 // skip pstring
421 fread(&ch, 1, sizeof(u8), infile);
422 fseek(infile, ch, SEEK_CUR);
423
424 if (ftell(infile) & 1)
425 {
426 fread(&ch, 1, sizeof(u8), infile);
427 }
428
429 count--;
430 i++;
431 }
432
433 break;
434
435 case CHUNK_INST:
436
437 {
438 u16 playmode;
439
440 // skip some stuff we don't care about
441 fseek(infile, 8, SEEK_CUR);
442 fread(&playmode, 1, sizeof(u16), infile);
443 playmode = reverse_endian_16(playmode);
444
445 if (playmode != 1)
446 {
447 aiffinfo->mark.position0[0] = 0;
448 aiffinfo->mark.position0[1] = 0;
449 aiffinfo->mark.position0[2] = 0;
450 aiffinfo->mark.position0[3] = 0;
451 aiffinfo->mark.position1[0] = 0;
452 aiffinfo->mark.position1[1] = 0;
453 aiffinfo->mark.position1[2] = 0;
454 aiffinfo->mark.position1[3] = 0;
455 }
456
457 fseek(infile, 10, SEEK_CUR);
458 }
459
460 break;
461
462 default:
463
464 fseek(infile, length, SEEK_CUR);
465
466 break;
467 }
468 }
469
470 // put the read position back to where the samples are
471 fseek(infile, sample_position, SEEK_SET);
472
473 return TRUE;
474 }
475
476
477 /*---------------------------------------------------------------------------*
478 Name: aiffGetChannels
479
480 Description: return num of channels.
481
482 Arguments: aiffinfo pointer of an AIFFINFO structure.
483
484 Returns: num of channels.
485 *---------------------------------------------------------------------------*/
486
aiffGetChannels(AIFFINFO * aiffinfo)487 int aiffGetChannels(AIFFINFO *aiffinfo)
488 {
489 return ((aiffinfo->comm.channels[0] << 8) |
490 (aiffinfo->comm.channels[1]));
491 }
492
493
494 /*---------------------------------------------------------------------------*
495 Name: aiffGetSampleRate
496
497 Description: return num of samples per 1 sec.
498
499 Arguments: aiffinfo pointer of an AIFFINFO structure.
500
501 Returns: num of samples per sec.
502 *---------------------------------------------------------------------------*/
503
aiffGetSampleRate(AIFFINFO * aiffinfo)504 int aiffGetSampleRate(AIFFINFO *aiffinfo)
505 {
506 unsigned long ieeeExponent;
507 unsigned long ieeeMantissaHi;
508
509 // FIXED: sign must be removed from exponent, NOT mantissa.
510
511 ieeeExponent = ((aiffinfo->comm.samplesPerSec[0] << 8) |
512 (aiffinfo->comm.samplesPerSec[1]));
513
514 ieeeMantissaHi = ((aiffinfo->comm.samplesPerSec[2] << 24) |
515 (aiffinfo->comm.samplesPerSec[3] << 16) |
516 (aiffinfo->comm.samplesPerSec[4] << 8) |
517 (aiffinfo->comm.samplesPerSec[5]));
518
519 ieeeExponent &= 0x7FFF; // remove sign bit
520
521 return (ieeeMantissaHi >> (16414 - ieeeExponent));
522 }
523
524
525 /*---------------------------------------------------------------------------*
526 Name: aiffGetSamples
527
528 Description: return num of samples.
529
530 Arguments: aiffinfo pointer of an AIFFINFO structure.
531
532 Returns: num of samples.
533 *---------------------------------------------------------------------------*/
534
aiffGetSamples(AIFFINFO * aiffinfo)535 int aiffGetSamples(AIFFINFO *aiffinfo)
536 {
537 return ((aiffinfo->comm.samples[0] << 24) |
538 (aiffinfo->comm.samples[1] << 16) |
539 (aiffinfo->comm.samples[2] << 8) |
540 (aiffinfo->comm.samples[3]));
541 }
542
543
544 /*---------------------------------------------------------------------------*
545 Name: aiffGetBitsPerSample
546
547 Description: return bit width per a sample.
548
549 Arguments: aiffinfo pointer of an AIFFINFO structure.
550
551 Returns: bit width per a sample.
552 *---------------------------------------------------------------------------*/
553
aiffGetBitsPerSample(AIFFINFO * aiffinfo)554 int aiffGetBitsPerSample(AIFFINFO *aiffinfo)
555 {
556 return ((aiffinfo->comm.bitsPerSample[0] << 8) |
557 (aiffinfo->comm.bitsPerSample[1]));
558 }
559
560
561 /*---------------------------------------------------------------------------*
562 Name: aiffGetLoopStart
563
564 Description: return a position of loop start.
565
566 Arguments: aiffinfo pointer of an AIFFINFO structure.
567
568 Returns: position of loop start.
569 *---------------------------------------------------------------------------*/
570
aiffGetLoopStart(AIFFINFO * aiffinfo)571 int aiffGetLoopStart(AIFFINFO *aiffinfo)
572 {
573 return ((aiffinfo->mark.position0[0] << 24) |
574 (aiffinfo->mark.position0[1] << 16) |
575 (aiffinfo->mark.position0[2] << 8) |
576 (aiffinfo->mark.position0[3]));
577 }
578
579
580 /*---------------------------------------------------------------------------*
581 Name: aiffGetLoopEnd
582
583 Description: return a position of loop end.
584
585 Arguments: aiffinfo pointer of an AIFFINFO structure.
586
587 Returns: position of loop end.
588 *---------------------------------------------------------------------------*/
589
aiffGetLoopEnd(AIFFINFO * aiffinfo)590 int aiffGetLoopEnd(AIFFINFO *aiffinfo)
591 {
592 return ((aiffinfo->mark.position1[0] << 24) |
593 (aiffinfo->mark.position1[1] << 16) |
594 (aiffinfo->mark.position1[2] << 8) |
595 (aiffinfo->mark.position1[3]));
596 }
597