1 | /*--------------------------------------------------------*/
|
---|
2 | /* k5towav (c) Prehisto feb 2015 */
|
---|
3 | /* To convert MO K7 file to WAV file */
|
---|
4 | /*--------------------------------------------------------*/
|
---|
5 |
|
---|
6 | #include <stdio.h>
|
---|
7 | #include <string.h>
|
---|
8 | #include <stdlib.h>
|
---|
9 | #include <sys/types.h>
|
---|
10 | #include <sys/stat.h>
|
---|
11 | #include <unistd.h>
|
---|
12 |
|
---|
13 | #ifndef TRUE
|
---|
14 | # define TRUE 1
|
---|
15 | #endif
|
---|
16 | #ifndef FALSE
|
---|
17 | # define FALSE 0
|
---|
18 | #endif
|
---|
19 |
|
---|
20 | /* WAV constants */
|
---|
21 | #define WAVE_HEADER_SIZE 0x2c
|
---|
22 | #define WAVE_RIFF_CHUNK_SIZE 4
|
---|
23 | #define WAVE_FORMAT_CHUNK_SIZE 16
|
---|
24 | #define WAVE_FORMAT_PCM 1
|
---|
25 | #define WAVE_FORMAT_CHANNELS 1
|
---|
26 | #define WAVE_FORMAT_SAMPLESPERSEC 11025
|
---|
27 | #define WAVE_FORMAT_BLOCKALIGN 2
|
---|
28 | #define WAVE_FORMAT_AVGBYTEPERSEC WAVE_FORMAT_SAMPLESPERSEC*WAVE_FORMAT_BLOCKALIGN
|
---|
29 | #define WAVE_FORMAT_BITPERSAMPLE 16
|
---|
30 |
|
---|
31 | /* Sample parameters */
|
---|
32 | #define CYCLES_PER_FRAME 19968
|
---|
33 | #define MICROSEC_PER_FRAME 20000
|
---|
34 | #define MICROSEC_PER_SEC 1000000
|
---|
35 | #define CURRENT_VALUE_DEFAULT 0x7fff
|
---|
36 |
|
---|
37 | static int flag_modified = FALSE;
|
---|
38 | static int current_value = CURRENT_VALUE_DEFAULT;
|
---|
39 | static double remain = 0;
|
---|
40 | static int cycles = 0;
|
---|
41 |
|
---|
42 |
|
---|
43 |
|
---|
44 | static void write_gap (int length, FILE *file)
|
---|
45 | {
|
---|
46 | int i;
|
---|
47 |
|
---|
48 | for (i=0; i<length; i++)
|
---|
49 | {
|
---|
50 | fputc (current_value&0xff, file );
|
---|
51 | fputc ((current_value>>8)&0xff, file );
|
---|
52 | }
|
---|
53 | }
|
---|
54 |
|
---|
55 |
|
---|
56 |
|
---|
57 | static void write_motoroff (FILE *file)
|
---|
58 | {
|
---|
59 | write_gap (WAVE_FORMAT_SAMPLESPERSEC/2, file);
|
---|
60 | }
|
---|
61 |
|
---|
62 |
|
---|
63 |
|
---|
64 | static void write_motoron (FILE *file)
|
---|
65 | {
|
---|
66 | write_gap (WAVE_FORMAT_SAMPLESPERSEC, file);
|
---|
67 | }
|
---|
68 |
|
---|
69 |
|
---|
70 |
|
---|
71 | static void write_data_gap (FILE *file)
|
---|
72 | {
|
---|
73 | /* Must have time to do at least :
|
---|
74 | 4+2 NEXT LDA ,X+
|
---|
75 | 4+2 STA ,U+
|
---|
76 | 4+1 LEAY -1,U
|
---|
77 | 3 BNE NEXT
|
---|
78 | ... a bit more! */
|
---|
79 | write_gap (WAVE_FORMAT_SAMPLESPERSEC/8, file);
|
---|
80 | }
|
---|
81 |
|
---|
82 |
|
---|
83 |
|
---|
84 | static void write_signal (FILE *file)
|
---|
85 | {
|
---|
86 | int i;
|
---|
87 | double size = ((((double)cycles*(double)MICROSEC_PER_FRAME)
|
---|
88 | /(double)CYCLES_PER_FRAME)
|
---|
89 | *(double)WAVE_FORMAT_SAMPLESPERSEC)
|
---|
90 | /(double)MICROSEC_PER_SEC;
|
---|
91 |
|
---|
92 | size += remain-(double)((int)remain);
|
---|
93 | remain = size;
|
---|
94 |
|
---|
95 | /* write signal */
|
---|
96 | for (i=0; i<(int)size; i++)
|
---|
97 | {
|
---|
98 | fputc (current_value&0xff, file );
|
---|
99 | fputc ((current_value>>8)&0xff, file );
|
---|
100 | }
|
---|
101 |
|
---|
102 | /* invert signal */
|
---|
103 | current_value=~current_value;
|
---|
104 |
|
---|
105 | cycles = 0;
|
---|
106 | }
|
---|
107 |
|
---|
108 |
|
---|
109 |
|
---|
110 | static void write_byte_standard (char byte, FILE *file)
|
---|
111 | {
|
---|
112 | int bit;
|
---|
113 |
|
---|
114 | /* 4 LF1AF STA <$2045
|
---|
115 | 2 LDB #$08 */
|
---|
116 | cycles += 4+2;
|
---|
117 | for (bit=0x80; bit>0; bit>>=1)
|
---|
118 | {
|
---|
119 | /* 7 LF1B3 BSR LF1CB
|
---|
120 | 2 LF1CB LDA #$40
|
---|
121 | 4+0 EORA ,U
|
---|
122 | 4+0 STA ,U */
|
---|
123 | cycles += 7+2+4+4;
|
---|
124 | write_signal (file);
|
---|
125 | /* 5 RTS
|
---|
126 | 3 LDX #$002D
|
---|
127 | 7 BSR LF1A2
|
---|
128 | 4+1 LF1A2 LEAX -$01,X
|
---|
129 | 3 BNE LF1A2
|
---|
130 | 2 CLRA
|
---|
131 | 5 RTS
|
---|
132 | 3 LDX #$0032
|
---|
133 | 6 ASL <$2045
|
---|
134 | 3 BCC LF1C5 */
|
---|
135 | cycles += 5+3+7+(0x2d*(4+1+3))+2+5+3+6+3;
|
---|
136 |
|
---|
137 | if (((int)byte & bit) == 0)
|
---|
138 | {
|
---|
139 | /* 7 LF1C5 BSR LF1A2
|
---|
140 | 4+1 LF1A2 LEAX -$01,X
|
---|
141 | 3 BNE LF1A2
|
---|
142 | 2 CLRA
|
---|
143 | 5 RTS */
|
---|
144 | cycles += 7+(0x32*(4+1+3))+2+5;
|
---|
145 | }
|
---|
146 | else
|
---|
147 | {
|
---|
148 | /* 7 BSR LF1CB
|
---|
149 | 2 LF1CB LDA #$40
|
---|
150 | 4+0 EORA ,U
|
---|
151 | 4+0 STA ,U */
|
---|
152 | cycles += 7+2+4+4;
|
---|
153 | write_signal (file);
|
---|
154 | /* 5 RTS
|
---|
155 | 4+1 LEAX -$03,X
|
---|
156 | 7 LF1C5 BSR LF1A2
|
---|
157 | 4+1 LF1A2 LEAX -$01,X
|
---|
158 | 3 BNE LF1A2
|
---|
159 | 2 CLRA
|
---|
160 | 5 RTS */
|
---|
161 | cycles += 5+4+1+7+((0x32-3)*(4+1+3))+2+5;
|
---|
162 | }
|
---|
163 | /* 2 DECB
|
---|
164 | 3 BNE LF1B3 */
|
---|
165 | cycles += 5;
|
---|
166 | }
|
---|
167 | /* 5 RTS */
|
---|
168 | cycles += 5;
|
---|
169 | }
|
---|
170 |
|
---|
171 |
|
---|
172 |
|
---|
173 | static void write_byte_modified (char byte, FILE *file)
|
---|
174 | {
|
---|
175 | int bit;
|
---|
176 |
|
---|
177 | /* 4 LF1AF STA <$2045
|
---|
178 | 2 LDB #$08 */
|
---|
179 | cycles += 4+2;
|
---|
180 | for (bit=0x80; bit>0; bit>>=1)
|
---|
181 | {
|
---|
182 | /* 7 LF1B3 BSR LF1CB
|
---|
183 | 2 LF1CB LDA #$40
|
---|
184 | 4+0 EORA ,U
|
---|
185 | 4+0 STA ,U */
|
---|
186 | cycles += 7+2+4+4;
|
---|
187 | write_signal (file);
|
---|
188 | cycles += 269;
|
---|
189 |
|
---|
190 | if (((int)byte & bit) == 1)
|
---|
191 | {
|
---|
192 | write_signal (file);
|
---|
193 | }
|
---|
194 | cycles += 564;
|
---|
195 |
|
---|
196 | /* 2 DECB
|
---|
197 | 3 BNE LF1B3 */
|
---|
198 | cycles += 5;
|
---|
199 | }
|
---|
200 | /* 5 RTS */
|
---|
201 | cycles += 5;
|
---|
202 | }
|
---|
203 |
|
---|
204 |
|
---|
205 |
|
---|
206 | static void write_byte (char byte, FILE *file)
|
---|
207 | {
|
---|
208 | if (flag_modified == FALSE)
|
---|
209 | write_byte_standard (byte, file);
|
---|
210 | else
|
---|
211 | write_byte_modified (byte, file);
|
---|
212 | }
|
---|
213 |
|
---|
214 |
|
---|
215 |
|
---|
216 | #define STOCK_LENGTH 40
|
---|
217 | #define MOTOR_STOPS_AFTER_THIS_BLOCK 0x01
|
---|
218 | #define MOTOR_STOPS_AFTER_DATA_BLOCK 0x02
|
---|
219 |
|
---|
220 | static void convert_file (FILE *bin_file, FILE *wav_file)
|
---|
221 | {
|
---|
222 | static char stock[STOCK_LENGTH];
|
---|
223 | static size_t length = 0;
|
---|
224 | static size_t size = 0;
|
---|
225 | static int motor_status = 0;
|
---|
226 | char dcmoto_mark1[] = "DCMOTO\1\1\1\1\1\1\1\1\1\1\x3c\x5a";
|
---|
227 | char dcmoto_mark2[] = "\xdc\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\x3c\x5a";
|
---|
228 | char basic_mark[] = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\x3c\x5a";
|
---|
229 |
|
---|
230 | do
|
---|
231 | {
|
---|
232 | if ((length < STOCK_LENGTH) && (feof (bin_file) == 0))
|
---|
233 | {
|
---|
234 | size = fread(stock+length, 1, STOCK_LENGTH-length, bin_file);
|
---|
235 | length += size;
|
---|
236 | }
|
---|
237 |
|
---|
238 | if (length > 19)
|
---|
239 | {
|
---|
240 | if ((memcmp (dcmoto_mark1, stock, 18) == 0)
|
---|
241 | || (memcmp (dcmoto_mark2, stock, 18) == 0)
|
---|
242 | || (memcmp (basic_mark, stock, 18) == 0))
|
---|
243 | {
|
---|
244 | if (motor_status != 0)
|
---|
245 | {
|
---|
246 | write_motoroff (wav_file);
|
---|
247 | motor_status &= ~MOTOR_STOPS_AFTER_THIS_BLOCK;
|
---|
248 | }
|
---|
249 | memset (stock, 0x01, 6);
|
---|
250 |
|
---|
251 | cycles = 0;
|
---|
252 | remain = 0;
|
---|
253 |
|
---|
254 | if (stock[18] == '\0')
|
---|
255 | {
|
---|
256 | write_motoron (wav_file);
|
---|
257 | motor_status &= ~MOTOR_STOPS_AFTER_DATA_BLOCK;
|
---|
258 | if ((length > (18+2+0x0d)) && (stock[18+2+0x0d] != '\0'))
|
---|
259 | {
|
---|
260 | motor_status |= MOTOR_STOPS_AFTER_DATA_BLOCK;
|
---|
261 | }
|
---|
262 | motor_status |= MOTOR_STOPS_AFTER_THIS_BLOCK;
|
---|
263 | }
|
---|
264 | else
|
---|
265 | {
|
---|
266 | if ((motor_status & MOTOR_STOPS_AFTER_DATA_BLOCK) != 0)
|
---|
267 | {
|
---|
268 | write_motoron (wav_file);
|
---|
269 | }
|
---|
270 | else
|
---|
271 | {
|
---|
272 | write_data_gap (wav_file);
|
---|
273 | }
|
---|
274 |
|
---|
275 | if (stock[18] == '\xff')
|
---|
276 | {
|
---|
277 | motor_status &= ~MOTOR_STOPS_AFTER_DATA_BLOCK;
|
---|
278 | motor_status |= MOTOR_STOPS_AFTER_THIS_BLOCK;
|
---|
279 | }
|
---|
280 | else
|
---|
281 | {
|
---|
282 | motor_status &= ~MOTOR_STOPS_AFTER_THIS_BLOCK;
|
---|
283 | }
|
---|
284 | }
|
---|
285 | }
|
---|
286 | }
|
---|
287 | cycles += 4+2+7; /* For preparing data to be written */
|
---|
288 | write_byte (*stock, wav_file);
|
---|
289 | cycles += 6+3; /* For the loop */
|
---|
290 |
|
---|
291 | memmove (stock, stock+1, STOCK_LENGTH-1);
|
---|
292 | length--;
|
---|
293 | } while (length > 0);
|
---|
294 | }
|
---|
295 |
|
---|
296 |
|
---|
297 |
|
---|
298 | static void write_le4 (int value, FILE *file)
|
---|
299 | {
|
---|
300 | fputc( value&0xff, file );
|
---|
301 | fputc( (value>>8)&0xff, file );
|
---|
302 | fputc( (value>>16)&0xff, file );
|
---|
303 | fputc( (value>>24)&0xff, file );
|
---|
304 | }
|
---|
305 |
|
---|
306 |
|
---|
307 |
|
---|
308 | static void write_le2 (int value, FILE *file)
|
---|
309 | {
|
---|
310 | fputc( value&0xff, file );
|
---|
311 | fputc( (value>>8)&0xff, file );
|
---|
312 | }
|
---|
313 |
|
---|
314 |
|
---|
315 |
|
---|
316 | static void write_id (char *id, FILE *file)
|
---|
317 | {
|
---|
318 | int size = fwrite (id, 1, 4, file);
|
---|
319 | (void)size;
|
---|
320 | }
|
---|
321 |
|
---|
322 |
|
---|
323 |
|
---|
324 | static void update_wav_header (char *filename)
|
---|
325 | {
|
---|
326 | FILE *file;
|
---|
327 | struct stat st;
|
---|
328 |
|
---|
329 | stat( filename, &st );
|
---|
330 |
|
---|
331 | file = fopen (filename, "rb+");
|
---|
332 | if (file != NULL)
|
---|
333 | {
|
---|
334 | write_id ("RIFF", file);
|
---|
335 | write_le4 ((int)st.st_size-WAVE_RIFF_CHUNK_SIZE, file);
|
---|
336 | write_id ("WAVE", file);
|
---|
337 | write_id ("fmt ", file);
|
---|
338 | write_le4 (WAVE_FORMAT_CHUNK_SIZE, file);
|
---|
339 | write_le2 (WAVE_FORMAT_PCM, file);
|
---|
340 | write_le2 (WAVE_FORMAT_CHANNELS, file);
|
---|
341 | write_le4 (WAVE_FORMAT_SAMPLESPERSEC*2, file);
|
---|
342 | write_le4 (WAVE_FORMAT_AVGBYTEPERSEC, file);
|
---|
343 | write_le2 (WAVE_FORMAT_BLOCKALIGN, file);
|
---|
344 | write_le2 (WAVE_FORMAT_BITPERSAMPLE, file);
|
---|
345 | write_id ("data", file);
|
---|
346 | write_le4 ((int)st.st_size-WAVE_HEADER_SIZE, file);
|
---|
347 | fclose (file);
|
---|
348 | }
|
---|
349 | }
|
---|
350 |
|
---|
351 |
|
---|
352 |
|
---|
353 | static void write_wav (char *bin_name, char *wav_name)
|
---|
354 | {
|
---|
355 | int i;
|
---|
356 | FILE *bin_file;
|
---|
357 | FILE *wav_file;
|
---|
358 |
|
---|
359 | bin_file = fopen (bin_name, "rb");
|
---|
360 | if (bin_file != NULL)
|
---|
361 | {
|
---|
362 | wav_file = fopen (wav_name, "wb");
|
---|
363 | if (wav_file != NULL)
|
---|
364 | {
|
---|
365 | /* Create WAV header gap */
|
---|
366 | for (i=0; i<WAVE_HEADER_SIZE; i++)
|
---|
367 | {
|
---|
368 | fputc (0x00, wav_file);
|
---|
369 | }
|
---|
370 |
|
---|
371 | /* Write WAV data */
|
---|
372 | write_motoron (wav_file);
|
---|
373 | convert_file (bin_file, wav_file);
|
---|
374 | write_motoroff (wav_file);
|
---|
375 | fclose (wav_file);
|
---|
376 | update_wav_header (wav_name);
|
---|
377 | }
|
---|
378 | else
|
---|
379 | {
|
---|
380 | printf ("*** Can not write file %s\n", wav_name);
|
---|
381 | }
|
---|
382 | fclose (bin_file);
|
---|
383 | }
|
---|
384 | else
|
---|
385 | {
|
---|
386 | printf ("*** Can not read file %s\n", bin_name);
|
---|
387 | }
|
---|
388 | }
|
---|
389 |
|
---|
390 |
|
---|
391 |
|
---|
392 | static int info (void)
|
---|
393 | {
|
---|
394 | printf ("k5towav (c) Prehisto feb 2015\n");
|
---|
395 | printf (" Usage : k5towav [--modified] <filename>\n");
|
---|
396 | return EXIT_FAILURE;
|
---|
397 | }
|
---|
398 |
|
---|
399 |
|
---|
400 |
|
---|
401 | int main (int argc, char *argv[])
|
---|
402 | {
|
---|
403 | int i;
|
---|
404 | char bin_name[300] = "";
|
---|
405 | char wav_name[300] = "";
|
---|
406 |
|
---|
407 | for (i=1; i<argc; i++)
|
---|
408 | {
|
---|
409 | if (argv[i][0] == '-')
|
---|
410 | {
|
---|
411 | if (strcmp (argv[i], "--modified") == 0)
|
---|
412 | {
|
---|
413 | flag_modified = TRUE;
|
---|
414 | }
|
---|
415 | else
|
---|
416 | {
|
---|
417 | printf ("*** option '%s' unknown\n", argv[i]);
|
---|
418 | return info ();
|
---|
419 | }
|
---|
420 | }
|
---|
421 | else
|
---|
422 | {
|
---|
423 | if (*bin_name == '\0')
|
---|
424 | {
|
---|
425 | strcpy(bin_name, argv[i]);
|
---|
426 | }
|
---|
427 | else
|
---|
428 | {
|
---|
429 | return info ();
|
---|
430 | }
|
---|
431 | }
|
---|
432 | }
|
---|
433 |
|
---|
434 | sprintf (wav_name, "%s.wav", bin_name);
|
---|
435 |
|
---|
436 | write_wav (bin_name, wav_name);
|
---|
437 |
|
---|
438 | return EXIT_SUCCESS;
|
---|
439 | }
|
---|