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