/*---------------------------------------------------------------------------* Project: NitroSDK - tools - mic2wav File: main.cpp Copyright 2003-2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: main.cpp,v $ Revision 1.3 2004/08/05 07:27:58 takano_makoto fix bug. Revision 1.2 2004/06/18 10:52:56 yosizaki change to CXX_X86. Revision 1.1 2004/06/17 04:41:49 yosizaki (none) $NoKeywords: $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include // Create WAV file from log file class LogToWav : public WAVEFORMATEX { private: void *data; int len, reserve; bool end; private: void UpdateSetting(void) { cbSize = sizeof(WAVEFORMATEX); wFormatTag = WAVE_FORMAT_PCM; nBlockAlign = (WORD)((wBitsPerSample / 8) * nChannels); nAvgBytesPerSec = nSamplesPerSec * nBlockAlign * nChannels; } public: LogToWav() : data(NULL), len(0), reserve(0), end(false) { nChannels = 1; wBitsPerSample = 16; nSamplesPerSec = 11025; UpdateSetting(); } ~LogToWav() { Reset(); } // Destroy input data void Reset(void) { free(data), data = NULL, reserve = 0; len = 0; end = false; } // Determine if a single set of sample data is complete bool IsEnd(void) const { return end; } // Parse the input line void InputLine(const char *s); // Export current data to specified file bool Save(const char *path); } ; // Parse the input line void LogToWav::InputLine(const char *s) { switch(*s++) { case '#': // Explicit comment break; case '$': // Set parameters if(!strncmp(s, "bits=", 5)) { if(len == 0) wBitsPerSample = (WORD)atoi(s + 5); } else if(!strncmp(s, "rate=", 5)) { if(len == 0) nSamplesPerSec = (WORD)atoi(s + 5); } else if(!strncmp(s, "end", 3)) end = true; else return; UpdateSetting(); break; case '|': // Input data // Detect as "^|([0-9A-F]{n},)+$" with specified bit width { const int width = wBitsPerSample / 4; int nibble = 0, sample = 0; for( ; ; ) { // Extract sample as hex value char c = (char)toupper(*s++); if((c >= '0') && (c <= '9')) { sample = (sample << 4) + (c + 0 - '0'); ++nibble; } else if((c >= 'A') && (c <= 'F')) { sample = (sample << 4) + (c + 10 - 'A'); ++nibble; } // Add to buffer with delimiter else if(c == ',') { // Take only valid values if(nibble == width) { // If buffer is too small, expand it if(len >= reserve) { int new_len = reserve ? reserve * 2 : 16; void *p = realloc(data, new_len); if(!p) { printf("fatal error : can not allocate memory!\n"); exit(1); } data = p, reserve = new_len; } if(wBitsPerSample == 8) { *(BYTE*)((BYTE*)data + len) = (BYTE)sample; } else if(wBitsPerSample == 16) { *(SHORT*)((BYTE*)data + len) = (SHORT)(sample - 0x8000); } len += wBitsPerSample / 8; } nibble = 0, sample = 0; } // Otherwise, end else break; } } break; } } // Export current data to specified file bool LogToWav::Save(const char *path) { // Open the output file FILE *f = fopen(path, "wb"); if(!f) return false; // Align with DWORD boundary const int size = ((len + 3) & ~3); while(len < size) { if(wBitsPerSample == 8) { *(BYTE*)((BYTE*)data + len) = *(BYTE*)((BYTE*)data + len - 1); } else if(wBitsPerSample == 16) { *(SHORT*)((BYTE*)data + len) = *(SHORT*)((BYTE*)data + len - 2); } len += wBitsPerSample / 8; } // Output the data in order WORD w; DWORD d; fwrite("RIFF", 1, 4, f); // 4. d = 56 + size - 8; fwrite(&d, sizeof(d), 1, f); // 4. fwrite("WAVE", 1, 4, f); // 4. // "fmt" fwrite("fmt ", 1, 4, f); // 4. d = 16; fwrite(&d, sizeof(d), 1, f); // 4. w = (WORD)wFormatTag; fwrite(&w, sizeof(w), 1, f); // 2. w = (WORD)nChannels; fwrite(&w, sizeof(w), 1, f); // 2. d = (DWORD)nSamplesPerSec; fwrite(&d, sizeof(d), 1, f); // 4. d = (DWORD)nAvgBytesPerSec; fwrite(&d, sizeof(d), 1, f); // 4. w = (WORD)nBlockAlign; fwrite(&w, sizeof(w), 1, f); // 2. w = (WORD)wBitsPerSample; fwrite(&w, sizeof(w), 1, f); // 2. // 36. // "fact" fwrite("fact", 1, 4, f); // 4. d = 4; fwrite(&d, sizeof(d), 1, f); // 4. d = (DWORD)(len / nBlockAlign); fwrite(&d, sizeof(d), 1, f); // 4. // 48. // "data" fwrite("data", 1, 4, f); // 4. d = (DWORD)(len); fwrite(&d, sizeof(d), 1, f); // 4. // 56. fwrite(data, 1, len, f); fclose(f); return true; } int main(int argc, char* argv[]) { if(argc < 2) { printf("no input file.\n"); return 1; } // Open the input file FILE *f = fopen(argv[1], "r"); if(!f) { printf("can not open input file \"%s\".\n", argv[1]); return 2; } // Specify the directory. (Otherwise, the same location as the input file.) char s_dir[MAX_PATH]; if(argc >= 3) { strcpy(s_dir, argv[2]); const int n = strlen(s_dir) - 1; if((n >= 0) && ((s_dir[n] != '\\') && (s_dir[n] != '/'))) s_dir[n + 1] = '/', s_dir[n + 2] = '\0'; } else { strcpy(s_dir, argv[1]); int n = strlen(s_dir) - 1; while((n >= 0) && (s_dir[n] != '\\') && (s_dir[n] != '/')) --n; s_dir[n + 1] = '\0'; } { // Process by line LogToWav wav; int file_index = 0; char line[4096]; while(fgets(line, sizeof(line), f)) { wav.InputLine(line); if(wav.IsEnd()) { char path[32]; sprintf(path, "%s%08d.wav", s_dir, file_index++); _mkdir(s_dir); if(wav.Save(path)) printf("output. \"%s\"\n", path); else printf("failed! \"%s\"\n", path); wav.Reset(); } } } fclose(f); return 0; }