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