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