source: thomson/tools/k5towav/k5towav.c@ d4c7cf0

main
Last change on this file since d4c7cf0 was d4c7cf0, checked in by Adrien Destugues <pulkomandy@…>, 9 years ago

Increase the motor off gap and add another header marker.

  • Some games have a "DCMO6" marker, identify this one as well as the others
  • When using a line in to tape adapter, the motor off doesn't work, so include an extra delay between files.

git-svn-id: svn://localhost/thomson@61 85ae3b6b-dc8f-4344-a89d-598714f2e4e5

  • Property mode set to 100644
File size: 10.7 KB
Line 
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
37static int flag_modified = FALSE;
38static int current_value = CURRENT_VALUE_DEFAULT;
39static double remain = 0;
40static int cycles = 0;
41
42
43
44static 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
57static void write_motoroff (FILE *file)
58{
59 write_gap (WAVE_FORMAT_SAMPLESPERSEC*2, file);
60}
61
62
63
64static void write_motoron (FILE *file)
65{
66 write_gap (WAVE_FORMAT_SAMPLESPERSEC, file);
67}
68
69
70
71static 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
84static 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
110static 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
173static 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
206static 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
220static 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 dcmoto_mark3[] = "DCMO6\1\1\1\1\1\1\1\1\1\1\1\x3c\x5a";
229 char basic_mark[] = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\x3c\x5a";
230
231 do
232 {
233 if ((length < STOCK_LENGTH) && (feof (bin_file) == 0))
234 {
235 size = fread(stock+length, 1, STOCK_LENGTH-length, bin_file);
236 length += size;
237 }
238
239 if (length > 19)
240 {
241 if ((memcmp (dcmoto_mark1, stock, 18) == 0)
242 || (memcmp (dcmoto_mark2, stock, 18) == 0)
243 || (memcmp (dcmoto_mark3, stock, 18) == 0)
244 || (memcmp (basic_mark, stock, 18) == 0))
245 {
246 if (motor_status != 0)
247 {
248 write_motoroff (wav_file);
249 motor_status &= ~MOTOR_STOPS_AFTER_THIS_BLOCK;
250 }
251 memset (stock, 0x01, 6);
252
253 cycles = 0;
254 remain = 0;
255
256 if (stock[18] == '\0')
257 {
258 write_motoron (wav_file);
259 motor_status &= ~MOTOR_STOPS_AFTER_DATA_BLOCK;
260 if ((length > (18+2+0x0d)) && (stock[18+2+0x0d] != '\0'))
261 {
262 motor_status |= MOTOR_STOPS_AFTER_DATA_BLOCK;
263 }
264 motor_status |= MOTOR_STOPS_AFTER_THIS_BLOCK;
265 }
266 else
267 {
268 if ((motor_status & MOTOR_STOPS_AFTER_DATA_BLOCK) != 0)
269 {
270 write_motoron (wav_file);
271 }
272 else
273 {
274 write_data_gap (wav_file);
275 }
276
277 if (stock[18] == '\xff')
278 {
279 motor_status &= ~MOTOR_STOPS_AFTER_DATA_BLOCK;
280 motor_status |= MOTOR_STOPS_AFTER_THIS_BLOCK;
281 }
282 else
283 {
284 motor_status &= ~MOTOR_STOPS_AFTER_THIS_BLOCK;
285 }
286 }
287 }
288 }
289 cycles += 4+2+7; /* For preparing data to be written */
290 write_byte (*stock, wav_file);
291 cycles += 6+3; /* For the loop */
292
293 memmove (stock, stock+1, STOCK_LENGTH-1);
294 length--;
295 } while (length > 0);
296}
297
298
299
300static void write_le4 (int value, FILE *file)
301{
302 fputc( value&0xff, file );
303 fputc( (value>>8)&0xff, file );
304 fputc( (value>>16)&0xff, file );
305 fputc( (value>>24)&0xff, file );
306}
307
308
309
310static void write_le2 (int value, FILE *file)
311{
312 fputc( value&0xff, file );
313 fputc( (value>>8)&0xff, file );
314}
315
316
317
318static void write_id (char *id, FILE *file)
319{
320 int size = fwrite (id, 1, 4, file);
321 (void)size;
322}
323
324
325
326static void update_wav_header (char *filename)
327{
328 FILE *file;
329 struct stat st;
330
331 stat( filename, &st );
332
333 file = fopen (filename, "rb+");
334 if (file != NULL)
335 {
336 write_id ("RIFF", file);
337 write_le4 ((int)st.st_size-WAVE_RIFF_CHUNK_SIZE, file);
338 write_id ("WAVE", file);
339 write_id ("fmt ", file);
340 write_le4 (WAVE_FORMAT_CHUNK_SIZE, file);
341 write_le2 (WAVE_FORMAT_PCM, file);
342 write_le2 (WAVE_FORMAT_CHANNELS, file);
343 write_le4 (WAVE_FORMAT_SAMPLESPERSEC*2, file);
344 write_le4 (WAVE_FORMAT_AVGBYTEPERSEC, file);
345 write_le2 (WAVE_FORMAT_BLOCKALIGN, file);
346 write_le2 (WAVE_FORMAT_BITPERSAMPLE, file);
347 write_id ("data", file);
348 write_le4 ((int)st.st_size-WAVE_HEADER_SIZE, file);
349 fclose (file);
350 }
351}
352
353
354
355static void write_wav (char *bin_name, char *wav_name)
356{
357 int i;
358 FILE *bin_file;
359 FILE *wav_file;
360
361 bin_file = fopen (bin_name, "rb");
362 if (bin_file != NULL)
363 {
364 wav_file = fopen (wav_name, "wb");
365 if (wav_file != NULL)
366 {
367 /* Create WAV header gap */
368 for (i=0; i<WAVE_HEADER_SIZE; i++)
369 {
370 fputc (0x00, wav_file);
371 }
372
373 /* Write WAV data */
374 write_motoron (wav_file);
375 convert_file (bin_file, wav_file);
376 write_motoroff (wav_file);
377 fclose (wav_file);
378 update_wav_header (wav_name);
379 }
380 else
381 {
382 printf ("*** Can not write file %s\n", wav_name);
383 }
384 fclose (bin_file);
385 }
386 else
387 {
388 printf ("*** Can not read file %s\n", bin_name);
389 }
390}
391
392
393
394static int info (void)
395{
396 printf ("k5towav (c) Prehisto feb 2015\n");
397 printf (" Usage : k5towav [--modified] <filename>\n");
398 return EXIT_FAILURE;
399}
400
401
402
403int main (int argc, char *argv[])
404{
405 int i;
406 char bin_name[300] = "";
407 char wav_name[300] = "";
408
409 for (i=1; i<argc; i++)
410 {
411 if (argv[i][0] == '-')
412 {
413 if (strcmp (argv[i], "--modified") == 0)
414 {
415 flag_modified = TRUE;
416 }
417 else
418 {
419 printf ("*** option '%s' unknown\n", argv[i]);
420 return info ();
421 }
422 }
423 else
424 {
425 if (*bin_name == '\0')
426 {
427 strcpy(bin_name, argv[i]);
428 }
429 else
430 {
431 return info ();
432 }
433 }
434 }
435
436 sprintf (wav_name, "%s.wav", bin_name);
437
438 write_wav (bin_name, wav_name);
439
440 return EXIT_SUCCESS;
441}
Note: See TracBrowser for help on using the repository browser.