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