asap2wav.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:8k
源码类别:

Windows CE

开发平台:

C/C++

  1. /*
  2.  * asap2wav.c - converter of ASAP-supported formats to WAV files
  3.  *
  4.  * Copyright (C) 2005-2006  Piotr Fusik
  5.  *
  6.  * This file is part of ASAP (Another Slight Atari Player),
  7.  * see http://asap.sourceforge.net
  8.  *
  9.  * ASAP is free software; you can redistribute it and/or modify it
  10.  * under the terms of the GNU General Public License as published
  11.  * by the Free Software Foundation; either version 2 of the License,
  12.  * or (at your option) any later version.
  13.  *
  14.  * ASAP is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty
  16.  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17.  * See the GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with ASAP; if not, write to the Free Software Foundation, Inc.,
  21.  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  22.  */
  23. #include "config.h"
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <stdarg.h>
  27. #include "asap.h"
  28. static void print_error(const char *format, ...)
  29. {
  30. va_list args;
  31. va_start(args, format);
  32. fprintf(stderr, "asap2wav: ");
  33. vfprintf(stderr, format, args);
  34. fputc('n', stderr);
  35. va_end(args);
  36. }
  37. static const char *output_file = NULL;
  38. static unsigned int song = 1000; /* default */
  39. static unsigned int quality = 1;
  40. static unsigned int frequency = 44100;
  41. static unsigned int seconds = 180;
  42. static unsigned int use_16bit = 1;
  43. static int set_output(const char *s)
  44. {
  45. output_file = s;
  46. return 0;
  47. }
  48. static int set_dec(const char *s, unsigned int *result, const char *name,
  49.                    unsigned int minval, unsigned int maxval)
  50. {
  51. unsigned int newval = 0;
  52. while (*s != '') {
  53. if (*s < '0' || *s > '9') {
  54. print_error("%s must be an integer", name);
  55. return 1;
  56. }
  57. newval = 10 * newval + *s++ - '0';
  58. if (newval > maxval) {
  59. print_error("maximum %s is %u", name, maxval);
  60. return 1;
  61. }
  62. }
  63. if (newval < minval) {
  64. print_error("minimum %s is %u", name, minval);
  65. return 1;
  66. }
  67. *result = newval;
  68. return 0;
  69. }
  70. static int set_song(const char *s)
  71. {
  72. return set_dec(s, &song, "subsong number", 0, 255);
  73. }
  74. static int set_quality(const char *s)
  75. {
  76. return set_dec(s, &quality, "quality", 0, 3);
  77. }
  78. static int set_frequency(const char *s)
  79. {
  80. return set_dec(s, &frequency, "sample rate", 4000, 65535);
  81. }
  82. static int set_time(const char *s)
  83. {
  84. unsigned int newmin;
  85. const char *p;
  86. if (s[0] < '0' || s[0] > '9') {
  87. print_error("invalid time format");
  88. return 1;
  89. }
  90. newmin = s[0] - '0';
  91. p = s + 1;
  92. if (*p >= '0' && *p <= '9')
  93. newmin = 10 * newmin + *p++ - '0';
  94. if (*p == ':') {
  95. unsigned int newsec;
  96. if (newmin > 59) {
  97. print_error("maximum time is 59:59");
  98. return 1;
  99. }
  100. if (set_dec(p + 1, &newsec, "SS", newmin == 0 ? 1 : 0, 59))
  101. return 1;
  102. seconds = 60 * newmin + newsec;
  103. return 0;
  104. }
  105. return set_dec(s, &seconds, "time", 1, 3599);
  106. }
  107. /* write 16-bit word as little endian */
  108. static void fput16(unsigned int x, FILE *fp)
  109. {
  110. fputc(x & 0xff, fp);
  111. fputc((x >> 8) & 0xff, fp);
  112. }
  113. /* write 32-bit word as little endian */
  114. static void fput32(unsigned int x, FILE *fp)
  115. {
  116. fputc(x & 0xff, fp);
  117. fputc((x >> 8) & 0xff, fp);
  118. fputc((x >> 16) & 0xff, fp);
  119. fputc((x >> 24) & 0xff, fp);
  120. }
  121. int main(int argc, char *argv[])
  122. {
  123. static const struct {
  124. const char name[9];
  125. int (*func)(const char *s);
  126. } param_opts[] = {
  127. { "output=", set_output },
  128. { "song=", set_song },
  129. { "quality=", set_quality },
  130. { "time=", set_time },
  131. { "rate=", set_frequency }
  132. };
  133. int i;
  134. int files_processed = 0;
  135. for (i = 1; i < argc; i++) {
  136. const char *arg = argv[i];
  137. if (arg[0] == '-') {
  138. int j;
  139. for (j = 0; j < sizeof(param_opts) / sizeof(param_opts[0]); j++) {
  140. if (arg[1] == param_opts[j].name[0] && arg[2] == '') {
  141. if (++i >= argc) {
  142. print_error("missing argument for '-%c'", arg[1]);
  143. return 1;
  144. }
  145. if (param_opts[j].func(argv[i]))
  146. return 1;
  147. break;
  148. }
  149. if (arg[1] == '-') {
  150. size_t len = strlen(param_opts[j].name);
  151. if (strncmp(arg + 2, param_opts[j].name, len) == 0) {
  152. if (param_opts[j].func(arg + 2 + len))
  153. return 1;
  154. break;
  155. }
  156. }
  157. }
  158. if (j < sizeof(param_opts) / sizeof(param_opts[0]))
  159. continue;
  160. if (strcmp(arg, "-b") == 0 || strcmp(arg, "--byte-samples") == 0) {
  161. use_16bit = 0;
  162. continue;
  163. }
  164. if (strcmp(arg, "-w") == 0 || strcmp(arg, "--word-samples") == 0) {
  165. use_16bit = 1;
  166. continue;
  167. }
  168. if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
  169. printf(
  170. "Usage: asap2wav [OPTIONS] INPUTFILE...n"
  171. "Each INPUTFILE must be in a supported format:n"
  172. #ifdef STEREO_SOUND
  173. "SAP, CMC, CMR, DMC, MPT, MPD, RMT, TMC, TM8 or TM2.n"
  174. #else
  175. "SAP, CMC, CMR, DMC, MPT, MPD, RMT, TMC or TM2.n"
  176. #endif
  177. "Options:n"
  178. "-o FILE     --output=FILE      Set output WAV file namen"
  179. "-s SONG     --song=SONG        Select subsong number (zero-based)n"
  180. "-t TIME     --time=TIME        Set output length MM:SS (default: 03:00)n"
  181. "-r FREQ     --rate=FREQ        Set sample rate in Hz (default: 44100)n"
  182. "-q QUALITY  --quality=QUALITY  Set sound quality 0-3 (default: 1)n"
  183. "-b          --byte-samples     Output 8-bit samplesn"
  184. "-w          --word-samples     Output 16-bit samples (default)n"
  185. "-h          --help             Display this information and exitn"
  186. "-v          --version          Display version information and exitn"
  187. );
  188. return 0;
  189. }
  190. if (strcmp(arg, "-v") == 0 || strcmp(arg, "--version") == 0) {
  191. printf("ASAP2WAV " ASAP_VERSION "n");
  192. return 0;
  193. }
  194. print_error("unknown option: %s", arg);
  195. return 1;
  196. }
  197. else {
  198. FILE *fp;
  199. static unsigned char module[65000];
  200. unsigned int module_len;
  201. unsigned int channels;
  202. unsigned int block_size;
  203. unsigned int bytes_per_second;
  204. unsigned int n_bytes;
  205. static unsigned char buffer[8192];
  206. if (strlen(arg) >= FILENAME_MAX) {
  207. print_error("filename too long");
  208. return 1;
  209. }
  210. fp = fopen(arg, "rb");
  211. if (fp == NULL) {
  212. print_error("cannot open %s", arg);
  213. return 1;
  214. }
  215. module_len = fread(module, 1, sizeof(module), fp);
  216. fclose(fp);
  217. ASAP_Initialize(frequency, use_16bit ? AUDIO_FORMAT_S16_LE : AUDIO_FORMAT_U8, quality);
  218. if (!ASAP_Load(arg, module, module_len)) {
  219. print_error("%s: format not supported", arg);
  220. return 1;
  221. }
  222. if (song > 255)
  223. ASAP_PlaySong(ASAP_GetDefSong());
  224. else if (song < ASAP_GetSongs()) {
  225. ASAP_PlaySong(song);
  226. /* back to default */
  227. song = 1000;
  228. }
  229. else {
  230. print_error("you have requested subsong %u ...", song);
  231. print_error("... but %s contains only %u subsongs", arg, ASAP_GetSongs());
  232. return 1;
  233. }
  234. if (output_file == NULL) {
  235. const char *dot;
  236. static char output_default[FILENAME_MAX + 5]; /* max. original name + ".wav" + '' */
  237. dot = strrchr(arg, '.');
  238. sprintf(output_default, "%.*s.wav", (int) (dot - arg), arg);
  239. output_file = output_default;
  240. }
  241. fp = fopen(output_file, "wb");
  242. if (fp == NULL) {
  243. print_error("cannot write %s", output_file);
  244. return 1;
  245. }
  246. channels = ASAP_GetChannels();
  247. block_size = channels << use_16bit;
  248. bytes_per_second = frequency * block_size;
  249. n_bytes = seconds * bytes_per_second;
  250. fwrite("RIFF", 1, 4, fp);
  251. fput32(n_bytes + 36, fp);
  252. fwrite("WAVEfmt x101", 1, 14, fp);
  253. fput16(channels, fp);
  254. fput32(frequency, fp);
  255. fput32(bytes_per_second, fp);
  256. fput16(block_size, fp);
  257. fput16(8 << use_16bit, fp);
  258. fwrite("data", 1, 4, fp);
  259. fput32(n_bytes, fp);
  260. while (n_bytes > sizeof(buffer)) {
  261. ASAP_Generate(buffer, sizeof(buffer));
  262. if (fwrite(buffer, 1, sizeof(buffer), fp) != sizeof(buffer)) {
  263. fclose(fp);
  264. print_error("error writing to %s", output_file);
  265. return 1;
  266. }
  267. n_bytes -= sizeof(buffer);
  268. }
  269. ASAP_Generate(buffer, n_bytes);
  270. fwrite(buffer, 1, n_bytes, fp);
  271. fclose(fp);
  272. output_file = NULL;
  273. files_processed++;
  274. }
  275. }
  276. if (files_processed == 0) {
  277. print_error("no input files; try: asap2wav --help");
  278. return 1;
  279. }
  280. return 0;
  281. }