Mercurial > hg > dmlib
annotate tools/mod2wav.c @ 796:97ecc0a9c21f
Silence some "probing".
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 18 Oct 2013 19:47:30 +0300 |
parents | ed60a7ee3ebb |
children | f066e9dccf29 |
rev | line source |
---|---|
0 | 1 /* |
2 * mod2wav - Render XM/JSSMOD module to WAV waveform file | |
3 * Programmed and designed by Matti 'ccr' Hamalainen | |
4 * (C) Copyright 2007 Tecnic Software productions (TNSP) | |
5 * | |
6 * Please read file 'COPYING' for information on license and distribution. | |
7 */ | |
8 #include <stdio.h> | |
9 #include <stdlib.h> | |
10 #include <errno.h> | |
11 #include "jss.h" | |
12 #include "jssmod.h" | |
13 #include "jssmix.h" | |
14 #include "jssplr.h" | |
15 #include "dmlib.h" | |
16 #include "dmargs.h" | |
206
9b6c0ed66960
Use the routines factored into dmwav module.
Matti Hamalainen <ccr@tnsp.org>
parents:
185
diff
changeset
|
17 #include "dmwav.h" |
285
245b15cd1919
Don't link libSDL uselessly to utilities that do not actually use it.
Matti Hamalainen <ccr@tnsp.org>
parents:
206
diff
changeset
|
18 #include "dmmutex.h" |
0 | 19 |
20 | |
300 | 21 char *optInFilename = NULL, *optOutFilename = NULL; |
0 | 22 int optOutFormat = JSS_AUDIO_S16, |
23 optOutChannels = 2, | |
24 optOutFreq = 44100, | |
25 optMuteOChannels = -1, | |
26 optStartOrder = -1; | |
27 BOOL optUsePlayTime = FALSE; | |
28 size_t optPlayTime; | |
29 | |
30 | |
37 | 31 DMOptArg optList[] = |
32 { | |
33 { 0, '?', "help", "Show this help", OPT_NONE }, | |
34 { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, | |
35 { 3, '1', "16bit", "16-bit output", OPT_NONE }, | |
36 { 4, '8', "8bit", "8-bit output", OPT_NONE }, | |
37 { 5, 'm', "mono", "Mono output", OPT_NONE }, | |
38 { 6, 's', "stereo", "Stereo output", OPT_NONE }, | |
39 { 7, 'f', "freq", "Output frequency", OPT_ARGREQ }, | |
40 { 8, 'M', "mute", "Mute other channels than #", OPT_ARGREQ }, | |
41 { 9, 'o', "order", "Start from order #", OPT_ARGREQ }, | |
42 { 10, 't', "time", "Play for # seconds", OPT_ARGREQ }, | |
0 | 43 // {10, 'l', "loop", "Loop for # times", OPT_ARGREQ }, |
44 }; | |
45 | |
46 const int optListN = sizeof(optList) / sizeof(optList[0]); | |
47 | |
48 | |
49 BOOL argHandleOpt(const int optN, char *optArg, char *currArg) | |
50 { | |
51 (void) optArg; | |
52 | |
37 | 53 switch (optN) |
54 { | |
55 case 0: | |
56 dmPrintBanner(stdout, dmProgName, | |
57 "[options] [sourcefile] [destfile]"); | |
58 | |
59 dmArgsPrintHelp(stdout, optList, optListN); | |
60 exit(0); | |
61 break; | |
0 | 62 |
37 | 63 case 2: |
64 dmVerbosity++; | |
65 break; | |
66 | |
67 case 3: | |
68 optOutFormat = JSS_AUDIO_S16; | |
69 break; | |
0 | 70 |
37 | 71 case 4: |
72 optOutFormat = JSS_AUDIO_U8; | |
73 break; | |
0 | 74 |
37 | 75 case 5: |
76 optOutChannels = JSS_AUDIO_MONO; | |
77 break; | |
0 | 78 |
37 | 79 case 6: |
38
8b04b0b51edc
Oops, fix a stupid bug in -s option .. it was setting the wrong variable. :|
Matti Hamalainen <ccr@tnsp.org>
parents:
37
diff
changeset
|
80 optOutChannels = JSS_AUDIO_STEREO; |
37 | 81 break; |
0 | 82 |
37 | 83 case 7: |
84 optOutFreq = atoi(optArg); | |
85 break; | |
0 | 86 |
37 | 87 case 8: |
88 optMuteOChannels = atoi(optArg); | |
89 break; | |
90 | |
91 case 9: | |
92 optStartOrder = atoi(optArg); | |
93 break; | |
0 | 94 |
37 | 95 case 10: |
96 optPlayTime = atoi(optArg); | |
97 optUsePlayTime = TRUE; | |
98 break; | |
0 | 99 |
37 | 100 default: |
101 dmError("Unknown argument '%s'.\n", currArg); | |
102 return FALSE; | |
0 | 103 } |
104 | |
105 return TRUE; | |
106 } | |
107 | |
108 | |
109 BOOL argHandleFile(char *currArg) | |
110 { | |
300 | 111 if (!optInFilename) |
112 optInFilename = currArg; | |
37 | 113 else |
300 | 114 if (!optOutFilename) |
115 optOutFilename = currArg; | |
37 | 116 else |
117 { | |
0 | 118 dmError("Too many filename arguments (only source and dest needed) '%s'\n", currArg); |
119 return FALSE; | |
120 } | |
121 | |
122 return TRUE; | |
123 } | |
124 | |
125 | |
126 int main(int argc, char *argv[]) | |
127 { | |
15
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
128 DMResource *inFile = NULL; |
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
129 FILE *outFile = NULL; |
68 | 130 JSSModule *mod = NULL; |
131 JSSMixer *dev = NULL; | |
132 JSSPlayer *plr = NULL; | |
0 | 133 int result = -1; |
134 size_t bufLen = 1024*4, dataTotal, dataWritten, sampSize; | |
135 Uint8 *mb = NULL; | |
136 | |
137 dmInitProg("mod2wav", "XM/JSSMOD to WAV renderer", "0.2", NULL, NULL); | |
138 dmVerbosity = 1; | |
139 | |
140 // Parse arguments | |
141 if (!dmArgsProcess(argc, argv, optList, optListN, | |
142 argHandleOpt, argHandleFile, TRUE)) | |
143 exit(1); | |
144 | |
145 // Check arguments | |
300 | 146 if (optInFilename == NULL || optOutFilename == NULL) |
37 | 147 { |
300 | 148 dmError("Input or output file not specified. Try --help.\n"); |
0 | 149 return 1; |
150 } | |
151 | |
152 // Initialize miniJSS | |
153 jssInit(); | |
154 | |
155 // Open the source file | |
730
3d813c81f33c
More work on resources API.
Matti Hamalainen <ccr@tnsp.org>
parents:
652
diff
changeset
|
156 if ((result = dmf_create_stdio(optInFilename, "rb", &inFile)) != DMERR_OK) |
15
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
157 { |
83
6b42aed2745b
Cleanups and correct the dmf_create_stdio() issue here as well.
Matti Hamalainen <ccr@tnsp.org>
parents:
68
diff
changeset
|
158 dmError("Error opening input file '%s', %d: %s\n", |
730
3d813c81f33c
More work on resources API.
Matti Hamalainen <ccr@tnsp.org>
parents:
652
diff
changeset
|
159 optInFilename, result, dmErrorStr(result)); |
15
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
160 return 1; |
0 | 161 } |
162 | |
163 // Read module file | |
300 | 164 fprintf(stderr, "Reading file: %s\n", optInFilename); |
0 | 165 #ifdef JSS_SUP_XM |
15
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
166 fprintf(stderr, "* Trying XM...\n"); |
796 | 167 result = jssLoadXM(inFile, &mod, FALSE); |
0 | 168 #endif |
169 #ifdef JSS_SUP_JSSMOD | |
15
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
170 if (result != 0) |
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
171 { |
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
172 dmfseek(inFile, 0L, SEEK_SET); |
777
ed60a7ee3ebb
Change JSSMOD loader to use DMResources.
Matti Hamalainen <ccr@tnsp.org>
parents:
730
diff
changeset
|
173 dmMsg(1, "* Trying JSSMOD ...\n"); |
796 | 174 result = jssLoadJSSMOD(inFile, &mod, FALSE); |
15
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
175 } |
0 | 176 #endif |
15
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
177 dmf_close(inFile); |
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
178 if (result != DMERR_OK) |
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
179 { |
83
6b42aed2745b
Cleanups and correct the dmf_create_stdio() issue here as well.
Matti Hamalainen <ccr@tnsp.org>
parents:
68
diff
changeset
|
180 dmError("Error loading module file, %d: %s\n", |
15
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
181 result, dmErrorStr(result)); |
feec43a3497c
Fix input file reading of mod2wav utility.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
182 return 3; |
0 | 183 } |
184 | |
49
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
39
diff
changeset
|
185 // Try to convert it |
68 | 186 if ((result = jssConvertModuleForPlaying(mod)) != DMERR_OK) |
49
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
39
diff
changeset
|
187 { |
83
6b42aed2745b
Cleanups and correct the dmf_create_stdio() issue here as well.
Matti Hamalainen <ccr@tnsp.org>
parents:
68
diff
changeset
|
188 dmError("Could not convert module for playing, %d: %s\n", |
49
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
39
diff
changeset
|
189 result, dmErrorStr(result)); |
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
39
diff
changeset
|
190 return 3; |
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
39
diff
changeset
|
191 } |
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
39
diff
changeset
|
192 |
0 | 193 // Open mixer |
68 | 194 dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO); |
195 if (dev == NULL) | |
39 | 196 { |
83
6b42aed2745b
Cleanups and correct the dmf_create_stdio() issue here as well.
Matti Hamalainen <ccr@tnsp.org>
parents:
68
diff
changeset
|
197 dmError("jvmInit() returned NULL\n"); |
0 | 198 return 4; |
199 } | |
200 | |
68 | 201 sampSize = jvmGetSampleSize(dev); |
83
6b42aed2745b
Cleanups and correct the dmf_create_stdio() issue here as well.
Matti Hamalainen <ccr@tnsp.org>
parents:
68
diff
changeset
|
202 if ((mb = dmMalloc(bufLen * sampSize)) == NULL) |
39 | 203 { |
83
6b42aed2745b
Cleanups and correct the dmf_create_stdio() issue here as well.
Matti Hamalainen <ccr@tnsp.org>
parents:
68
diff
changeset
|
204 dmError("Could not allocate mixing buffer\n"); |
0 | 205 return 5; |
206 } | |
207 | |
208 dmMsg(1, "Using fmt=%d, bits=%d, channels=%d, freq=%d [%d / sample]\n", | |
68 | 209 optOutFormat, jvmGetSampleRes(dev), optOutChannels, optOutFreq, |
0 | 210 sampSize); |
211 | |
212 // Initialize player | |
68 | 213 if ((plr = jmpInit(dev)) == NULL) |
214 { | |
83
6b42aed2745b
Cleanups and correct the dmf_create_stdio() issue here as well.
Matti Hamalainen <ccr@tnsp.org>
parents:
68
diff
changeset
|
215 dmError("jmpInit() returned NULL.\n"); |
0 | 216 return 6; |
217 } | |
218 | |
219 // Set callback | |
68 | 220 jvmSetCallback(dev, jmpExec, plr); |
0 | 221 |
222 // Initialize playing | |
68 | 223 jmpSetModule(plr, mod); |
37 | 224 if (optStartOrder >= 0) |
225 { | |
0 | 226 dmMsg(1, "Starting from song order #%d\n", optStartOrder); |
227 } else | |
228 optStartOrder = 0; | |
37 | 229 |
68 | 230 jmpPlayOrder(plr, optStartOrder); |
185
1f8f4d7cb33b
Increase default global volume.
Matti Hamalainen <ccr@tnsp.org>
parents:
83
diff
changeset
|
231 jvmSetGlobalVol(dev, 150); |
0 | 232 |
68 | 233 if (optMuteOChannels > 0 && optMuteOChannels <= mod->nchannels) |
37 | 234 { |
0 | 235 int i; |
68 | 236 for (i = 0; i < mod->nchannels; i++) |
237 jvmMute(dev, i, TRUE); | |
238 jvmMute(dev, optMuteOChannels - 1, FALSE); | |
0 | 239 } |
240 | |
241 // Open output file | |
300 | 242 if ((outFile = fopen(optOutFilename, "wb")) == NULL) |
37 | 243 { |
730
3d813c81f33c
More work on resources API.
Matti Hamalainen <ccr@tnsp.org>
parents:
652
diff
changeset
|
244 dmError("Error opening output file '%s'. (%s)\n", |
3d813c81f33c
More work on resources API.
Matti Hamalainen <ccr@tnsp.org>
parents:
652
diff
changeset
|
245 optInFilename, strerror(errno)); |
0 | 246 return 7; |
247 } | |
248 | |
249 // Write initial header | |
206
9b6c0ed66960
Use the routines factored into dmwav module.
Matti Hamalainen <ccr@tnsp.org>
parents:
185
diff
changeset
|
250 dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, 1024); |
0 | 251 |
252 // Render audio data and output to file | |
253 if (optUsePlayTime) | |
254 dmMsg(1, "Rendering module (%d seconds) ...\n", optPlayTime); | |
255 else | |
256 dmMsg(1, "Rendering module ...\n"); | |
257 | |
258 optPlayTime *= optOutFreq; | |
259 dataTotal = 0; | |
260 dataWritten = 1; | |
68 | 261 while (plr->isPlaying && dataWritten > 0) |
0 | 262 { |
263 size_t writeLen = bufLen; | |
264 if (optUsePlayTime && (writeLen + dataTotal) > optPlayTime) | |
265 writeLen = optPlayTime - dataTotal; | |
266 | |
267 if (writeLen > 0) | |
268 { | |
68 | 269 jvmRenderAudio(dev, mb, writeLen); |
0 | 270 #if (SDL_BYTEORDER == SDL_BIG_ENDIAN) |
271 jssEncodeSample16((Uint16 *)mb, writeLen * optOutChannels, jsampSwapEndianess); | |
272 #endif | |
273 dataWritten = fwrite(mb, sampSize, writeLen, outFile); | |
274 if (dataWritten < writeLen) | |
275 { | |
276 dmError("Error writing data!\n"); | |
277 fclose(outFile); | |
278 return 8; | |
279 } | |
280 dataTotal += dataWritten; | |
281 } | |
282 | |
283 if (optUsePlayTime && dataTotal >= optPlayTime) | |
284 break; | |
285 } | |
286 | |
287 // Write the correct header | |
288 if (fseek(outFile, 0L, SEEK_SET) != 0) | |
289 { | |
290 dmError("Error rewinding to header position!\n"); | |
291 return 9; | |
292 } | |
293 | |
206
9b6c0ed66960
Use the routines factored into dmwav module.
Matti Hamalainen <ccr@tnsp.org>
parents:
185
diff
changeset
|
294 dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, dataTotal); |
0 | 295 |
296 // Done! | |
297 fclose(outFile); | |
68 | 298 |
299 jmpClose(plr); | |
300 jvmClose(dev); | |
301 jssFreeModule(mod); | |
302 jssClose(); | |
303 | |
0 | 304 dmMsg(1, "OK.\n"); |
305 return 0; | |
306 } |