1 /* 2 * Spectravideo SVI Cassette file 3 * 4 * BLOAD "CAS:",R 5 * 6 * By Stefano Bodrato 7 * 8 * $Id: svi.c $ 9 */ 10 11 #include "appmake.h" 12 13 14 static char *binname = NULL; 15 static char *crtfile = NULL; 16 static char *outfile = NULL; 17 static int origin = -1; 18 static char audio = 0; 19 static char c_disk = 0; 20 static char fast = 0; 21 static char khz_22 = 0; 22 static char dumb = 0; 23 static char loud = 0; 24 static char help = 0; 25 26 static unsigned char h_lvl; 27 static unsigned char l_lvl; 28 29 30 static int create_disk(); 31 32 /* Options that are available for this module */ 33 option_t svi_options[] = { 34 { 'h', "help", "Display this help", OPT_BOOL, &help}, 35 { 'b', "binfile", "Linked binary file", OPT_STR, &binname }, 36 { 'c', "crt0file", "crt0 file used in linking", OPT_STR, &crtfile }, 37 { 'o', "output", "Name of output file", OPT_STR, &outfile }, 38 { 0 , "org", "Origin of the binary", OPT_INT, &origin }, 39 { 0, "audio", "Create also a WAV file", OPT_BOOL, &audio }, px_exec(char * target)40 { 0, "fast", "Tweak the audio tones to run a bit faster", OPT_BOOL, &fast }, 41 { 0, "22", "22050hz bitrate option", OPT_BOOL, &khz_22 }, 42 { 0, "dumb", "Just convert to WAV a tape file", OPT_BOOL, &dumb }, 43 { 0, "loud", "Louder audio volume", OPT_BOOL, &loud }, 44 { 0, "disk", "Create a .dsk image", OPT_BOOL, &c_disk }, 45 { 0, NULL, NULL, OPT_NONE, NULL } 46 }; 47 48 /* two fast cycles for '0', two slow cycles for '1' */ 49 50 void sv_bit(FILE* fpout, int bit, char tweak) 51 { 52 int i, period0, period1, period1lo; 53 54 if (fast) { 55 period1 = 14; 56 period0 = 9; 57 } else { 58 period1 = 18; 59 period0 = 9; 60 } 61 62 if (fast) 63 period1lo = period1 + 3; 64 else 65 period1lo = period1 + 1; 66 67 if (tweak) 68 period1 += 3; 69 70 if (bit) { 71 /* '1' */ 72 for (i = 0; i < period0; i++) 73 fputc(h_lvl, fpout); 74 for (i = 0; i < period0; i++) 75 fputc(l_lvl, fpout); 76 } else { 77 /* '0' */ 78 for (i = 0; i < period1; i++) 79 fputc(h_lvl, fpout); 80 for (i = 0; i < period1lo; i++) 81 fputc(l_lvl, fpout); 82 } 83 } 84 85 void sv_rawout(FILE* fpout, unsigned char b) 86 { 87 static unsigned char c[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; 88 int i; 89 90 /* Start bit */ 91 sv_bit(fpout, 1, 1); 92 93 /* byte */ 94 for (i = 0; i < 8; i++) 95 sv_bit(fpout, (b & c[i]), 0); 96 } 97 98 void sv_tone(FILE* fpout) 99 { 100 int i; 101 102 for (i = 0; (i < 1600); i++) 103 /* workaround (64 bit gcc bug ?) */ 104 sv_bit(fpout, 0, (i & 4) ? 1 : 0); 105 sv_bit(fpout, 1, 1); 106 } 107 108 /* 10101....0101010101111111 */ 109 void headtune(FILE* fp) 110 { 111 int i; 112 113 for (i = 0; i < 16; i++) 114 writebyte(85, fp); 115 writebyte(127, fp); 116 } 117 118 int svi_exec(char* target) 119 { 120 char filename[FILENAME_MAX + 1]; 121 char wavfile[FILENAME_MAX + 1]; 122 char name[11]; 123 FILE *fpin, *fpout; 124 int c; 125 int i; 126 int pos; 127 int len; 128 129 if (help) 130 return -1; 131 132 if (binname == NULL || (!dumb && (crtfile == NULL && origin == -1))) { 133 return -1; 134 } 135 136 if ( c_disk ) { 137 return create_disk(); 138 } 139 140 if (origin != -1) { 141 pos = origin; 142 } else { 143 if ((pos = get_org_addr(crtfile)) == -1) { 144 exit_log(1,"Could not find parameter ZORG (not z88dk compiled?)\n"); 145 } 146 } 147 148 if (loud) { 149 h_lvl = 0xFF; 150 l_lvl = 0; 151 } else { 152 h_lvl = 0xe0; 153 l_lvl = 0x20; 154 } 155 156 if (dumb) { 157 strcpy(filename, binname); 158 } else { 159 160 if (outfile == NULL) { 161 strcpy(filename, binname); 162 suffix_change(filename, ".cas"); 163 } else { 164 strcpy(filename, outfile); 165 } 166 167 if (strcmp(binname, filename) == 0) { 168 exit_log(1, "Input and output file names must be different\n"); 169 } 170 171 if ((fpin = fopen_bin(binname, crtfile)) == NULL) { 172 exit_log(1,"Can't open input file\n"); 173 } 174 175 /* 176 * Now we try to determine the size of the file 177 * to be converted 178 */ 179 if (fseek(fpin, 0, SEEK_END)) { 180 fclose(fpin); 181 exit_log(1,"Couldn't determine size of file\n"); 182 } 183 184 len = ftell(fpin); 185 186 fseek(fpin, 0L, SEEK_SET); 187 188 if ((fpout = fopen(filename, "wb")) == NULL) { 189 printf("Can't open output file\n"); 190 exit(1); 191 } 192 193 /* Write out the header file */ 194 headtune(fpout); 195 for (i = 0; i < 10; i++) 196 writebyte(208, fpout); 197 198 /* Deal with the filename */ 199 snprintf(name, sizeof(name), "%-*s", (int) sizeof(name)-1, binname); 200 201 for (i = 0; i < 6; i++) 202 writebyte(name[i], fpout); 203 204 writeword(0, fpout); 205 206 /* Now, the body */ 207 headtune(fpout); 208 writeword(pos, fpout); /* Start Address */ 209 writeword(pos + len + 1, fpout); /* End Address */ 210 writeword(pos, fpout); /* Call Address */ 211 212 /* (58 bytes written so far...) */ 213 214 /* We append the binary file */ 215 216 for (i = 0; i < len; i++) { 217 c = getc(fpin); 218 writebyte(c, fpout); 219 } 220 221 /* Append some zeros, just to be sure not to get an error*/ 222 223 for (i = 0; i < 16384; i++) 224 writebyte(0, fpout); 225 226 fclose(fpin); 227 fclose(fpout); 228 } 229 230 /* ***************************************** */ 231 /* Now, if requested, create the audio file */ 232 /* ***************************************** */ 233 if ((audio) || (fast) || (khz_22) || (loud)) { 234 if ((fpin = fopen(filename, "rb")) == NULL) { 235 exit_log(1, "Can't open file %s for wave conversion\n", filename); 236 } 237 238 if (fseek(fpin, 0, SEEK_END)) { 239 fclose(fpin); 240 exit_log(1,"Couldn't determine size of file\n"); 241 } 242 len = ftell(fpin); 243 fseek(fpin, 0, SEEK_SET); 244 245 strcpy(wavfile, filename); 246 247 suffix_change(wavfile, ".RAW"); 248 249 if ((fpout = fopen(wavfile, "wb")) == NULL) { 250 exit_log(1, "Can't open output raw audio file %s\n", wavfile); 251 } 252 253 /* leading silence and tone*/ 254 for (i = 0; i < 0x3000; i++) 255 fputc(0x80, fpout); 256 sv_tone(fpout); 257 258 /* Write $7f */ 259 sv_bit(fpout, 0, 1); 260 for (i = 0; i < 7; i++) 261 sv_bit(fpout, 1, 1); 262 263 /* Skip the tone leader bytes */ 264 for (i = 0; (i < 17); i++) 265 c = getc(fpin); 266 len -= 17; 267 268 /* Copy the header */ 269 if (dumb) 270 printf("\nInfo: Program Name found in header: "); 271 for (i = 0; (i < 18); i++) { 272 c = getc(fpin); 273 if (dumb && i > 10 && i < 17) 274 printf("%c", c); 275 sv_rawout(fpout, c); 276 } 277 278 len -= 18; 279 280 /* leading silence and tone*/ 281 for (i = 0; i < 0x8000; i++) 282 fputc(h_lvl, fpout); 283 sv_tone(fpout); 284 285 /* Write $7f */ 286 sv_bit(fpout, 0, 1); 287 for (i = 0; i < 7; i++) 288 sv_bit(fpout, 1, 1); 289 290 /* Skip the tone leader bytes */ 291 for (i = 0; (i < 17); i++) 292 c = getc(fpin); 293 len -= 17; 294 295 /* program block */ 296 if (len > 0) { 297 for (i = 0; i < len; i++) { 298 c = getc(fpin); 299 sv_rawout(fpout, c); 300 } 301 } 302 303 fclose(fpin); 304 fclose(fpout); 305 306 /* Now complete with the WAV header */ 307 if (khz_22) 308 raw2wav_22k(wavfile,2); 309 else 310 raw2wav(wavfile); 311 312 } /* END of WAV CONVERSION BLOCK */ 313 314 return 0; 315 } 316 317 static uint8_t sectorbuf[256]; 318 319 static int create_disk() 320 { 321 char disc_name[FILENAME_MAX+1]; 322 char bootname[FILENAME_MAX+1]; 323 FILE *fpin,*fpout; 324 int track, sector; 325 size_t binlen; 326 327 if ( outfile == NULL ) { 328 strcpy(disc_name,binname); 329 suffix_change(disc_name,".svi"); 330 } else { 331 strcpy(disc_name,outfile); 332 } 333 334 335 strcpy(bootname, binname); 336 suffix_change(bootname, "_BOOTSTRAP.bin"); 337 338 if ( (fpin=fopen_bin(bootname, crtfile) ) == NULL ) { 339 exit_log(1,"Can't open input file %s\n",bootname); 340 } 341 if ( fseek(fpin,0,SEEK_END) ) { 342 fclose(fpin); 343 exit_log(1,"Couldn't determine size of file\n"); 344 } 345 binlen = ftell(fpin); 346 fseek(fpin,0L,SEEK_SET); 347 348 if ( binlen > 128 ) { 349 exit_log(1, "Bootstrap has length %d > 128", binlen); 350 } 351 memset(sectorbuf, 0, sizeof(sectorbuf)); 352 if (128 != fread(sectorbuf, 1, 128, fpin)) { fclose(fpin); exit_log(1, "Could not read required data from <%s>\n",bootname); } 353 fclose(fpin); 354 355 if ( (fpout = fopen(disc_name, "wb")) == NULL ) { 356 exit_log(1,"Can't open output file %s\n",disc_name); 357 } 358 359 if ((fpin = fopen_bin(binname, crtfile)) == NULL) { 360 exit_log(1,"Can't open input file %s\n",bootname); 361 } 362 363 // First track has 18 sectors of 128 bytes 364 fwrite(sectorbuf, 1, 128, fpout); // Track 0, sector 0 365 366 // And now we're on track 1, we have 17 sectors of 256 bytes 367 for ( track = 0; track < 40; track++ ) { 368 for ( sector = (track == 0 ? 1 : 0); sector < (track == 0 ? 18 : 17); sector++ ) { 369 int size = track == 0 ? 128 : 256; 370 memset(sectorbuf, 0, sizeof(sectorbuf)); 371 if ( !feof(fpin) ) { 372 if (size != fread(sectorbuf, 1, size, fpin)) { fclose(fpin); exit_log(1, "Could not read required data from <%s>\n",binname); } 373 } 374 fwrite(sectorbuf, 1, size, fpout); 375 } 376 } 377 fclose(fpout); 378 fclose(fpin); 379 380 return 0; 381 382 } 383