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

main
Last change on this file since d8aca9f was d8aca9f, checked in by Adrien Destugues <pulkomandy@…>, 9 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)

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

  • Property mode set to 100644
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.