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

Last change on this file since 60 was 60, checked in by pulkomandy, 5 years ago

Add a version of k5towav modified for MO6.

  • Use lower WAV samplerate (smaller file)
  • Use higher speed as allowed by the MO6 (faster loading)
File size: 10.6 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 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
298static 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
308static void write_le2 (int value, FILE *file)
309{
310    fputc( value&0xff, file );
311    fputc( (value>>8)&0xff, file );
312}
313
314
315
316static void write_id (char *id, FILE *file)
317{
318    int size = fwrite (id, 1, 4, file);
319    (void)size;
320}
321
322
323
324static 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
353static 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
392static 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
401int 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}
Note: See TracBrowser for help on using the repository browser.