1 /*--------------------------------------------------------------------------*
2 Project: Revolution Audio sound file converter
3 File: sndconv.c
4
5 Copyright (C)1998-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: sndconv.c,v $
14 Revision 1.2.40.1 2008/12/18 01:03:41 aka
15 Copied from HEAD.
16
17 Revision 1.3 2008/10/17 01:33:23 aka
18 Changed location of soundSetDefaultFormat() in main().
19
20 Revision 1.2 2006/02/09 06:26:26 aka
21 Changed copyright.
22
23
24 *--------------------------------------------------------------------------*/
25 #include <windows.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include "soundconv.h"
29
30 static int state;
31 static int line;
32 static char seps[] = " ,\t\n";
33
34 static char *inputPath;
35 static char path[1024];
36 static char error[1024];
37
38 HINSTANCE hDllSoundfile;
39 HINSTANCE hDllDsptool;
40
41
42 /*--------------------------------------------------------------------------*
43 absolutePath()
44
45 - changes '/' to '\\' to handle paths from bash
46 *--------------------------------------------------------------------------*/
absolutePath(char * token)47 int absolutePath(char *token)
48 {
49 if ((strchr(token, ':')) || (*token == '\\'))
50 return 1;
51
52 return 0;
53 }
54
55
56 /*--------------------------------------------------------------------------*
57 fixString()
58
59 - changes '/' to '\\' to handle paths from bash
60 *--------------------------------------------------------------------------*/
fixString(char * ch)61 void fixString(char *ch)
62 {
63 while(*ch)
64 {
65 if (*ch == '/')
66 *ch = '\\';
67
68 ch++;
69 }
70 }
71
72
73 /*--------------------------------------------------------------------------*
74 parsePathStatement()
75
76 - parse for path to set
77 - copy the string for later use
78 *--------------------------------------------------------------------------*/
parsePathStatement(void)79 void parsePathStatement(void)
80 {
81 char *token;
82
83 if (token = strtok(NULL, seps))
84 {
85 if (token[0] != ';')
86 {
87 // save the path for file accessing
88 strcpy(path, token);
89 fixString(path);
90 // printf("Setting path to %s\n", token);
91 return;
92 }
93 }
94
95 printf("%cError! Incomplete PATH statement on line %d.\n", 7, line);
96 }
97
98
99 /*--------------------------------------------------------------------------*
100 parseBeginStatement()
101
102 - check for end state
103 - parse for sound id
104 - set sound id in sound.c
105 - set state flag to begin
106 *--------------------------------------------------------------------------*/
parseBeginStatement(void)107 void parseBeginStatement(void)
108 {
109 char *token;
110
111 if (state == STATE_BEGIN)
112 printf("%cWarning! BEGIN statement made prior to END on line %d.\n", 7, line);
113
114 if (token = strtok(NULL, seps))
115 {
116 if (token[0] != ';')
117 {
118 soundInitParams();
119 soundSetIdString(token);
120 // printf("Begin sound id %s\n", token);
121 state = STATE_BEGIN;
122
123 return;
124 }
125 }
126
127 printf("%cError! Incomplete BEGIN statement on line %d.\n", 7, line);
128 }
129
130
131 /*--------------------------------------------------------------------------*
132 parseFileStatement()
133
134 - parse for sound file path
135 - set sound file path in sound.c
136 *--------------------------------------------------------------------------*/
parseFileStatement(void)137 void parseFileStatement(void)
138 {
139 char *token;
140
141 if (token = strtok(NULL, seps))
142 {
143 if (token[0] != ';')
144 {
145 fixString(token);
146
147 if (absolutePath(token))
148 {
149 soundSetSoundFile(token);
150 }
151 else if (path[0] != 0)
152 {
153 char ch[1024];
154
155 strcpy(ch, path);
156 strcat(ch, "\\");
157 strcat(ch, token);
158 soundSetSoundFile(ch);
159 }
160 else
161 {
162 soundSetSoundFile(token);
163 }
164
165 // printf("\tSound file %s\n", token);
166 return;
167 }
168 }
169
170 printf("%cError! Incomplete FILE statement on line %d.\n", 7, line);
171 }
172
173 /*--------------------------------------------------------------------------*
174 parseOutputStatment()
175
176 - parse output mode
177 - set flag in sound.c
178 *--------------------------------------------------------------------------*/
parseOutputStatement(void)179 void parseOutputStatement(void)
180 {
181 char *token;
182
183 if (token = strtok(NULL, seps))
184 {
185 if (token[0] != ';')
186 {
187 strupr(token);
188
189 if (strcmp(token, "ADPCM") == 0)
190 soundSetFormat(SOUND_FORMAT_ADPCM);
191 else if (strcmp(token, "8BIT") == 0)
192 soundSetFormat(SOUND_FORMAT_PCM8);
193 else if (strcmp(token, "16BIT") == 0)
194 soundSetFormat(SOUND_FORMAT_PCM16);
195 else
196 printf("%cWarning! Invalid token \"%s\" on line %d.\n", 7, token, line);
197
198 // printf("\tOutput %s\n", token);
199 return;
200 }
201 }
202
203 printf("%cError! Incomplete OUTPUT statement on line %d.\n", 7, line);
204 }
205
206
207 /*--------------------------------------------------------------------------*
208 parseSampleRateStatement()
209
210 - parse sample rate
211 - set sample rate in sound.c
212 *--------------------------------------------------------------------------*/
parseSamplerateStatement(void)213 void parseSamplerateStatement(void)
214 {
215 char *token;
216
217 if (token = strtok(NULL, seps))
218 {
219 if (token[0] != ';')
220 {
221 int i = atoi(token);
222
223 // printf("\tSample rate %d\n", i);
224
225 soundSetSampleRate(i);
226
227 return;
228 }
229 }
230
231 printf("%cError! Incomplete SAMPLERATE statement on line %d.\n", 7, line);
232 }
233
234
235 /*--------------------------------------------------------------------------*
236 parseLoopStatement()
237
238 - parse loop start and end
239 - set loop pointes in sound.c
240 *--------------------------------------------------------------------------*/
parseLoopStatement(void)241 void parseLoopStatement(void)
242 {
243 char *token;
244 int loopStart, loopEnd;
245
246 if (token = strtok(NULL, seps))
247 {
248 if (token[0] != ';')
249 {
250 loopStart = atoi(token);
251
252 if (token = strtok(NULL, seps))
253 {
254 if (token[0] != ';')
255 {
256 loopEnd = atoi(token);
257
258 // printf("\tLoop %d %d\n", loopStart, loopEnd);
259
260 soundSetLoopStart(loopStart);
261 soundSetLoopEnd(loopEnd);
262
263 return;
264 }
265 }
266 }
267 }
268
269 printf("%cError! Incomplete LOOP statement on line %d.\n", 7, line);
270 }
271
272
273 /*--------------------------------------------------------------------------*
274 parseMixStatement()
275
276 - parse mix
277 - set the output mix flag in sound.c
278 *--------------------------------------------------------------------------*/
parseMixStatement(void)279 void parseMixStatement(void)
280 {
281 char *token;
282
283 if (token = strtok(NULL, seps))
284 {
285 if (token[0] != ';')
286 {
287 strupr(token);
288
289 if (strcmp(token, "COMBINE") == 0)
290 soundSetMix(SOUND_STEREO_COMBINE);
291 else if (strcmp(token, "LEFT") == 0)
292 soundSetMix(SOUND_STEREO_LEFT);
293 else if (strcmp(token, "RIGHT") == 0)
294 soundSetMix(SOUND_STEREO_RIGHT);
295 else
296 printf("%cWarning! Invalid token \"%s\" on line %d.\n", 7, token, line);
297
298 // printf("\tMix %s\n", token);
299 return;
300 }
301 }
302
303 printf("%cError! Incomplete MIX statement on line %d.\n", 7, line);
304 }
305
306
307 /*--------------------------------------------------------------------------*
308 parseCommentStatement()
309
310 - parse comment
311 - write comment to output header file
312 *--------------------------------------------------------------------------*/
parseCommentStatement(void)313 void parseCommentStatement(void)
314 {
315 char *token;
316 char ch[1024];
317
318 sprintf(ch, "// ");
319
320 if (token = strtok(NULL, ""))
321 strcat(ch, token);
322
323 if (ch[strlen(ch) - 1] != '\n')
324 strcat(ch, "\n");
325
326 soundOutputComment(ch);
327 // printf("%s", ch);
328 }
329
330
331 /*--------------------------------------------------------------------------*
332 parseEndStatement()
333
334 - print sound to data file
335 - add entry for sound
336 - set state falg to end
337 *--------------------------------------------------------------------------*/
parseEndStatement(void)338 void parseEndStatement(void)
339 {
340 char *token;
341
342 if (state == STATE_END)
343 printf("%cWarning! END statement made prior to BEGIN on line %d.\n", 7, line);
344
345 if (soundPrintSound() != STATUS_SUCCESS)
346 printf("%cError! Sound not converted on line %d.\n", 7, line);
347
348 // printf("End sound\n");
349 printf(".");
350
351 if (token = strtok(NULL, seps))
352 {
353 if (token[0] == ';')
354 return;
355
356 printf("%cWarning! Unexpected token \"%s\" after END statement on line %d.\n", 7, token, line);
357 }
358
359 state = STATE_END;
360 }
361
362
363 /*--------------------------------------------------------------------------*
364 parseIncludeStatement()
365
366 - get file path to include
367 - eat the file
368 *--------------------------------------------------------------------------*/
369 int eatFile(char *ch);
parseIncludeStatement(void)370 void parseIncludeStatement(void)
371 {
372 char *token;
373
374 if (token = strtok(NULL, seps))
375 {
376 if (token[0] != ';')
377 {
378 int tempLine = line;
379 line = 1;
380
381 fixString(token);
382
383 if (absolutePath(token))
384 {
385 eatFile(token);
386 }
387 else if (path[0] != 0)
388 {
389 char ch[1024];
390
391 strcpy(ch, path);
392 strcat(ch, "\\");
393 strcat(ch, token);
394 eatFile(ch);
395 }
396 else
397 {
398 eatFile(token);
399 }
400
401 line = tempLine;
402
403 // printf("\tInclude file %s\n", token);
404
405 return;
406 }
407 }
408
409 printf("%cError! Incomplete INCLUDE statement on line %d.\n", 7, line);
410 }
411
412
413 /*--------------------------------------------------------------------------*
414 parseLine()
415
416 - parse line for command
417 *--------------------------------------------------------------------------*/
parseLine(char * ch)418 void parseLine(char *ch)
419 {
420 char *token = strtok(ch, seps);
421
422 while(token != NULL)
423 {
424 if (token[0] == ';')
425 break;
426
427 // convert string to all upper case
428 _strupr(token);
429
430 // see what the command is
431 if (strcmp(token, "PATH") == 0)
432 {
433 parsePathStatement();
434 }
435 else if (strcmp(token, "BEGIN") == 0)
436 {
437 parseBeginStatement();
438 }
439 else if (strcmp(token, "FILE") == 0)
440 {
441 parseFileStatement();
442 }
443 else if (strcmp(token, "OUTPUT") == 0)
444 {
445 parseOutputStatement();
446 }
447 else if (strcmp(token, "SAMPLERATE") == 0)
448 {
449 parseSamplerateStatement();
450 }
451 else if (strcmp(token, "LOOP") == 0)
452 {
453 parseLoopStatement();
454 }
455 else if (strcmp(token, "MIX") == 0)
456 {
457 parseMixStatement();
458 }
459 else if (strcmp(token, "END") == 0)
460 {
461 parseEndStatement();
462 }
463 else if (strcmp(token, "COMMENT") == 0)
464 {
465 parseCommentStatement();
466 }
467 else if (strcmp(token, "INCLUDE") == 0)
468 {
469 parseIncludeStatement();
470
471 // since this cause other strtok() to be called
472 // for other instances of file reads... we better reset
473 // the strtok by doing a read from the start of this string
474 strtok(ch, seps);
475 strtok(NULL, seps);
476 }
477 else
478 {
479 printf("%c\nWarning unknown token \"%s\" on line number %d!!!\n",
480 7, token, line);
481 }
482
483 token = strtok(NULL, seps);
484 }
485 }
486
487
488 /*--------------------------------------------------------------------------*
489 nextLine()
490
491 - get next line from file
492 - parse line
493 *--------------------------------------------------------------------------*/
nextLine(FILE * file)494 int nextLine(FILE *file)
495 {
496 int status;
497 char ch[256];
498
499 if (fgets(ch, 256, file))
500 {
501 parseLine(ch);
502 status = STATUS_SUCCESS;
503 }
504 else
505 {
506 if (feof(file) == 0)
507 status = STATUS_ERROR;
508 else
509 status = STATUS_EOF;
510 }
511
512 return status;
513 }
514
515
516 /*--------------------------------------------------------------------------*
517 satFile()
518
519 - read file by line
520 - send lines to parsor
521 *--------------------------------------------------------------------------*/
eatFile(char * s)522 int eatFile(char *s)
523 {
524 FILE *file;
525 int status = STATUS_ERROR;
526
527 if (file = fopen(s, "r"))
528 {
529 do
530 {
531 status = nextLine(file);
532 line++;
533 }
534 while (status == STATUS_SUCCESS);
535
536 switch (status)
537 {
538 case STATUS_EOF:
539
540 // printf("\n\nEnd of script file %s reached.\n", s);
541
542 break;
543
544 case STATUS_ERROR:
545
546 printf("%c\n\nError encountered while reading file, line %d!\n", 7, line);
547
548 break;
549 }
550
551 fclose(file);
552 }
553 else
554 {
555 printf("%c\nError, cannot open %s for reading!!!\n", 7, s);
556 }
557
558 return status;
559 }
560
561
562 /*--------------------------------------------------------------------------*
563 printBanner()
564 *--------------------------------------------------------------------------*/
printBanner(void)565 void printBanner(void)
566 {
567 printf("\n");
568 printf("sndconv.exe v1.2\n");
569 printf("Sound converter for Dolphin AX sound player.\n");
570 printf("Copyright 2001 Nintendo Technology Development, Inc.\n");
571 printf("\n");
572 }
573
574
575 /*--------------------------------------------------------------------------*
576 printUsage()
577 *--------------------------------------------------------------------------*/
printUsage(void)578 void printUsage(void)
579 {
580 printf("Usage:\n\n");
581 printf("SNDCONV <inputfile> [-option]\n");
582 printf("Where:\n");
583 printf(" <scriptfile>.......Script file (required)\n\n");
584
585 printf("Options are:\n");
586 printf(" -a.................Default output to ADPCM\n");
587 printf(" -w.................Default output to 16bit PCM\n");
588 printf(" -b.................Default output to 8bit PCM\n");
589 printf(" -h.................This help text.\n");
590 // printf(" -v.................Verbose mode.\n");
591 printf("\n\n");
592 printf("This tool generates data files for AX SP library.\n");
593
594 printf("\n");
595 }
596
597
598 /*--------------------------------------------------------------------------*
599 cleanup()
600
601 - quit output code module
602 - free libraries
603 *--------------------------------------------------------------------------*/
cleanup(void)604 void cleanup(void)
605 {
606 soundOutputQuit();
607
608 if (hDllSoundfile) FreeLibrary(hDllSoundfile);
609 if (hDllDsptool) FreeLibrary(hDllDsptool);
610 }
611
612
613 /*--------------------------------------------------------------------------*
614 loadDlls()
615
616 - load soundfile.dll and dsptool.dll
617 - get export function pointers
618 *--------------------------------------------------------------------------*/
619 // soundfile.dll exports
620 typedef int (*FUNCTION1)(u8 *path, SOUNDINFO *soundinfo);
621 typedef int (*FUNCTION2)(u8 *path, SOUNDINFO *soundinfo, void *dest);
622 FUNCTION1 getSoundInfo;
623 FUNCTION2 getSoundSamples;
624
625 // dsptool.dll exports
626 typedef void (*FUNCTION3)(u16*, u8*, ADPCMINFO*, int);
627 typedef int (*FUNCTION4)(int);
628 typedef void (*FUNCTION5)(u8 *src, ADPCMINFO *cxt, u32 samples);
629 FUNCTION3 encode;
630 FUNCTION4 getBytesForAdpcmBuffer;
631 FUNCTION4 getBytesForAdpcmSamples;
632 FUNCTION4 getNibbleAddress;
633 FUNCTION5 getLoopContext;
634
635
loadDlls(void)636 int loadDlls(void)
637 {
638 getSoundInfo = NULL;
639 getSoundSamples = NULL;
640 encode = NULL;
641 getBytesForAdpcmBuffer = NULL;
642
643 if (hDllSoundfile = LoadLibrary("soundfile.dll"))
644 {
645 getSoundInfo = (FUNCTION1)GetProcAddress(hDllSoundfile, "getSoundInfo");
646 getSoundSamples = (FUNCTION2)GetProcAddress(hDllSoundfile, "getSoundSamples");
647 }
648
649 if (hDllDsptool = LoadLibrary("dsptool.dll"))
650 {
651 encode = (FUNCTION3)GetProcAddress(hDllDsptool, "encode");
652 getBytesForAdpcmBuffer = (FUNCTION4)GetProcAddress(hDllDsptool, "getBytesForAdpcmBuffer");
653 getBytesForAdpcmSamples = (FUNCTION4)GetProcAddress(hDllDsptool, "getBytesForAdpcmSamples");
654 getNibbleAddress = (FUNCTION4)GetProcAddress(hDllDsptool, "getNibbleAddress");
655 getLoopContext = (FUNCTION5)GetProcAddress(hDllDsptool, "getLoopContext");
656 }
657
658 if (getSoundInfo && getSoundSamples && encode && getBytesForAdpcmBuffer && getNibbleAddress)
659 return STATUS_SUCCESS;
660
661 printf("\n%cError loading DLL\n", 7);
662
663 return STATUS_ERROR;
664 }
665
666
667 /*--------------------------------------------------------------------------*
668 init()
669
670 - initialize output code module
671 *--------------------------------------------------------------------------*/
init(char * s)672 int init(char *s)
673 {
674 char ch[1024];
675 char *dot;
676
677 // make a copy of the path
678 strcpy(ch, s);
679
680 // check string for forward slash
681 fixString(ch);
682
683 // terminate the path at the last dot
684 if (dot = strrchr(ch, '.'))
685 *dot = 0;
686
687 // initialize the output module with the new path
688 if (soundOutputInit(ch) == STATUS_ERROR)
689 {
690 return STATUS_ERROR;
691 }
692 else
693 {
694 // some local variables
695 line = 1;
696 state = STATE_END;
697 path[0] = 0;
698
699 return loadDlls();
700 }
701 }
702
703
704 /*--------------------------------------------------------------------------*
705 parseArgs()
706
707 - check number of arguments
708 - parse commandline
709 - set default output format and input file path
710 *--------------------------------------------------------------------------*/
parseArgs(int argc,char * argv[])711 int parseArgs(int argc, char *argv[])
712 {
713 int i;
714
715 if (argc < 2)
716 {
717 printf("\nERROR: Missing parameter\n\n");
718
719 return FALSE;
720 }
721
722 for (i = 1; i < argc; i++)
723 {
724 switch (argv[i][0])
725 {
726 case '?':
727
728 return FALSE;
729
730 break;
731
732 case '-':
733 case '/':
734 case '\\':
735
736 switch (argv[i][1])
737 {
738 case 'a':
739 case 'A':
740
741 soundSetDefaultFormat(SOUND_FORMAT_ADPCM);
742
743 break;
744
745 case 'w':
746 case 'W':
747
748 soundSetDefaultFormat(SOUND_FORMAT_PCM16);
749
750 break;
751
752 case 'b':
753 case 'B':
754
755 soundSetDefaultFormat(SOUND_FORMAT_PCM8);
756
757 break;
758
759 case 'h':
760 case 'H':
761
762 return FALSE;
763
764 break;
765
766 default:
767
768 printf("\n%cERROR: Unknown switch '%c'\n\n", 7, argv[i][1]);
769 return FALSE;
770
771 break;
772 }
773
774 break;
775
776 default:
777
778 inputPath = argv[i];
779
780 break;
781 }
782 }
783
784 if (inputPath == NULL)
785 {
786 printf("\nERROR: No input file specified!\n\n");
787 return FALSE;
788 }
789
790 return TRUE;
791 }
792
793 /*--------------------------------------------------------------------------*
794 main()
795
796 - print program banner
797 - check arguments
798 - eat script file
799 *--------------------------------------------------------------------------*/
main(int argc,char * argv[])800 int main(int argc, char *argv[])
801 {
802 int status;
803
804 printBanner();
805
806 soundSetDefaultFormat(SOUND_FORMAT_ADPCM);
807
808 if (parseArgs(argc, argv))
809 {
810 if (init(inputPath) == STATUS_SUCCESS)
811 {
812 path[0] = 0;
813 status = eatFile(inputPath);
814 printf("\n");
815 }
816 else
817 {
818 status = STATUS_ERROR;
819 }
820 }
821 else
822 {
823 printUsage();
824 status = STATUS_ERROR;
825 }
826
827 cleanup();
828
829 if (status == STATUS_ERROR)
830 return 1;
831
832 exit(0);
833 }
834