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