1 /*--------------------------------------------------------------------------*
2   Project: Revolution DSP ADPCM encoder
3   File:    main.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: main.c,v $
14   Revision 1.2  02/09/2006 07:07:35  aka
15   Changed copyright.
16 
17 
18  *--------------------------------------------------------------------------*/
19 #include <stdio.h>
20 #include <string.h>
21 #include <windows.h>
22 #include "endian.h"
23 #include "dspadpcm.h"
24 #include "dspheader.h"
25 
26 #define MAX_PATH_SIZE   256
27 
28 u8 input_path  [MAX_PATH_SIZE]; // path to input file
29 u8 output_path [MAX_PATH_SIZE]; // path to output file
30 u8 coef_path   [MAX_PATH_SIZE]; // path to DSPADPCMHEADER text dump file
31 
32 FILE *input_file;
33 FILE *output_file;
34 FILE *coef_file;
35 
36 BOOL  loop_flag;                // TRUE if loop points were specified on command line
37 BOOL  encode_flag;              // TRUE for encoding
38 BOOL  decode_flag;              // TRUE for decoding
39 BOOL  coef_flag;                // TRUE for text dump of DSPADPCMHEADER to file
40 BOOL  verbose_flag;             // TRUE is user specified verbose mode
41 BOOL  ea_flag;                  // TRUE if user specified end address
42 
43 u32   loopStart;                // user specified loop start sample
44 u32   loopEnd;                  // user specified loop end sample
45 u32   sampleEndAddr;    // user specified end address
46 
47 #define DECODE_WAV  0
48 #define DECODE_AIFF 1
49 
50 u32 decodeFormat;               // user specified decode format
51 
52 
53 /*--------------------------------------------------------------------------*
54         dsptool DLL interface
55  *--------------------------------------------------------------------------*/
56 HINSTANCE hDllDsptool;
57 
58 typedef u32 (*lpFunc1)(u32);
59 typedef u32 (*lpFunc2)(void);
60 typedef void (*lpFunc3)(s16*, u8*, ADPCMINFO*, u32);
61 typedef void (*lpFunc4)(u8*, s16*, ADPCMINFO*, u32);
62 typedef void (*lpFunc5)(u8*, ADPCMINFO*, u32);
63 
64 lpFunc1 getBytesForAdpcmBuffer;
65 lpFunc1 getBytesForAdpcmSamples;
66 lpFunc1 getBytesForPcmBuffer;
67 lpFunc1 getBytesForPcmSamples;
68 lpFunc1 getNibbleAddress;
69 lpFunc1 getNibblesForNSamples;
70 lpFunc1 getSampleForAdpcmNibble;
71 lpFunc2 getBytesForAdpcmInfo;
72 lpFunc3 encode;
73 lpFunc4 decode;
74 lpFunc5 getLoopContext;
75 
76 
77 /*--------------------------------------------------------------------------*
78         soundfile DLL interface
79  *--------------------------------------------------------------------------*/
80 HINSTANCE hDllSoundfile;
81 
82 typedef int (*lpFunc6)(u8 *path, SOUNDINFO *soundinfo);
83 typedef int (*lpFunc7)(u8 *path, SOUNDINFO *soundinfo, void *dest);
84 typedef int (*lpFunc8)(char *path, SOUNDINFO *info, void *samples);
85 lpFunc6 getSoundInfo;
86 lpFunc7 getSoundSamples;
87 lpFunc8 writeWaveFile;
88 lpFunc8 writeAiffFile;
89 
90 
91 /*--------------------------------------------------------------------------*/
print_banner(void)92 void print_banner(void)
93 {
94 
95     printf("\n");
96     printf("DSPADPCM v2.3 - DSP-ADPCM encoder\n");
97     printf("Copyright 2001 Nintendo. All rights reserved.\n\n");
98 
99 } // end print_banner
100 
101 
102 /*--------------------------------------------------------------------------*/
print_usage(void)103 void print_usage(void)
104 {
105 
106     printf("\n");
107     printf("Usage:\n\n");
108     printf("DSPADPCM -<mode> <inputfile> [<outputfile>] [-opt<argument>]\n\n");
109     printf("Where:\n");
110     printf("   <mode>.............E for Encode, D for Decode (required)\n");
111     printf("   <inputfile>........Input file (required)\n");
112     printf("   [<outputfile>].....Output file (optional)\n\n");
113 
114     printf("Options are:\n");
115     printf("   -c<coeffile>.......Text dump of coefficients and other data\n");
116     printf("   -l<start-end>......Sound effect is looped; 'start' is first sample\n");
117     printf("                      in loop, counting from zero. 'end' is the last\n");
118     printf("                      sample in the loop, also counting from zero.\n");
119     printf("   -a<end addr>.......For non-looped sound effects; last sample in\n");
120     printf("                      the sound effect, counting from zero.\n");
121     printf("   -h.................This help text.\n");
122     printf("   -v.................Verbose mode.\n");
123     printf("   -f.................Decode to AIFF.\n");
124     printf("   -w.................Decode to WAV (default).\n");
125     printf("\n\n");
126     printf("This tool generates DSPADPCM data from MONO, 16-bit PCM WAV or AIFF\n");
127     printf("files. The DSPADPCM output file (*.dsp) has a %d byte data header \n", sizeof(DSPADPCMHEADER));
128     printf("which contains the ADPCM coefficients, loop context (if any), \n");
129     printf("and other sample info. The format of this header is described \n");
130     printf("in the DSPADPCM documentation.\n\n");
131 
132 } // end print_usage()
133 
134 
135 /*--------------------------------------------------------------------------*/
136 
init(void)137 void init(void)
138 {
139 
140     input_file          = NULL;
141     output_file         = NULL;
142     coef_file           = NULL;
143         decodeFormat    = DECODE_WAV;
144 
145     hDllDsptool     = NULL;
146     hDllSoundfile   = NULL;
147 
148 } // end init()
149 
150 
151 /*--------------------------------------------------------------------------*/
clean_up(void)152 void clean_up(void)
153 {
154 
155     if (input_file)             fclose(input_file);
156     if (output_file)    fclose(output_file);
157     if (coef_file)              fclose(coef_file);
158     if (hDllDsptool)    FreeLibrary(hDllDsptool);
159     if (hDllSoundfile)  FreeLibrary(hDllSoundfile);
160 
161 } // end clean_up()
162 
163 
164 /*--------------------------------------------------------------------------*/
165 
coefficients(u16 * p)166 void coefficients(u16 *p)
167 {
168     int i;
169 
170     for (i = 0; i < 16; i++)
171         printf("[%d]: 0x%04X\n", i, *p++ & 0xffff);
172 }
173 
174 
175 /*--------------------------------------------------------------------------
176  * findbase() - returns pointer to first character of file basename
177  *--------------------------------------------------------------------------*/
findbase(BYTE * string)178 BYTE *findbase(BYTE *string)
179 {
180 
181     BYTE *ptr = string;
182 
183         while (*ptr++); // find end of string
184 
185     while ((--ptr >= string) && (*ptr != '\\') && (*ptr != '/') && (*ptr != ':'));
186 
187     return(++ptr);
188 
189 } // end findbase()
190 
191 
192 /*--------------------------------------------------------------------------
193  * findext() - returns pointer to start of file extension (including '.')
194  *--------------------------------------------------------------------------*/
findext(BYTE * string)195 BYTE *findext(BYTE *string)
196 {
197 
198     BYTE *ptr;
199     BYTE *end;
200 
201     ptr = string;
202 
203     while (*ptr++); // find end of string
204 
205     end = ptr;
206 
207         while ((--ptr >= string) && (*ptr != '.'));
208 
209     if (ptr <= string)
210                 return(end);
211     else
212         return(ptr);
213 
214 } // end findext()
215 
216 
217 /*--------------------------------------------------------------------------
218  * parse_args() - parse the command line arguments
219  *--------------------------------------------------------------------------*/
parse_args(int argc,char * argv[])220 BOOL parse_args(int argc, char *argv[])
221 {
222     BOOL rval;
223     u16  i;
224 
225     if (argc < 2)
226     {
227         // must specify input file at least
228         printf("\nERROR: Missing parameter\n");
229 
230         print_usage();
231 
232         return(FALSE);
233     }
234 
235     rval         = TRUE;
236     loop_flag    = FALSE;
237     encode_flag  = FALSE;
238     decode_flag  = FALSE;
239     coef_flag    = FALSE;
240     verbose_flag = FALSE;
241     ea_flag      = FALSE;
242 
243     memset(input_path,   0x00, MAX_PATH_SIZE);
244     memset(output_path,  0x00, MAX_PATH_SIZE);
245     memset(coef_path,    0x00, MAX_PATH_SIZE);
246 
247     loopStart     = 0xFFFFFFFF;
248     loopEnd       = 0xFFFFFFFF;
249     sampleEndAddr = 0x00000000;
250 
251     for (i = 1; (i < argc) && (rval == TRUE); i++)
252     {
253         switch (argv[i][0])
254         {
255             case '?':
256                 // user is confused
257                 return(FALSE);
258 
259                 break;
260 
261             case '-':
262             case '/':
263 //            case '\\':
264 
265                 switch(argv[i][1])
266                 {
267                 case 'f':
268                 case 'F':
269 
270                     decodeFormat = DECODE_AIFF;
271 
272                     break;
273 
274                 case 'w':
275                 case 'W':
276 
277                     decodeFormat = DECODE_WAV;
278 
279                     break;
280 
281                     case 'e':
282                     case 'E':
283 
284                         if (TRUE == decode_flag)
285                         {
286                             // user already asserted decode mode
287                             printf("\nERROR: Decode flag already asserted!\n");
288                             rval = FALSE;
289                         }
290                         else
291                         {
292                             encode_flag = TRUE;
293                         }
294 
295                         break;
296 
297                     case 'D':
298                     case 'd':
299 
300                         if (TRUE == encode_flag)
301                         {
302                             // user already asserted encode mode
303                             printf("\nERROR: Encode flag already asserted!\n");
304                             rval = FALSE;
305                         }
306                         else
307                         {
308                             decode_flag = TRUE;
309                         }
310 
311                         break;
312 
313                     case 'l':
314                     case 'L':
315 
316                         loop_flag = TRUE;
317                         if (EOF == sscanf(&argv[i][2], "%d-%d", &loopStart, &loopEnd))
318                         {
319                             printf("\nERROR: Unable to parse loop points '%s'\n", &argv[i][2]);
320                             rval = FALSE;
321                         }
322 
323                         break;
324 
325                     case '?':
326                     case 'H':
327                     case 'h':
328 
329                         return(FALSE);
330 
331                         break;
332 
333                     case 'a':
334                     case 'A':
335 
336                         if (EOF == sscanf(&argv[i][2], "%d", &sampleEndAddr))
337                         {
338                             printf("\nERROR: Invalid sample end address.\n");
339                             rval = FALSE;
340                         }
341                         ea_flag = TRUE;
342 
343                         break;
344 
345                     case 'c':
346                     case 'C':
347 
348                         // specify coefficient output file
349                         if (argv[i][2])
350                         {
351                             strcpy(coef_path, &argv[i][2]);
352                         }
353                         coef_flag = TRUE;
354 
355                         break;
356 
357                     case 'v':
358                     case 'V':
359 
360                         verbose_flag = TRUE;
361 
362                         break;
363 
364                     default:
365 
366                         // unknown switch
367                         printf("\nERROR: Unknown switch '%c'\n", argv[i][1]);
368                         rval = FALSE;
369 
370                         break;
371 
372                 } // end switch
373 
374 
375                 break;
376 
377             default:
378 
379                 if (0 == input_path[0])
380                 {
381                     // input path not specified yet, so argument must be the input path
382                     strcpy(input_path, &argv[i][0]);
383                 }
384                 else if (0 == output_path[0])
385                 {
386                     // an input_path has been specified, so this must be the output
387                     strcpy(output_path, &argv[i][0]);
388                 }
389                 else
390                 {
391                     // unknown unswitched argument
392                     printf("\nERROR: Extraneous argument '%s'\n", argv[i]);
393                     rval = FALSE;
394                 }
395 
396                 break;
397 
398         } // end switch()
399     } // for...i
400 
401     // now perform sanity check
402     if (0 == input_path[0])
403     {
404         // no input file specified!
405         printf("\nERROR: No input file specified!\n");
406         rval = FALSE;
407     }
408 
409     if (0 == output_path[0])
410     {
411         // output path not specified yet, use default
412         strcpy(output_path, findbase(input_path));
413 
414         if (TRUE == decode_flag)
415         {
416                         if (decodeFormat != DECODE_AIFF)
417                         {
418                     // add default extension of '.wav'
419                         strcpy(findext(output_path), ".wav");
420                         }
421                         else
422                         {
423                     // add default extension of '.aif'
424                         strcpy(findext(output_path), ".aif");
425                         }
426         }
427         else if (TRUE == encode_flag)
428         {
429             // add default extension of '.dsp'
430             strcpy(findext(output_path), ".dsp");
431         }
432         else
433         {
434             printf("\nERROR: MODE directive not specified!\n");
435             rval = FALSE;
436         }
437     }
438 
439     if ((0 == coef_path[0]) && (coef_flag = TRUE))
440     {
441         // coefficient output path not specified, use default
442         strcpy(coef_path, findbase(input_path));
443 
444         // add default extension of '.txt'
445         strcpy(findext(coef_path), ".txt");
446     }
447 
448 #define ARAM_MAX_RANGE  0x4000000   // 64MB of ARAM - in my dreams
449 
450     if (TRUE == loop_flag)
451     {
452         if (loopStart > loopEnd)
453         {
454             printf("\nWARNING: loopStart is greater than loopEnd\n");
455         }
456 
457         if (loopStart > ARAM_MAX_RANGE)
458         {
459             printf("\nWARNING: loop-start is beyond valid ARAM range! (0x%08X)\n", loopStart);
460         }
461 
462         if (loopEnd > ARAM_MAX_RANGE)
463         {
464             printf("\nWARNING: loop=end is beyond valid ARAM range! (0x%08X)\n", loopEnd);
465         }
466 
467         if (TRUE == ea_flag)
468         {
469             printf("\nWARNING: '-a' argument ignored for looped sample.\n");
470         }
471     }
472 
473     if (sampleEndAddr > ARAM_MAX_RANGE)
474     {
475         printf("\nWARNING: sample-end address is beyond valid ARAM range! (0x%08X)\n", sampleEndAddr);
476     }
477 
478         if (verbose_flag)
479         {
480                 printf("\tinput file : '%s'\n", input_path);
481                 printf("\toutput file: '%s'\n", output_path);
482                 printf("\tcoef file  : '%s'\n", coef_path);
483                 printf("\n");
484         }
485 
486     // debug
487 /*
488         printf("\n****************************\n");
489 
490         printf("input_path : '%s'\n", input_path);
491         printf("output_path: '%s'\n", output_path);
492         printf("coef_path  : '%s'\n", coef_path);
493         printf("decode_path: '%s'\n", decode_path);
494 
495         printf("\n");
496 
497         printf("loopStart: %d\n", loopStart);
498         printf("loopEnd  : %d\n", loopEnd);
499 
500         printf("\n");
501 
502         printf("rval: %d\n", rval);
503 
504         //exit(0);
505 
506   */
507 
508     return(rval);
509 
510 } // end parse args
511 
512 
513 /*--------------------------------------------------------------------------
514  *      dump DSPHEADER to specified file
515  *--------------------------------------------------------------------------*/
dump_header(DSPADPCMHEADER * h,FILE * handle)516 void dump_header(DSPADPCMHEADER *h, FILE *handle)
517 {
518 
519     u16 i;
520     u16 j;
521 
522     fprintf(handle, "\n");
523 
524     fprintf(handle, "Header size: %d bytes\n\n", sizeof(DSPADPCMHEADER));
525 
526     fprintf(handle, "Sample     : '%s'\n", input_path);
527     fprintf(handle, "Length     : %d samples\n", reverse_endian_32(h->num_samples));
528     fprintf(handle, "Num nibbles: %d ADPCM nibbles\n", reverse_endian_32(h->num_adpcm_nibbles));
529 
530     fprintf(handle, "Sample Rate: %d Hz\n", reverse_endian_32(h->sample_rate));
531     fprintf(handle, "Loop Flag  : %s\n", VOICE_TYPE_LOOPED == reverse_endian_16(h->loop_flag) ? "LOOPED" : "NOT LOOPED");
532 
533     fprintf(handle, "\n");
534 
535     fprintf(handle, "Start Addr : 0x%08X + ARAM_offset (ADPCM nibble mode)\n", reverse_endian_32(h->sa));
536     fprintf(handle, "End Addr   : 0x%08X + ARAM_offset (ADPCM nibble mode)\n", reverse_endian_32(h->ea));
537     fprintf(handle, "Curr Addr  : 0x%08X + ARAM_offset (ADPCM nibble mode)\n", reverse_endian_32(h->ca));
538 
539     fprintf(handle, "\n");
540 
541     j = 0;
542     for (i=0; i<16; i+=2)
543     {
544         fprintf(handle, "a1[%d]: 0x%04X a2[%d]: 0x%04X \n", j, reverse_endian_16(h->coef[i]), j, reverse_endian_16(h->coef[i+1]));
545         j++;
546     }
547 
548     fprintf(handle, "\n");
549 
550     fprintf(handle, "Gain      : 0x%04X\n", reverse_endian_16(h->gain));
551     fprintf(handle, "Pred/Scale: 0x%04X\n", reverse_endian_16(h->ps));
552     fprintf(handle, "y[n-1]    : 0x%04X\n", reverse_endian_16(h->yn1));
553     fprintf(handle, "y[n-2]    : 0x%04X\n", reverse_endian_16(h->yn2));
554 
555     fprintf(handle, "\n");
556 
557     fprintf(handle, "Loop Pred/Scale: 0x%04X\n", reverse_endian_16(h->lps));
558     fprintf(handle, "Loop y[n-1]    : 0x%04X\n", reverse_endian_16(h->lyn1));
559     fprintf(handle, "Loop y[n-2]    : 0x%04X\n", reverse_endian_16(h->lyn2));
560 
561 } // end dump_header()
562 
563 
564 /*--------------------------------------------------------------------------*
565  *
566  *--------------------------------------------------------------------------*/
encode_soundfile(char * path,SOUNDINFO * soundinfo)567 void encode_soundfile(char *path, SOUNDINFO *soundinfo)
568 {
569     DSPADPCMHEADER dspadpcmheader;
570     ADPCMINFO adpcminfo;
571     void *soundbuffer, *outputbuffer;
572 
573     if (verbose_flag) printf(" Done.\nGetting sound samples...");
574 
575     soundbuffer     = malloc(soundinfo->bufferLength);
576     outputbuffer    = malloc(getBytesForAdpcmBuffer(soundinfo->samples));
577 
578     if (!soundbuffer || !outputbuffer)
579     {
580         if (soundbuffer)    free(soundbuffer);
581         if (outputbuffer)   free(outputbuffer);
582 
583         printf("Cannot allocate buffers for encode!\n");
584         return;
585     }
586 
587     memset(&dspadpcmheader, 0, sizeof(DSPADPCMHEADER));
588 
589     dspadpcmheader.num_samples          = reverse_endian_32(soundinfo->samples);
590     dspadpcmheader.num_adpcm_nibbles    = reverse_endian_32(getNibblesForNSamples(soundinfo->samples));
591     dspadpcmheader.sample_rate          = reverse_endian_32(soundinfo->sampleRate);
592 
593     // if the user specified loop points on the command line use them
594         // or else look for loop points in the adpcminfo
595     if (loop_flag)
596     {
597             u32 nibbleLoopStart, nibbleLoopEnd, nibbleCurrent;
598 
599                 nibbleLoopStart = getNibbleAddress(loopStart);
600                 nibbleLoopEnd   = getNibbleAddress(loopEnd);
601                 nibbleCurrent   = getNibbleAddress(0);
602 
603                 dspadpcmheader.loop_flag                = reverse_endian_16(VOICE_TYPE_LOOPED);
604                 dspadpcmheader.format                   = reverse_endian_16(DEC_MODE_ADPCM);
605         dspadpcmheader.sa                               = reverse_endian_32(nibbleLoopStart);
606         dspadpcmheader.ea                               = reverse_endian_32(nibbleLoopEnd);
607         dspadpcmheader.ca                               = reverse_endian_32(nibbleCurrent);
608     }
609         else if (soundinfo->loopEnd) // the sound info has loops form AIFF
610         {
611             u32 nibbleLoopStart, nibbleLoopEnd, nibbleCurrent;
612 
613                 nibbleLoopStart = getNibbleAddress(soundinfo->loopStart);
614         nibbleLoopEnd   = getNibbleAddress(soundinfo->loopEnd - 1); // AIFF loop end is 1 based
615                 nibbleCurrent   = getNibbleAddress(0);
616 
617                 dspadpcmheader.loop_flag                = reverse_endian_16(VOICE_TYPE_LOOPED);
618                 dspadpcmheader.format                   = reverse_endian_16(DEC_MODE_ADPCM);
619         dspadpcmheader.sa                               = reverse_endian_32(nibbleLoopStart);
620         dspadpcmheader.ea                               = reverse_endian_32(nibbleLoopEnd);
621         dspadpcmheader.ca                               = reverse_endian_32(nibbleCurrent);
622         }
623     else // not looped
624     {
625             u32 nibbleLoopStart, nibbleLoopEnd, nibbleCurrent;
626 
627                 nibbleLoopStart = getNibbleAddress(0);
628 
629                 // if the user specified end address use it
630                 if (ea_flag)
631                         nibbleLoopEnd   = getNibbleAddress(sampleEndAddr);
632                 else
633                         nibbleLoopEnd   = getNibbleAddress(soundinfo->samples - 1);
634 
635                 nibbleCurrent   = getNibbleAddress(0);
636 
637                 dspadpcmheader.loop_flag                = reverse_endian_16(VOICE_TYPE_NOTLOOPED);
638                 dspadpcmheader.format                   = reverse_endian_16(DEC_MODE_ADPCM);
639         dspadpcmheader.sa                               = reverse_endian_32(nibbleLoopStart);
640         dspadpcmheader.ea                               = reverse_endian_32(nibbleLoopEnd);
641         dspadpcmheader.ca                               = reverse_endian_32(nibbleCurrent);
642     }
643 
644     getSoundSamples(path, soundinfo, soundbuffer);
645 
646         if (verbose_flag) printf(" Done.\nEncoding samples...");
647 
648         encode(soundbuffer, outputbuffer, &adpcminfo, soundinfo->samples);
649 
650     // if the user specified loops get loop context
651         if (loop_flag)
652                 getLoopContext(outputbuffer, &adpcminfo, loopStart);
653         // see if the aiff file has loop points
654         else if (soundinfo->loopEnd)
655                 getLoopContext(outputbuffer, &adpcminfo, soundinfo->loopStart);
656         // no loop make sure loop context is 0
657         else
658                 adpcminfo.loop_pred_scale = adpcminfo.loop_yn1 = adpcminfo.loop_yn2 = 0;
659 
660     // put the adpcm info on the dsp_header
661     dspadpcmheader.coef[0]  = reverse_endian_16(adpcminfo.coef[0]);
662     dspadpcmheader.coef[1]  = reverse_endian_16(adpcminfo.coef[1]);
663     dspadpcmheader.coef[2]  = reverse_endian_16(adpcminfo.coef[2]);
664     dspadpcmheader.coef[3]  = reverse_endian_16(adpcminfo.coef[3]);
665     dspadpcmheader.coef[4]  = reverse_endian_16(adpcminfo.coef[4]);
666     dspadpcmheader.coef[5]  = reverse_endian_16(adpcminfo.coef[5]);
667     dspadpcmheader.coef[6]  = reverse_endian_16(adpcminfo.coef[6]);
668     dspadpcmheader.coef[7]  = reverse_endian_16(adpcminfo.coef[7]);
669     dspadpcmheader.coef[8]  = reverse_endian_16(adpcminfo.coef[8]);
670     dspadpcmheader.coef[9]  = reverse_endian_16(adpcminfo.coef[9]);
671     dspadpcmheader.coef[10] = reverse_endian_16(adpcminfo.coef[10]);
672     dspadpcmheader.coef[11] = reverse_endian_16(adpcminfo.coef[11]);
673     dspadpcmheader.coef[12] = reverse_endian_16(adpcminfo.coef[12]);
674     dspadpcmheader.coef[13] = reverse_endian_16(adpcminfo.coef[13]);
675     dspadpcmheader.coef[14] = reverse_endian_16(adpcminfo.coef[14]);
676     dspadpcmheader.coef[15] = reverse_endian_16(adpcminfo.coef[15]);
677     dspadpcmheader.gain     = reverse_endian_16(adpcminfo.gain);
678     dspadpcmheader.ps       = reverse_endian_16(adpcminfo.pred_scale);
679     dspadpcmheader.yn1      = reverse_endian_16(adpcminfo.yn1);
680     dspadpcmheader.yn2      = reverse_endian_16(adpcminfo.yn2);
681     dspadpcmheader.lps      = reverse_endian_16(adpcminfo.loop_pred_scale);
682     dspadpcmheader.lyn1     = reverse_endian_16(adpcminfo.loop_yn1);
683     dspadpcmheader.lyn2     = reverse_endian_16(adpcminfo.loop_yn2);
684 
685         if (verbose_flag) printf(" Done.\nWriting DSPADPCM file...");
686 
687     // write the output file
688     fwrite(&dspadpcmheader, 1, sizeof(DSPADPCMHEADER), output_file);
689     fwrite(outputbuffer, getBytesForAdpcmSamples(soundinfo->samples), sizeof(u8), output_file);
690 
691         if (coef_flag)
692         {
693                 if (verbose_flag) printf(" Done.\nWriting text dump file ...");
694                 dump_header(&dspadpcmheader, coef_file);
695         }
696 
697         if (verbose_flag) printf(" Done.\n");
698 }
699 
700 
701 /*--------------------------------------------------------------------------*
702  *
703  *--------------------------------------------------------------------------*/
encode_input_file(void)704 void encode_input_file(void)
705 {
706     SOUNDINFO       soundinfo;
707 
708         if (verbose_flag) printf("Getting sound header...");
709 
710     switch (getSoundInfo(input_path, &soundinfo))
711     {
712     case SOUND_FILE_SUCCESS:
713 
714         if (soundinfo.bitsPerSample != 16)
715         {
716             printf("Sound file buffer not 16bit samples!\n");
717             return;
718         }
719 
720         if (soundinfo.channels != 1)
721         {
722             printf("Soundfile buffer not mono!\n");
723             return;
724         }
725 
726         encode_soundfile(input_path, &soundinfo);
727 
728         break;
729 
730     case SOUND_FILE_FORMAT_ERROR:
731 
732         printf("Sound file format not supported!\n");
733 
734         return;
735 
736     case SOUND_FILE_FOPEN_ERROR:
737 
738         printf("fopen error for sound file!\n");
739 
740         return;
741     }
742 }
743 
744 
745 /*--------------------------------------------------------------------------*
746  *
747  *--------------------------------------------------------------------------*/
decode_input_file(void)748 void decode_input_file(void)
749 {
750         DSPADPCMHEADER dspadpcmheader;
751         u32     samples, sampleRate;
752         u8  *inputBuffer;
753     u16 *outputBuffer;
754 
755         if (verbose_flag) printf("Getting DSPADPCM header...");
756 
757         // get DSPADPCMHEADER
758         fread(&dspadpcmheader, 1, sizeof(DSPADPCMHEADER), input_file);
759 
760         samples         = reverse_endian_32(dspadpcmheader.num_samples);
761         sampleRate      = reverse_endian_32(dspadpcmheader.sample_rate);
762 
763         // allocate buffers
764         if (inputBuffer = malloc(getBytesForAdpcmSamples(samples)))
765         {
766                 if (verbose_flag) printf(" Done.\nGetting ADPCM samples...");
767 
768                 if (outputBuffer = malloc(samples * 2))
769                 {
770             SOUNDINFO soundinfo;
771             ADPCMINFO adpcminfo;
772 
773                         // prepare adpcminfo for decoding
774                         adpcminfo.coef[0]       = (s16)reverse_endian_16(dspadpcmheader.coef[0]);
775                         adpcminfo.coef[1]       = (s16)reverse_endian_16(dspadpcmheader.coef[1]);
776                         adpcminfo.coef[2]       = (s16)reverse_endian_16(dspadpcmheader.coef[2]);
777                         adpcminfo.coef[3]       = (s16)reverse_endian_16(dspadpcmheader.coef[3]);
778                         adpcminfo.coef[4]       = (s16)reverse_endian_16(dspadpcmheader.coef[4]);
779                         adpcminfo.coef[5]       = (s16)reverse_endian_16(dspadpcmheader.coef[5]);
780                         adpcminfo.coef[6]       = (s16)reverse_endian_16(dspadpcmheader.coef[6]);
781                         adpcminfo.coef[7]       = (s16)reverse_endian_16(dspadpcmheader.coef[7]);
782                         adpcminfo.coef[8]       = (s16)reverse_endian_16(dspadpcmheader.coef[8]);
783                         adpcminfo.coef[9]       = (s16)reverse_endian_16(dspadpcmheader.coef[9]);
784                         adpcminfo.coef[10]      = (s16)reverse_endian_16(dspadpcmheader.coef[10]);
785                         adpcminfo.coef[11]      = (s16)reverse_endian_16(dspadpcmheader.coef[11]);
786                         adpcminfo.coef[12]      = (s16)reverse_endian_16(dspadpcmheader.coef[12]);
787                         adpcminfo.coef[13]      = (s16)reverse_endian_16(dspadpcmheader.coef[13]);
788                         adpcminfo.coef[14]      = (s16)reverse_endian_16(dspadpcmheader.coef[14]);
789                         adpcminfo.coef[15]      = (s16)reverse_endian_16(dspadpcmheader.coef[15]);
790                         adpcminfo.gain          = reverse_endian_16(dspadpcmheader.gain);
791                         adpcminfo.pred_scale= 0;
792                         adpcminfo.yn1           = 0;
793                         adpcminfo.yn2           = 0;
794 
795                         // read adpcm samples into input buffer
796                         fread(inputBuffer, getBytesForAdpcmSamples(samples), sizeof(u8), input_file);
797 
798                         if (verbose_flag) printf(" Done.\nDecoding samples...");
799 
800                         // decode samples to buffer
801                         decode(
802                                 inputBuffer,
803                                 outputBuffer,
804                                 &adpcminfo,
805                                 samples
806                                 );
807 
808             soundinfo.bitsPerSample = 16;
809             soundinfo.bufferLength  = samples * 2;
810             soundinfo.channels      = 1;
811             soundinfo.sampleRate    = sampleRate;
812             soundinfo.samples       = samples;
813 
814             if (dspadpcmheader.loop_flag)
815             {
816                 soundinfo.loopStart = getSampleForAdpcmNibble(reverse_endian_32(dspadpcmheader.sa));
817                 soundinfo.loopEnd   = getSampleForAdpcmNibble(reverse_endian_32(dspadpcmheader.ea)) + 1;
818             }
819             else
820             {
821                 soundinfo.loopStart = 0;
822                 soundinfo.loopEnd   = 0;
823             }
824 
825                         if (verbose_flag) printf(" Done.\nWriting sound file...");
826 
827                 switch (decodeFormat)
828                         {
829                         case DECODE_WAV:
830 
831                 writeWaveFile(output_path, &soundinfo, outputBuffer);
832 
833                                 break;
834 
835                         case DECODE_AIFF:
836 
837                 writeAiffFile(output_path, &soundinfo, outputBuffer);
838 
839                 break;
840                         }
841                 }
842                 else
843                 {
844                         printf("\nERROR: Cannot allocate output buffer!\n");
845                         clean_up();
846                         exit(1);
847                 }
848         }
849         else
850         {
851                 printf("\nERROR: Cannot allocate input buffer!\n");
852                 clean_up();
853                 exit(1);
854         }
855 
856         // free buffers
857         if (inputBuffer)        free(inputBuffer);
858         if (outputBuffer)       free(outputBuffer);
859 
860         // see if we should write a coefficient file
861         if (coef_flag)
862         {
863                 if (verbose_flag) printf(" Done.\nWriting text dump file...");
864         dump_header(&dspadpcmheader, coef_file);
865         }
866         if (verbose_flag) printf(" Done.\n");
867 }
868 
869 
870 /*--------------------------------------------------------------------------*/
get_dll(void)871 int get_dll(void)
872 {
873     hDllDsptool = LoadLibrary("dsptool.dll");
874 
875     if (hDllDsptool)
876     {
877         getBytesForAdpcmBuffer  = (lpFunc1)GetProcAddress(hDllDsptool, "getBytesForAdpcmBuffer");
878         getBytesForAdpcmSamples = (lpFunc1)GetProcAddress(hDllDsptool, "getBytesForAdpcmSamples");
879         getBytesForPcmBuffer    = (lpFunc1)GetProcAddress(hDllDsptool, "getBytesForPcmBuffer");
880         getBytesForPcmSamples   = (lpFunc1)GetProcAddress(hDllDsptool, "getBytesForPcmSamples");
881         getNibbleAddress        = (lpFunc1)GetProcAddress(hDllDsptool, "getNibbleAddress");
882         getNibblesForNSamples   = (lpFunc1)GetProcAddress(hDllDsptool, "getNibblesForNSamples");
883         getSampleForAdpcmNibble = (lpFunc1)GetProcAddress(hDllDsptool, "getSampleForAdpcmNibble");
884         getBytesForAdpcmInfo    = (lpFunc2)GetProcAddress(hDllDsptool, "getBytesForAdpcmInfo");
885         encode                  = (lpFunc3)GetProcAddress(hDllDsptool, "encode");
886         decode                  = (lpFunc4)GetProcAddress(hDllDsptool, "decode");
887         getLoopContext          = (lpFunc5)GetProcAddress(hDllDsptool, "getLoopContext");
888 
889         if (
890             !getBytesForAdpcmBuffer     ||
891             !getBytesForAdpcmSamples    ||
892             !getBytesForPcmBuffer       ||
893             !getBytesForPcmSamples      ||
894             !getNibbleAddress           ||
895             !getNibblesForNSamples      ||
896             !getSampleForAdpcmNibble    ||
897             !getBytesForAdpcmInfo       ||
898             !encode                     ||
899             !decode                     ||
900             !getLoopContext
901             ) return FALSE;
902     }
903 
904     hDllSoundfile = LoadLibrary("soundfile.dll");
905 
906     if (hDllSoundfile)
907     {
908         getSoundInfo            = (lpFunc6)GetProcAddress(hDllSoundfile, "getSoundInfo");
909         getSoundSamples         = (lpFunc7)GetProcAddress(hDllSoundfile, "getSoundSamples");
910         writeWaveFile           = (lpFunc8)GetProcAddress(hDllSoundfile, "writeWaveFile");
911         writeAiffFile           = (lpFunc8)GetProcAddress(hDllSoundfile, "writeAiffFile");
912 
913         if (
914             !getSoundInfo       ||
915             !getSoundSamples    ||
916             !writeWaveFile      ||
917             !writeAiffFile
918             ) return FALSE;
919     }
920 
921     if (hDllDsptool && hDllSoundfile)
922     {
923         return TRUE;
924     }
925     else
926     {
927         return FALSE;
928     }
929 }
930 
931 
932 /*--------------------------------------------------------------------------*
933  * main()
934  *--------------------------------------------------------------------------*/
main(int argc,char * argv[])935 int main(int argc, char *argv[])
936 {
937     init();
938     print_banner();
939 
940     if (FALSE == parse_args(argc, argv))
941     {
942         // don't print usage help, it just adds more junk to
943         // log files. print usage only for missing parameters or explicit
944         // requests for help.
945         exit(1);
946     }
947 
948     // load the dspadpcm.dll
949     if (FALSE == get_dll())
950     {
951         printf("\nERROR: Failed to load dll\n");
952         exit(1);
953     }
954 
955         // open files
956         if ((input_file = fopen(input_path, "rb")) == NULL)
957         {
958                 printf("\nERROR: Cannot open %s for reading!\n", input_path);
959                 clean_up();
960                 exit(1);
961         }
962 
963         if ((output_file = fopen(output_path, "wb")) == NULL)
964         {
965                 printf("\nERROR: Cannot open %s for writing!\n", output_path);
966                 clean_up();
967                 exit(1);
968         }
969 
970         if (coef_path)
971         {
972                 if ((coef_file = fopen(coef_path, "w")) == NULL)
973                 {
974                         printf("\nERROR: Cannot open %s for writing!\n", coef_path);
975                         clean_up();
976                         exit(1);
977                 }
978         }
979 
980     // encode or decode
981     if (encode_flag)
982         encode_input_file();
983 
984     if (decode_flag)
985         decode_input_file();
986 
987     // clean up
988     clean_up();
989 
990     // exit with a clean bill of health
991     exit(0);
992 
993 } // end main()
994