source: Thomson/tools/k5towav/k5towav.c @ 69

Last change on this file since 69 was 61, checked in by pulkomandy, 5 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.
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.