/*--------------------------------------------------------*/ /* k5towav (c) Prehisto feb 2015 */ /* To convert MO K7 file to WAV file */ /*--------------------------------------------------------*/ #include #include #include #include #include #include #ifndef TRUE # define TRUE 1 #endif #ifndef FALSE # define FALSE 0 #endif /* WAV constants */ #define WAVE_HEADER_SIZE 0x2c #define WAVE_RIFF_CHUNK_SIZE 4 #define WAVE_FORMAT_CHUNK_SIZE 16 #define WAVE_FORMAT_PCM 1 #define WAVE_FORMAT_CHANNELS 1 #define WAVE_FORMAT_SAMPLESPERSEC 11025 #define WAVE_FORMAT_BLOCKALIGN 2 #define WAVE_FORMAT_AVGBYTEPERSEC WAVE_FORMAT_SAMPLESPERSEC*WAVE_FORMAT_BLOCKALIGN #define WAVE_FORMAT_BITPERSAMPLE 16 /* Sample parameters */ #define CYCLES_PER_FRAME 19968 #define MICROSEC_PER_FRAME 20000 #define MICROSEC_PER_SEC 1000000 #define CURRENT_VALUE_DEFAULT 0x7fff static int flag_modified = FALSE; static int current_value = CURRENT_VALUE_DEFAULT; static double remain = 0; static int cycles = 0; static void write_gap (int length, FILE *file) { int i; for (i=0; i>8)&0xff, file ); } } static void write_motoroff (FILE *file) { write_gap (WAVE_FORMAT_SAMPLESPERSEC*2, file); } static void write_motoron (FILE *file) { write_gap (WAVE_FORMAT_SAMPLESPERSEC, file); } static void write_data_gap (FILE *file) { /* Must have time to do at least : 4+2 NEXT LDA ,X+ 4+2 STA ,U+ 4+1 LEAY -1,U 3 BNE NEXT ... a bit more! */ write_gap (WAVE_FORMAT_SAMPLESPERSEC/8, file); } static void write_signal (FILE *file) { int i; double size = ((((double)cycles*(double)MICROSEC_PER_FRAME) /(double)CYCLES_PER_FRAME) *(double)WAVE_FORMAT_SAMPLESPERSEC) /(double)MICROSEC_PER_SEC; size += remain-(double)((int)remain); remain = size; /* write signal */ for (i=0; i<(int)size; i++) { fputc (current_value&0xff, file ); fputc ((current_value>>8)&0xff, file ); } /* invert signal */ current_value=~current_value; cycles = 0; } static void write_byte_standard (char byte, FILE *file) { int bit; /* 4 LF1AF STA <$2045 2 LDB #$08 */ cycles += 4+2; for (bit=0x80; bit>0; bit>>=1) { /* 7 LF1B3 BSR LF1CB 2 LF1CB LDA #$40 4+0 EORA ,U 4+0 STA ,U */ cycles += 7+2+4+4; write_signal (file); /* 5 RTS 3 LDX #$002D 7 BSR LF1A2 4+1 LF1A2 LEAX -$01,X 3 BNE LF1A2 2 CLRA 5 RTS 3 LDX #$0032 6 ASL <$2045 3 BCC LF1C5 */ cycles += 5+3+7+(0x2d*(4+1+3))+2+5+3+6+3; if (((int)byte & bit) == 0) { /* 7 LF1C5 BSR LF1A2 4+1 LF1A2 LEAX -$01,X 3 BNE LF1A2 2 CLRA 5 RTS */ cycles += 7+(0x32*(4+1+3))+2+5; } else { /* 7 BSR LF1CB 2 LF1CB LDA #$40 4+0 EORA ,U 4+0 STA ,U */ cycles += 7+2+4+4; write_signal (file); /* 5 RTS 4+1 LEAX -$03,X 7 LF1C5 BSR LF1A2 4+1 LF1A2 LEAX -$01,X 3 BNE LF1A2 2 CLRA 5 RTS */ cycles += 5+4+1+7+((0x32-3)*(4+1+3))+2+5; } /* 2 DECB 3 BNE LF1B3 */ cycles += 5; } /* 5 RTS */ cycles += 5; } static void write_byte_modified (char byte, FILE *file) { int bit; /* 4 LF1AF STA <$2045 2 LDB #$08 */ cycles += 4+2; for (bit=0x80; bit>0; bit>>=1) { /* 7 LF1B3 BSR LF1CB 2 LF1CB LDA #$40 4+0 EORA ,U 4+0 STA ,U */ cycles += 7+2+4+4; write_signal (file); cycles += 269; if (((int)byte & bit) == 1) { write_signal (file); } cycles += 564; /* 2 DECB 3 BNE LF1B3 */ cycles += 5; } /* 5 RTS */ cycles += 5; } static void write_byte (char byte, FILE *file) { if (flag_modified == FALSE) write_byte_standard (byte, file); else write_byte_modified (byte, file); } #define STOCK_LENGTH 40 #define MOTOR_STOPS_AFTER_THIS_BLOCK 0x01 #define MOTOR_STOPS_AFTER_DATA_BLOCK 0x02 static void convert_file (FILE *bin_file, FILE *wav_file) { static char stock[STOCK_LENGTH]; static size_t length = 0; static size_t size = 0; static int motor_status = 0; char dcmoto_mark1[] = "DCMOTO\1\1\1\1\1\1\1\1\1\1\x3c\x5a"; char dcmoto_mark2[] = "\xdc\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\x3c\x5a"; char dcmoto_mark3[] = "DCMO6\1\1\1\1\1\1\1\1\1\1\1\x3c\x5a"; char basic_mark[] = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\x3c\x5a"; do { if ((length < STOCK_LENGTH) && (feof (bin_file) == 0)) { size = fread(stock+length, 1, STOCK_LENGTH-length, bin_file); length += size; } if (length > 19) { if ((memcmp (dcmoto_mark1, stock, 18) == 0) || (memcmp (dcmoto_mark2, stock, 18) == 0) || (memcmp (dcmoto_mark3, stock, 18) == 0) || (memcmp (basic_mark, stock, 18) == 0)) { if (motor_status != 0) { write_motoroff (wav_file); motor_status &= ~MOTOR_STOPS_AFTER_THIS_BLOCK; } memset (stock, 0x01, 6); cycles = 0; remain = 0; if (stock[18] == '\0') { write_motoron (wav_file); motor_status &= ~MOTOR_STOPS_AFTER_DATA_BLOCK; if ((length > (18+2+0x0d)) && (stock[18+2+0x0d] != '\0')) { motor_status |= MOTOR_STOPS_AFTER_DATA_BLOCK; } motor_status |= MOTOR_STOPS_AFTER_THIS_BLOCK; } else { if ((motor_status & MOTOR_STOPS_AFTER_DATA_BLOCK) != 0) { write_motoron (wav_file); } else { write_data_gap (wav_file); } if (stock[18] == '\xff') { motor_status &= ~MOTOR_STOPS_AFTER_DATA_BLOCK; motor_status |= MOTOR_STOPS_AFTER_THIS_BLOCK; } else { motor_status &= ~MOTOR_STOPS_AFTER_THIS_BLOCK; } } } } cycles += 4+2+7; /* For preparing data to be written */ write_byte (*stock, wav_file); cycles += 6+3; /* For the loop */ memmove (stock, stock+1, STOCK_LENGTH-1); length--; } while (length > 0); } static void write_le4 (int value, FILE *file) { fputc( value&0xff, file ); fputc( (value>>8)&0xff, file ); fputc( (value>>16)&0xff, file ); fputc( (value>>24)&0xff, file ); } static void write_le2 (int value, FILE *file) { fputc( value&0xff, file ); fputc( (value>>8)&0xff, file ); } static void write_id (char *id, FILE *file) { int size = fwrite (id, 1, 4, file); (void)size; } static void update_wav_header (char *filename) { FILE *file; struct stat st; stat( filename, &st ); file = fopen (filename, "rb+"); if (file != NULL) { write_id ("RIFF", file); write_le4 ((int)st.st_size-WAVE_RIFF_CHUNK_SIZE, file); write_id ("WAVE", file); write_id ("fmt ", file); write_le4 (WAVE_FORMAT_CHUNK_SIZE, file); write_le2 (WAVE_FORMAT_PCM, file); write_le2 (WAVE_FORMAT_CHANNELS, file); write_le4 (WAVE_FORMAT_SAMPLESPERSEC*2, file); write_le4 (WAVE_FORMAT_AVGBYTEPERSEC, file); write_le2 (WAVE_FORMAT_BLOCKALIGN, file); write_le2 (WAVE_FORMAT_BITPERSAMPLE, file); write_id ("data", file); write_le4 ((int)st.st_size-WAVE_HEADER_SIZE, file); fclose (file); } } static void write_wav (char *bin_name, char *wav_name) { int i; FILE *bin_file; FILE *wav_file; bin_file = fopen (bin_name, "rb"); if (bin_file != NULL) { wav_file = fopen (wav_name, "wb"); if (wav_file != NULL) { /* Create WAV header gap */ for (i=0; i\n"); return EXIT_FAILURE; } int main (int argc, char *argv[]) { int i; char bin_name[300] = ""; char wav_name[300] = ""; for (i=1; i