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