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