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