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