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