1 /*---------------------------------------------------------------------------*
2   Project:  NitroSDK - tools - mic2wav
3   File:     main.cpp
4 
5   Copyright 2003-2008 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: main.cpp,v $
14   Revision 1.3  2004/08/05 07:27:58  takano_makoto
15   fix bug.
16 
17   Revision 1.2  2004/06/18 10:52:56  yosizaki
18   change to CXX_X86.
19 
20   Revision 1.1  2004/06/17 04:41:49  yosizaki
21   (none)
22 
23   $NoKeywords: $
24  *---------------------------------------------------------------------------*/
25 
26 #include <windows.h>
27 #include <mmsystem.h>
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32 #include <direct.h>
33 
34 
35 // Create WAV file from log file
36 class   LogToWav :
37     public  WAVEFORMATEX
38 {
39 private:
40     void    *data;
41     int     len, reserve;
42     bool    end;
43 
44 private:
45 
UpdateSetting(void)46     void    UpdateSetting(void)
47     {
48         cbSize          = sizeof(WAVEFORMATEX);
49         wFormatTag      = WAVE_FORMAT_PCM;
50         nBlockAlign     = (WORD)((wBitsPerSample / 8) * nChannels);
51         nAvgBytesPerSec = nSamplesPerSec * nBlockAlign * nChannels;
52     }
53 
54 public:
55 
LogToWav()56     LogToWav() : data(NULL), len(0), reserve(0), end(false)
57     {
58         nChannels = 1;
59         wBitsPerSample = 16;
60         nSamplesPerSec = 11025;
61         UpdateSetting();
62     }
63 
~LogToWav()64     ~LogToWav()
65     {
66         Reset();
67     }
68 
69     // Destroy input data
Reset(void)70     void    Reset(void)
71     {
72         free(data), data = NULL, reserve = 0;
73         len = 0;
74         end = false;
75     }
76 
77     // Determine if a single set of sample data is complete
IsEnd(void) const78     bool    IsEnd(void) const { return  end;    }
79 
80     // Parse the input line
81     void    InputLine(const char *s);
82 
83     // Export current data to specified file
84     bool    Save(const char *path);
85 
86 } ;
87 
88 
89 // Parse the input line
InputLine(const char * s)90 void    LogToWav::InputLine(const char *s)
91 {
92     switch(*s++) {
93     case '#':   // Explicit comment
94         break;
95     case '$':   // Set parameters
96         if(!strncmp(s, "bits=", 5)) {
97             if(len == 0)
98                 wBitsPerSample = (WORD)atoi(s + 5);
99         }
100         else if(!strncmp(s, "rate=", 5)) {
101             if(len == 0)
102                 nSamplesPerSec = (WORD)atoi(s + 5);
103         }
104         else if(!strncmp(s, "end", 3))
105             end = true;
106         else
107             return;
108         UpdateSetting();
109         break;
110     case '|':   // Input data
111         // Detect as "^|([0-9A-F]{n},)+$" with specified bit width
112         {
113             const int   width = wBitsPerSample / 4;
114             int nibble = 0, sample = 0;
115             for( ; ; ) {
116                 // Extract sample as hex value
117                 char    c = (char)toupper(*s++);
118                 if((c >= '0') && (c <= '9')) {
119                     sample = (sample << 4) + (c +  0 - '0');
120                     ++nibble;
121                 }
122                 else if((c >= 'A') && (c <= 'F')) {
123                     sample = (sample << 4) + (c + 10 - 'A');
124                     ++nibble;
125                 }
126                 // Add to buffer with delimiter
127                 else if(c == ',') {
128                     // Take only valid values
129                     if(nibble == width) {
130                         // If buffer is too small, expand it
131                         if(len >= reserve) {
132                             int new_len = reserve ? reserve * 2 : 16;
133                             void    *p = realloc(data, new_len);
134                             if(!p) {
135                                 printf("fatal error : can not allocate memory!\n");
136                                 exit(1);
137                             }
138                             data = p, reserve = new_len;
139                         }
140                         if(wBitsPerSample == 8) {
141                             *(BYTE*)((BYTE*)data + len) = (BYTE)sample;
142                         }
143                         else if(wBitsPerSample == 16) {
144                             *(SHORT*)((BYTE*)data + len) = (SHORT)(sample - 0x8000);
145                         }
146                         len += wBitsPerSample / 8;
147                     }
148                     nibble = 0, sample = 0;
149                 }
150                 // Otherwise, end
151                 else
152                     break;
153             }
154         }
155         break;
156     }
157 
158 }
159 
160 // Export current data to specified file
Save(const char * path)161 bool    LogToWav::Save(const char *path)
162 {
163     // Open the output file
164     FILE    *f = fopen(path, "wb");
165     if(!f)  return  false;
166 
167     // Align with DWORD boundary
168     const int   size = ((len + 3) & ~3);
169     while(len < size) {
170         if(wBitsPerSample == 8) {
171             *(BYTE*)((BYTE*)data + len) = *(BYTE*)((BYTE*)data + len - 1);
172         }
173         else if(wBitsPerSample == 16) {
174             *(SHORT*)((BYTE*)data + len) = *(SHORT*)((BYTE*)data + len - 2);
175         }
176         len += wBitsPerSample / 8;
177     }
178 
179     // Output the data in order
180     WORD    w;
181     DWORD   d;
182     fwrite("RIFF", 1, 4, f);        // 4.
183     d = 56 + size - 8;
184     fwrite(&d, sizeof(d), 1, f);    // 4.
185     fwrite("WAVE", 1, 4, f);        // 4.
186     // "fmt"
187     fwrite("fmt ", 1, 4, f);        // 4.
188     d = 16;
189     fwrite(&d, sizeof(d), 1, f);    // 4.
190     w = (WORD)wFormatTag;
191     fwrite(&w, sizeof(w), 1, f);    // 2.
192     w = (WORD)nChannels;
193     fwrite(&w, sizeof(w), 1, f);    // 2.
194     d = (DWORD)nSamplesPerSec;
195     fwrite(&d, sizeof(d), 1, f);    // 4.
196     d = (DWORD)nAvgBytesPerSec;
197     fwrite(&d, sizeof(d), 1, f);    // 4.
198     w = (WORD)nBlockAlign;
199     fwrite(&w, sizeof(w), 1, f);    // 2.
200     w = (WORD)wBitsPerSample;
201     fwrite(&w, sizeof(w), 1, f);    // 2.
202     // 36.
203     // "fact"
204     fwrite("fact", 1, 4, f);        // 4.
205     d = 4;
206     fwrite(&d, sizeof(d), 1, f);    // 4.
207     d = (DWORD)(len / nBlockAlign);
208     fwrite(&d, sizeof(d), 1, f);    // 4.
209     // 48.
210     // "data"
211     fwrite("data", 1, 4, f);        // 4.
212     d = (DWORD)(len);
213     fwrite(&d, sizeof(d), 1, f);    // 4.
214     // 56.
215     fwrite(data, 1, len, f);
216     fclose(f);
217 
218     return  true;
219 }
220 
221 
main(int argc,char * argv[])222 int main(int argc, char* argv[])
223 {
224     if(argc < 2) {
225         printf("no input file.\n");
226         return  1;
227     }
228 
229     // Open the input file
230     FILE    *f = fopen(argv[1], "r");
231     if(!f) {
232         printf("can not open input file \"%s\".\n", argv[1]);
233         return  2;
234     }
235 
236     // Specify the directory. (Otherwise, the same location as the input file.)
237     char    s_dir[MAX_PATH];
238     if(argc >= 3) {
239         strcpy(s_dir, argv[2]);
240         const int   n = strlen(s_dir) - 1;
241         if((n >= 0) && ((s_dir[n] != '\\') && (s_dir[n] != '/')))
242             s_dir[n + 1] = '/', s_dir[n + 2] = '\0';
243     } else {
244         strcpy(s_dir, argv[1]);
245         int n = strlen(s_dir) - 1;
246         while((n >= 0) && (s_dir[n] != '\\') && (s_dir[n] != '/'))
247             --n;
248         s_dir[n + 1] = '\0';
249     }
250 
251     {   // Process by line
252         LogToWav    wav;
253         int file_index = 0;
254         char    line[4096];
255         while(fgets(line, sizeof(line), f)) {
256             wav.InputLine(line);
257             if(wav.IsEnd()) {
258                 char    path[32];
259                 sprintf(path, "%s%08d.wav", s_dir, file_index++);
260                 _mkdir(s_dir);
261                 if(wav.Save(path))
262                     printf("output. \"%s\"\n", path);
263                 else
264                     printf("failed! \"%s\"\n", path);
265 
266                 wav.Reset();
267             }
268         }
269     }
270 
271     fclose(f);
272     return  0;
273 }
274