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