/ c2t.c
c2t.c
   1  /*
   2  
   3  c2t, Code to Tape|Text, Version 0.997, Wed Sep 27 15:27:56 GMT 2017
   4  
   5  Parts copyright (c) 2011-2017 All Rights Reserved, Egan Ford (egan@sense.net)
   6  
   7  THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
   8  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
   9  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  10  PARTICULAR PURPOSE.
  11  
  12  Built on work by:
  13  	* Mike Willegal (http://www.willegal.net/appleii/toaiff.c)
  14  	* Paul Bourke (http://paulbourke.net/dataformats/audio/, AIFF and WAVE output code)
  15  	* Malcolm Slaney and Ken Turkowski (Integer to IEEE 80-bit float code)
  16  	* Lance Leventhal and Winthrop Saville (6502 Assembly Language Subroutines, CRC 6502 code)
  17      * Piotr Fusik (http://atariarea.krap.pl/x-asm/inflate.html, inflate 6502 code)
  18      * Rich Geldreich (http://code.google.com/p/miniz/, deflate C code)
  19      * Mike Chambers (http://rubbermallet.org/fake6502.c, 6502 simulator)
  20  
  21  License:
  22  	*  Do what you like, remember to credit all sources when using.
  23  
  24  Description:
  25  	This small utility will read Apple I/II binary and
  26  	monitor text files and output Apple I or II AIFF and WAV
  27  	audio files for use with the Apple I and II cassette
  28  	interface.
  29  
  30  Features:
  31  	*  Apple I, II, II+, IIe support.
  32  	*  Big and little-endian machine support.
  33  		o  Little-endian tested.
  34  	*  AIFF and WAVE output (both tested).
  35  	*  Platforms tested:
  36  		o  32-bit/64-bit x86 OS/X.
  37  		o  32-bit/64-bit x86 Linux.
  38  		o  32-bit x86 Windows/Cygwin.
  39  		o  32-bit x86 Windows/MinGW.
  40  	*  Multi-segment tapes.
  41  
  42  Compile:
  43  	OS/X:
  44  		gcc -Wall -O -o c2t c2t.c
  45  	Linux:
  46  		gcc -Wall -O -o c2t c2t.c -lm
  47  	Windows/Cygwin:
  48  		gcc -Wall -O -o c2t c2t.c
  49  	Windows/MinGW:
  50  		PATH=C:\MinGW\bin;%PATH%
  51  		gcc -Wall -O -static -o c2t c2t.c
  52  
  53  Notes:
  54  	*  Virtual ][ only supports .aif (or .cass)
  55  	*  Dropbox only supports .wav and .aiff (do not use .wave or .aif)
  56  
  57  Not yet done:
  58  	*  Test big-endian.
  59  	*  gnuindent
  60      *  Redo malloc code in appendtone
  61  
  62  Thinking about:
  63  	*  Check for existing file and abort, or warn, or prompt.
  64  	*  -q quiet option for Makefiles
  65  	*  autoload support for basic programs
  66  
  67  Bugs:
  68  	*  Probably
  69  
  70  */
  71  
  72  #if defined(_WIN32)
  73  #include "miniz_win32.h"
  74  #else
  75  #include "miniz.h"
  76  #endif
  77  
  78  #include <fake6502.h>
  79  #include <stdio.h>
  80  #include <stdlib.h>
  81  #include <ctype.h>
  82  #include <unistd.h>
  83  #include <string.h>
  84  #include <math.h>
  85  #include <c2t.h>
  86  
  87  #define ABS(x) (((x) < 0) ? -(x) : (x))
  88  
  89  #define VERSION "Version 0.997"
  90  #define OUTFILE argv[argc-1]
  91  #define BINARY 0
  92  #define MONITOR 1
  93  #define AIFF 2
  94  #define WAVE 3
  95  #define DSK 4 
  96  
  97  #define WRITEBYTE(x) { \
  98  	unsigned char wb_j, wb_temp=(x); \
  99  	for(wb_j=0;wb_j<8;wb_j++) { \
 100  		if(wb_temp & 0x80) \
 101  			appendtone(&output,&outputlength,freq1,rate,0,1,&offset); \
 102  		else \
 103  			appendtone(&output,&outputlength,freq0,rate,0,1,&offset); \
 104  		wb_temp<<=1; \
 105  	} \
 106  }
 107  
 108  void usage();
 109  char *getext(char *filename);
 110  void appendtone(double **sound, long *length, int freq, int rate, double time, double cycles, int *offset);
 111  void Write_AIFF(FILE * fptr, double *samples, long nsamples, int nfreq, int bits, double amp);
 112  void Write_WAVE(FILE * fptr, double *samples, long nsamples, int nfreq, int bits, double amp);
 113  void ConvertToIeeeExtended(double num, unsigned char *bytes);
 114  uint8_t read6502(uint16_t address);
 115  void write6502(uint16_t address, uint8_t value);
 116  
 117  unsigned char ram[65536];
 118  int square = 0;
 119  
 120  typedef struct seg {
 121  	int start;
 122  	int length;
 123  	int codelength;
 124  	unsigned char *data;
 125  	char filename[256];
 126  } segment;
 127  
 128  int main(int argc, char **argv)
 129  {
 130  	FILE *ofp;
 131  	double *output = NULL, amp=0.75;
 132  	long outputlength=0;
 133  	int i, c, model=0, outputtype, offset=0, fileoutput=1, warm=0, dsk=0, noformat=0, k8=0, qr=0;
 134  	int autoload=0, basicload=0, compress=0, fast=0, cd=0, tape=0, endpage=0, longmon=0, rate=11025, bits=8, freq0=2000, freq1=1000, freq_pre=770, freq_end=770;
 135  	char *filetypes[] = {"binary","monitor","aiff","wave","disk"};
 136  	char *modeltypes[] = {"\b","I","II"};
 137  	char *ext;
 138  	unsigned int numseg = 0;
 139  	segment *segments = NULL;
 140  
 141  	opterr = 1;
 142  	while((c = getopt(argc, argv, "12vabcftdpn8meh?lqr:")) != -1)
 143  		switch(c) {
 144  			case '1':		// apple 1
 145  				rate = 8000;
 146  				model = 1;
 147  				break;
 148  			case '2':		// apple 2
 149  				model = 2;
 150  				break;
 151  			case 'v':		// version
 152  				fprintf(stderr,"\n%s\n\n",VERSION);
 153  				return 1;
 154  				break;
 155  			case 'a':		// assembly autoloader
 156  				model = 2;
 157  				autoload = 1;
 158  				break;
 159  			case 'b':		// basic autoloader
 160  				model = 2;
 161  				basicload = autoload = 1;
 162  				break;
 163  			case 'c':		// compression
 164  				model = 2;
 165  				autoload = compress = 1;
 166  				break;
 167  			case 'f':		// hifreq
 168  				rate = 48000;
 169  				model = 2;
 170  				autoload = fast = 1;
 171  				cd = k8 = 0;
 172  				break;
 173  			case 'd':		// hifreq CD
 174  				rate = 44100;
 175  				bits = 16;
 176  				amp = 1.0;
 177  				model = 2;
 178  				cd = autoload = 1;
 179  				fast = k8 = 0;
 180  				break;
 181  			case 't':		// 10 sec leader
 182  				tape = 6;
 183  				amp = 1.0;
 184  				break;
 185  			case 'm':		// drop to monitor after load
 186  				warm = 1;
 187  				break;
 188  			case 'e':		// end on page boundary 
 189  				endpage = 1;
 190  				break;
 191  			case 'p':		// stdout
 192  				fileoutput = 0;
 193  				break;
 194  			case 'n':
 195  				noformat = 1;
 196  				break;
 197  			case '8':		// 8k
 198  				rate = 48000;
 199  				model = 2;
 200  				autoload = k8 = 1;
 201  				fast = cd = 0;
 202  				break;
 203  			case 'h':		// help
 204  			case '?':
 205  				usage();
 206  				return 1;
 207  			case 'q':		// qr code support
 208  				rate = 48000;
 209  				model = 2;
 210  				autoload = k8 = qr = 1;
 211  				fast = cd = 0;
 212  				break;
 213  			case 'l':		// long mon lines
 214  				longmon = 1;
 215  				break;
 216  			case 'r':		// override rate for -1/-2 only
 217  				rate = atoi(optarg);
 218  				autoload = basicload = k8 = qr = fast = cd = 0;
 219  				break;
 220  		}
 221  
 222  	if(argc - optind < 1 + fileoutput) {
 223  		usage();
 224  		return 1;
 225  	}
 226  
 227  	// read intput files
 228  
 229  	fprintf(stderr,"\n");
 230  	for(i=optind;i<argc-fileoutput;i++) {
 231  		char start[5];
 232  		unsigned char b, *data;
 233  		int j, k, inputtype=BINARY;
 234  		segment *tmp;
 235  		FILE *ifp;
 236  
 237  		if((tmp = realloc(segments, (numseg+1) * sizeof(segment))) == NULL) {
 238  			fprintf(stderr,"could not allocate segment %d\n",numseg+1);
 239  			abort();
 240  		}
 241  		segments = tmp;
 242  
 243  		k=0;
 244  		for(j=0;j<strlen(argv[i]);j++) {
 245  			if(argv[i][j] == ',')
 246  				break;
 247  			segments[numseg].filename[k++]=argv[i][j];
 248  		}
 249  		segments[numseg].filename[k] = '\0';
 250  		// TODO: store as basename, check for MINGW compat
 251  
 252  		k=0;j++;
 253  		for(;j<strlen(argv[i]);j++)
 254  			start[k++]=argv[i][j];
 255  		start[k] = '\0';
 256  		if(k == 0)
 257  			segments[numseg].start = -1;
 258  		else
 259  			segments[numseg].start = (int)strtol(start, (char **)NULL, 16);
 260  
 261  		if((ext = getext(segments[numseg].filename)) != NULL)
 262  			if(strcmp(ext,"mon") == 0)
 263  				inputtype = MONITOR;
 264  
 265  		if((ext = getext(segments[numseg].filename)) != NULL)
 266  			if(strcmp(ext,"dsk") == 0)
 267  				inputtype = DSK;
 268  
 269  //TODO: Windows needs "rb", check UNIX/Linux
 270  
 271  		if ((ifp = fopen(segments[numseg].filename, "rb")) == NULL) {
 272  			fprintf(stderr,"Cannot read: %s\n\n",segments[numseg].filename);
 273  			return 1;
 274  		}
 275  
 276  		fprintf(stderr,"Reading %s, type %s, segment %d, start: ",segments[numseg].filename,filetypes[inputtype],numseg+1);
 277  
 278  //hack to support dumping disks for testing, should be 48, not 140 (really should be dynamic)
 279  
 280  		if((data = malloc(140*1024*sizeof(char))) == NULL) {
 281  			fprintf(stderr,"could not allocate 140K data\n");
 282  			abort();
 283  		}
 284  
 285  		if(inputtype == DSK) {
 286  			dsk = 1;
 287  			segments[numseg].length = 0;
 288  			for(i=0;i<5;i++) {
 289  				//segments[numseg].start=i*(140 * 1024 / 5);
 290  				segments[numseg].start=0x1000;
 291  
 292  				while(fread(&b, 1, 1, ifp) == 1 && segments[numseg].length < (140 * 1024 / 5))
 293  					data[segments[numseg].length++]=b;
 294  
 295  				segments[numseg].data = data;
 296  				fprintf(stderr,"0x%04X, length: %d\n",segments[numseg].start,segments[numseg].length);
 297  
 298  				if(segments[numseg].length != (140 * 1024 / 5)) {
 299  					fprintf(stderr,"\n%s segment too short (< %d) for file type DISK\n\n",segments[numseg].filename,140*1024/5);
 300  					return 1;
 301  				}
 302  
 303  				if(i==4)
 304  					break;
 305  
 306  				numseg++;
 307  				if((tmp = realloc(segments, (numseg+1) * sizeof(segment))) == NULL) {
 308  					fprintf(stderr,"could not allocate segment %d\n",numseg+1);
 309  					abort();
 310  				}
 311  				segments = tmp;
 312  				strcpy(segments[numseg].filename,segments[numseg-1].filename);
 313  				segments[numseg].length = 0;
 314  				if((data = malloc(48*1024*sizeof(char))) == NULL) {
 315  					fprintf(stderr,"could not allocate 48K data\n");
 316  					abort();
 317  				}
 318  				data[segments[numseg].length++]=b;
 319  
 320  				fprintf(stderr,"Reading %s, type %s, segment %d, start: ",segments[numseg].filename,filetypes[inputtype],numseg+1);
 321  			}
 322  		}
 323  
 324  		if(inputtype == BINARY) {
 325  			if(segments[numseg].start == -1) {
 326  				fread(&b, 1, 1, ifp);
 327  				segments[numseg].start = b;
 328  				fread(&b, 1, 1, ifp);
 329  				segments[numseg].start |= b << 8;
 330  				fread(&b, 1, 1, ifp);
 331  				segments[numseg].length = b;
 332  				fread(&b, 1, 1, ifp);
 333  				segments[numseg].length |= b << 8;
 334  			}
 335  
 336  			segments[numseg].length=0;
 337  			while(fread(&b, 1, 1, ifp) == 1)
 338  				data[segments[numseg].length++]=b;
 339  
 340  			segments[numseg].data = data;
 341  			fprintf(stderr,"0x%04X, length: %d\n",segments[numseg].start,segments[numseg].length);
 342  		}
 343  
 344  		if(inputtype == MONITOR) {
 345  			int byte, naddr;
 346  			char addrs[8], s;
 347  
 348  			segments[numseg].start = -1;
 349  			segments[numseg].length = 0;
 350  
 351  			while(fscanf(ifp,"%s ",addrs) != EOF) {
 352  				naddr = (int)strtol(addrs, (char **)NULL, 16);
 353  				if(segments[numseg].start == -1)
 354  					segments[numseg].start = naddr;
 355  	
 356  				if(naddr != segments[numseg].start + segments[numseg].length) { // multi segment
 357  					segments[numseg].data = data;
 358  					fprintf(stderr,"0x%04X, length: %d\n",segments[numseg].start,segments[numseg].length);
 359  					numseg++;
 360  					if((tmp = realloc(segments, (numseg+1) * sizeof(segment))) == NULL) {
 361  						fprintf(stderr,"could not allocate segment %d\n",numseg+1);
 362  						abort();
 363  					}
 364  					segments = tmp;
 365  					if((data = malloc(48*1024*sizeof(char))) == NULL) {
 366  						fprintf(stderr,"could not allocate 48K data\n");
 367  						abort();
 368  					}
 369  					segments[numseg].start = naddr;
 370  					segments[numseg].length = 0;
 371  					strcpy(segments[numseg].filename,segments[numseg-1].filename);
 372  					fprintf(stderr,"Reading %s, type %s, segment %d, start: ",segments[numseg].filename,filetypes[inputtype],numseg+1);
 373  				}
 374  	
 375  				while (fscanf(ifp, "%x%c", &byte, &s) != EOF) {
 376  					data[segments[numseg].length++]=byte;
 377  					if (s == '\n' || s == '\r')
 378  						break;
 379  				}
 380  			}
 381  			segments[numseg].data = data;
 382  			fprintf(stderr,"0x%04X, length: %d\n",segments[numseg].start,segments[numseg].length);
 383  		}
 384  
 385  		fclose(ifp);
 386  		numseg++;
 387  	}
 388  	fprintf(stderr,"\n");
 389  
 390  	if(dsk) {
 391  		fast=autoload=cd=tape=0;
 392  		model=2;
 393  
 394  		if(numseg != 5) {
 395  			fprintf(stderr,"Number of segments != 5 and/or not of length %d\n\n",140*1024/5);
 396  			return 1;
 397  		}
 398  		else {
 399  			for(i=0;i<5;i++) {
 400  				if(segments[i].length != 140*1024/5) {
 401  					fprintf(stderr,"Number of segments != 5 and/or not of length %d\n\n",140*1024/5);
 402  					return 1;
 403  				}
 404  			}	
 405  		}
 406  	}
 407  
 408  	if(endpage)
 409  		for(i=0;i<numseg;i++) {
 410  			int pad = (0xFF - ((segments[i].length + segments[i].start - 1) & 0xFF));
 411  
 412  			segments[i].length += pad;
 413  			while(pad--)
 414  				segments[i].data[segments[i].length - pad - 1] = 0;
 415  		}
 416  
 417  	if(numseg > 1 || model == 1) {
 418  		if(autoload)
 419  			fprintf(stderr,"WARNING: number of segments > 1 or model = 1: autoload and fast disabled.\n\n");
 420  		autoload = fast = 0;
 421  	}
 422  
 423  	if(fileoutput) {
 424  		if((ext = getext(OUTFILE)) == NULL) {
 425  			usage();
 426  			return 1;
 427  		}
 428  		else {
 429  			if(strcmp(ext,"aiff") == 0 || strcmp(ext,"aif") == 0)
 430  				outputtype = AIFF;
 431  			else if(strcmp(ext,"wave") == 0 || strcmp(ext,"wav") == 0)
 432  				outputtype = WAVE;
 433  			else if(strcmp(ext,"mon") == 0)
 434  				outputtype = MONITOR;
 435  			else {
 436  				usage();
 437  				return 1;
 438  			}
 439  		}
 440  	}
 441  	else {
 442  /*
 443  		if(!model)
 444  			outputtype = MONITOR;
 445  		else
 446  			outputtype = AIFF;
 447  */
 448  		outputtype = MONITOR;
 449  	}
 450  
 451  	if(outputtype != MONITOR && !model) {
 452  		fprintf(stderr,"\nYou must specify -1 or -2 for Apple I or II tape format, exiting.\n\n");
 453  		return 1;
 454  	}
 455  
 456  	// TODO: check for existing file and abort, or warn, or prompt
 457  
 458  	ofp=stdout;
 459  	if(fileoutput) {
 460  		if ((ofp = fopen(OUTFILE, "w")) == NULL) {
 461  			fprintf(stderr,"\nCannot write: %s\n\n",OUTFILE);
 462  			return 1;
 463  		}
 464  		fprintf(stderr,"Writing %s as Apple %s formatted %s.\n\n",OUTFILE,modeltypes[model],filetypes[outputtype]);
 465  	}
 466  	else
 467  		fprintf(stderr,"Writing %s as Apple %s formatted %s.\n\n","STDOUT",modeltypes[model],filetypes[outputtype]);
 468  
 469  	if(outputtype == MONITOR) {
 470  		int i, j, saddr;
 471  		// unsigned long cmp_len;
 472  		size_t cmp_len;
 473  		unsigned char *cmp_data;
 474  
 475  		for(i=0;i<numseg;i++) {
 476  			if(compress) {
 477  				cmp_data = tdefl_compress_mem_to_heap(segments[i].data, segments[i].length, &cmp_len, TDEFL_MAX_PROBES_MASK);
 478  				free(segments[i].data);
 479  				segments[i].data = cmp_data;
 480  				segments[i].length = cmp_len;
 481  			}
 482  			saddr = segments[i].start;
 483  			fprintf(ofp,"%04X:", saddr);
 484  			for(j=0;j<segments[i].length;j++) {
 485  				fprintf(ofp," %02X", segments[i].data[j]);
 486  				if(++saddr % (8+(24*longmon)) == 0 && j < segments[i].length - 1)
 487  					fprintf(ofp,"\n%04X:",saddr);
 488  			}
 489  			fprintf(ofp,"\n");
 490  		}
 491  
 492  		fclose(ofp);
 493  		return 0;
 494  	}
 495  
 496  	// write out code
 497  	if(!autoload  && !dsk) {
 498  		int i, j;
 499  		//unsigned long cmp_len;
 500  		size_t cmp_len;
 501  		unsigned char *cmp_data;
 502  		char checksum;
 503  
 504  		for(i=0;i<numseg;i++) {
 505  			// header
 506  			if(model == 1) {
 507  				appendtone(&output,&outputlength,1000,rate,4.0+tape,0,&offset);
 508  				appendtone(&output,&outputlength,2000,rate,0,1,&offset);
 509  			}
 510  			else {
 511  				appendtone(&output,&outputlength,770,rate,4.0+tape,0,&offset);
 512  				appendtone(&output,&outputlength,2500,rate,0,0.5,&offset);
 513  				appendtone(&output,&outputlength,2000,rate,0,0.5,&offset);
 514  			}
 515  			checksum = 0xff;
 516  
 517  			if(compress) {
 518  				cmp_data = tdefl_compress_mem_to_heap(segments[i].data, segments[i].length, &cmp_len, TDEFL_MAX_PROBES_MASK);
 519  				free(segments[i].data);
 520  				segments[i].data = cmp_data;
 521  				segments[i].length = cmp_len;
 522  			}
 523  			for(j=0;j<segments[i].length;j++) {
 524  				WRITEBYTE(segments[i].data[j]);
 525  				checksum ^= segments[i].data[j];
 526  			}
 527  	
 528  			// checksum/endbits
 529  			if(model == 2)
 530  				WRITEBYTE(checksum);
 531  			appendtone(&output,&outputlength,1000,rate,0,1,&offset);
 532  		}
 533  
 534  		// friendly help
 535  		fprintf(stderr,"To load up and run on your Apple %s, type:\n\n",modeltypes[model]);
 536  		if(model == 1)
 537  			fprintf(stderr,"\tC100R\n\t");
 538  		else
 539  			fprintf(stderr,"\tCALL -151\n\t");
 540  
 541  		for(i=0;i<numseg;i++)
 542  			fprintf(stderr,"%X.%XR ",segments[i].start,segments[i].start+segments[i].length-1);
 543  		fprintf(stderr,"\n");
 544  
 545  		if(numseg == 1) {
 546  			if(model == 1)
 547  				fprintf(stderr,"\t%XR\n",segments[0].start);
 548  			else
 549  				fprintf(stderr,"\t%XG\n",segments[0].start);
 550  		}
 551  		fprintf(stderr,"\n");
 552  	}
 553  
 554  	if(autoload) {
 555  		char eta[40], loading[]=" LOADING ";
 556  		unsigned char byte, checksum, *cmp_data, table[12];
 557  		unsigned long ones=0, zeros=0;
 558  		size_t cmp_len;
 559  		unsigned int length, move_len;
 560  		int i, j;
 561  
 562  		appendtone(&output,&outputlength,770,rate,4.0+tape,0,&offset);
 563  		appendtone(&output,&outputlength,2500,rate,0,0.5,&offset);
 564  		appendtone(&output,&outputlength,2000,rate,0,0.5,&offset);
 565  
 566  		// compute uncompressed ETA
 567  		for(j=0;j<segments[0].length;j++) {
 568  			byte=segments[0].data[j];
 569  			for(i=0;i<8;i++) {
 570  				if(byte & 0x80)
 571  					ones++;
 572  				else
 573  					zeros++;
 574  				byte <<= 1;
 575  			}
 576  		}
 577  
 578  		if(fast) {
 579  			freq0 = 12000;
 580  			freq1 = 8000;
 581  			freq_pre = 6000;
 582  			freq_end = 2000;
 583  		}
 584  		if(k8) {
 585  			freq0 = 12000;
 586  			freq1 = 6000;
 587  			freq_pre = 2000;
 588  			freq_end = 770;
 589  		}
 590  		if(cd) {
 591  			freq0 = 11025;
 592  			freq1 = 7350;
 593  			freq_pre = 5512;
 594  			freq_end = 2000;
 595  		}
 596  
 597  		if(compress) {
 598  			unsigned long cmp_ones=0, cmp_zeros=0;
 599  			double inflate_time = 0;
 600  			unsigned int endj;
 601  
 602  			cmp_data = tdefl_compress_mem_to_heap(segments[0].data, segments[0].length, &cmp_len, TDEFL_MAX_PROBES_MASK);
 603  
 604  			for(j=0;j<cmp_len;j++) {
 605  				byte=cmp_data[j];
 606  				for(i=0;i<8;i++) {
 607  					if(byte & 0x80)
 608  						cmp_ones++;
 609  					else
 610  						cmp_zeros++;
 611  					byte <<= 1;
 612  				}
 613  			}
 614  
 615  			// we need to append inflate/decompress code to end of data
 616  			for(j=0;j<sizeof(inflatecode)/sizeof(char);j++) {
 617  				byte=inflatecode[j];
 618  				for(i=0;i<8;i++) {
 619  					if(byte & 0x80)
 620  						cmp_ones++;
 621  					else
 622  						cmp_zeros++;
 623  					byte <<= 1;
 624  				}
 625  			}
 626  
 627  			//compute inflate time
 628  
 629  			//load up inflate data
 630  			checksum = 0xff;
 631  			for(j=0;j<cmp_len;j++) {
 632  				ram[0xBA00 - cmp_len + j] = cmp_data[j];
 633  				checksum ^= cmp_data[j];
 634  			}
 635  			//load up inflate code
 636  			for(j=0;j<sizeof(inflatecode)/sizeof(char);j++) {
 637  				ram[0xBA00 + j] = inflatecode[j];
 638  				checksum ^= inflatecode[j];
 639  			}
 640  			ram[0xBA00 + j] = checksum;
 641  			endj = 0xBA00 + j + 1;
 642  
 643  			if(k8) {
 644  				for(j=(0x823 - 0x80C);j<sizeof(fastload8000)/sizeof(char);j++)
 645  					ram[0xBE80 - (0x823 - 0x80C) + j] = fastload8000[j];
 646  				ram[0xBE80 - (0x823 - 0x80C) + j++] = (0xBA00 - cmp_len) & 0xFF;
 647  				ram[0xBE80 - (0x823 - 0x80C) + j++] = (0xBA00 - cmp_len) >> 8;
 648  				ram[0xBE80 - (0x823 - 0x80C) + j++] = endj & 0xFF;
 649  				ram[0xBE80 - (0x823 - 0x80C) + j++] = endj >> 8;
 650  				ram[0x00] = 0xFF;
 651  				ram[0xBF09] = 0x00; //BRK
 652  
 653  				reset6502();
 654  				exec6502(0xBEE3);
 655  
 656  				if(ram[0x00] != 0)
 657  					fprintf(stderr,"WARNING: simulated checksum failed: %02X\n",ram[0x00]);
 658  
 659  				inflate_time += clockticks6502/1023000.0;
 660  			}
 661  
 662  			//zero page src
 663  			ram[0x0] = (0xBA00 - cmp_len) & 0xFF;
 664  			ram[0x1] = (0xBA00 - cmp_len) >> 8;
 665  			//zero page dst
 666  			ram[0x2] = (segments[0].start) & 0xFF; 
 667  			ram[0x3] = (segments[0].start) >> 8;
 668  			//setup JSR
 669  			ram[0xBF00] = 0x20; // JSR $9B00
 670  			ram[0xBF01] = 0x00;
 671  			ram[0xBF02] = 0xBA;
 672  			ram[0xBF03] = 0x00; //BRK to stop simulation
 673  			//run it
 674  			reset6502();
 675  			exec6502(0xBF00);
 676  			//compare (just to be safe)
 677  			for(j=0;j<segments[0].length;j++)
 678  				if(ram[segments[0].start + j] != segments[0].data[j]) {
 679  					fprintf(stderr,"WARNING: simulated inflate failed at %04X\n",j+0x1000);
 680  					break;
 681  				}
 682  			inflate_time += clockticks6502/1023000.0;
 683  
 684  			fprintf(stderr,"start: 0x%04X, length: %5d, deflated: %.02f%%, data time:%.02f, inflate time:%.02f\n",(unsigned int)(0xB9FF - cmp_len),(unsigned int)cmp_len,100.0*(1-cmp_len/(float)segments[0].length),cmp_ones/(float)freq1 + cmp_zeros/(float)freq0,inflate_time);
 685  
 686  			if((ones/(float)freq1 + zeros/(float)freq0) < inflate_time + (cmp_ones/(float)freq1 + cmp_zeros/(float)freq0)) {
 687  				fprintf(stderr,"WARNING: compression disabled: no significant gain (%.02f)\n",ones/(float)freq1 + zeros/(float)freq0);
 688  				compress = 0;
 689  			}
 690  			else {
 691  				free(segments[0].data);
 692  				segments[0].data = cmp_data;
 693  				segments[0].codelength = segments[0].length;
 694  				segments[0].length = cmp_len;
 695  				ones=cmp_ones;
 696  				zeros=cmp_zeros;
 697  			}
 698  			fprintf(stderr,"\n");
 699  		}
 700  
 701  		sprintf(eta,", ETA %d SEC. ",(int) (ones/(float)freq1 + zeros/(float)freq0 + 0.5 + 0.25 + (3.75 * ((k8|cd|fast) == 0))) );
 702  
 703  		length = sizeof(basic)/sizeof(char) + sizeof(table)/sizeof(char) + strlen(loading) + strlen(segments[0].filename) + strlen(eta) + 1;
 704  
 705  		move_len = (0x823 - 0x80C);
 706  		if(fast)
 707  			length += sizeof(fastload9600)/sizeof(char);
 708  		else
 709  			if(k8)
 710  				length += sizeof(fastload8000)/sizeof(char);
 711  			else
 712  				if(cd)
 713  					length += sizeof(fastloadcd)/sizeof(char);
 714  				else {
 715  					length += sizeof(autoloadcode)/sizeof(char);
 716  					move_len = (0x81A - 0x80C);
 717  				}
 718  
 719  		if(fast | k8 | cd) {
 720  			if(length - sizeof(basic)/sizeof(char) - move_len > 384) {
 721  				segments[0].filename[strlen(segments[0].filename) - (length - sizeof(basic)/sizeof(char) - move_len - 384)] = '\0';
 722  				fprintf(stderr,"WARNING: BF00 page overflow: truncating display filename to %s\n\n",segments[0].filename);
 723  				length = 384 + sizeof(basic)/sizeof(char) + move_len;
 724  			}
 725  		}
 726  		else {
 727  			if(length - sizeof(basic)/sizeof(char) - move_len > 256) {
 728  				segments[0].filename[strlen(segments[0].filename) - (length - sizeof(basic)/sizeof(char) - move_len - 256)] = '\0';
 729  				fprintf(stderr,"WARNING: BF00 page overflow: truncating display filename to %s\n\n",segments[0].filename);
 730  				length = 256 + sizeof(basic)/sizeof(char) + move_len;
 731  			}
 732  		}
 733  
 734  		freq0 = 2000;
 735  		freq1 = 1000;
 736  		checksum = 0xff;
 737  
 738  		if(basicload) { // write basic stub
 739  			header[0] = length & 0xFF;
 740  			header[1] = length >> 8;
 741  			for(i=0;i<3;i++) {
 742  				WRITEBYTE(header[i]);
 743  				checksum ^= header[i];
 744  			}
 745  			WRITEBYTE(checksum);
 746  
 747  			appendtone(&output,&outputlength,1000,rate,0,1,&offset);
 748  			appendtone(&output,&outputlength,770,rate,4.0,0,&offset);
 749  			appendtone(&output,&outputlength,2500,rate,0,0.5,&offset);
 750  			appendtone(&output,&outputlength,2000,rate,0,0.5,&offset);
 751  
 752  			// write out basic program
 753  			checksum = 0xff;
 754  			for(i=0;i<sizeof(basic)/sizeof(char);i++) {
 755  				WRITEBYTE(basic[i]);
 756  				checksum ^= basic[i];
 757  			}
 758  		}
 759  		else { // write out JMP 80C NOP NOP ...
 760  			unsigned char patch[] = {0x4C,0x0C,0x08,0xEA,0xEA,0xEA,0xEA,0xEA,0xEA,0xEA,0xEA,0xEA};
 761  			for(i=0;i<sizeof(patch)/sizeof(char);i++) {
 762  				WRITEBYTE(patch[i]);
 763  				checksum ^= patch[i];
 764  			}
 765  		}
 766  
 767  		// write out move and load code
 768  		if(compress) {
 769  			unsigned int cmp_start = 0xBA00 - segments[0].length;
 770  
 771  			//load start
 772  			table[0] = cmp_start & 0xff;
 773  			table[1] = cmp_start >> 8;
 774  
 775  			//load end
 776  			table[2] = (cmp_start + segments[0].length + sizeof(inflatecode)/sizeof(char) + 1) & 0xff;
 777  			table[3] = (cmp_start + segments[0].length + sizeof(inflatecode)/sizeof(char) + 1) >> 8;
 778  
 779  			//inflate src
 780  			table[4] = cmp_start & 0xff;
 781  			table[5] = cmp_start >> 8;
 782  
 783  			//inflate end
 784  			table[8] = (segments[0].start + segments[0].codelength) & 0xff;
 785  			table[9] = (segments[0].start + segments[0].codelength) >> 8;
 786  		}
 787  		else {
 788  			//load start
 789  			table[0] = segments[0].start & 0xff;
 790  			table[1] = segments[0].start >> 8;
 791  
 792  			//load end
 793  			table[2] = (segments[0].start + segments[0].length + 1) & 0xff;
 794  			table[3] = (segments[0].start + segments[0].length + 1) >> 8;
 795  		}
 796  		//JMP to code, inflate dst
 797  		table[6] = segments[0].start & 0xff;
 798  		table[7] = segments[0].start >> 8;
 799  		table[10] = compress;
 800  		table[11] = warm;
 801  
 802  		if(fast)
 803  			for(i=0;i<sizeof(fastload9600)/sizeof(char);i++) {
 804  				WRITEBYTE(fastload9600[i]);
 805  				checksum ^= fastload9600[i];
 806  			}
 807  		else
 808  			if(k8)
 809  				for(i=0;i<sizeof(fastload8000)/sizeof(char);i++) {
 810  					WRITEBYTE(fastload8000[i]);
 811  					checksum ^= fastload8000[i];
 812  				}
 813  			else
 814  				if(cd)
 815  					for(i=0;i<sizeof(fastloadcd)/sizeof(char);i++) {
 816  						WRITEBYTE(fastloadcd[i]);
 817  						checksum ^= fastloadcd[i];
 818  					}
 819  				else
 820  					for(i=0;i<sizeof(autoloadcode)/sizeof(char);i++) {
 821  						WRITEBYTE(autoloadcode[i]);
 822  						checksum ^= autoloadcode[i];
 823  					}
 824  
 825  		// append table
 826  		for(i=0;i<sizeof(table)/sizeof(char);i++) {
 827  			WRITEBYTE(table[i]);
 828  			checksum ^= table[i];
 829  		}
 830  
 831  		// append LOADING...
 832  		loading[0] = 0x0D;
 833  		for(i=0;i<strlen(loading);i++) {
 834  			byte = toupper(loading[i]) + 0x80;
 835  			if(loading[i] == '_')
 836  				byte = toupper(' ') + 0x80;
 837  			WRITEBYTE(byte);
 838  			checksum ^= byte;
 839  		}
 840  
 841  		// append to loader the name of the file
 842  		for(i=0;i<strlen(segments[0].filename);i++) {
 843  			byte = toupper(segments[0].filename[i]) + 0x80;
 844  			if(segments[0].filename[i] == '_')
 845  				byte = toupper(' ') + 0x80;
 846  			WRITEBYTE(byte);
 847  			checksum ^= byte;
 848  		}
 849  
 850  		// append to loader the ETA
 851  		for(i=0;i<strlen(eta);i++) {
 852  			byte = toupper(eta[i]) + 0x80;
 853  			WRITEBYTE(byte);
 854  			checksum ^= byte;
 855  		}
 856  
 857  		// append to NULL to LOADING string
 858  		WRITEBYTE(0x00);
 859  		checksum ^= 0x00;
 860  
 861  		// it's a wrap!
 862  		WRITEBYTE(0xff);
 863  		checksum ^= 0xff;
 864  
 865  		if(!basicload) {
 866  			int pad = (0xFF - (length & 0xFF));
 867  
 868  			if(!(fast|cd|k8))
 869  				pad += 0x100;
 870  
 871  			length += pad;
 872  			while(pad--)
 873  				WRITEBYTE(0x00);
 874  		}
 875  
 876  		WRITEBYTE(checksum);
 877  
 878  		appendtone(&output,&outputlength,1000,rate,0,1,&offset);
 879  		if(fast || cd || k8)
 880  			appendtone(&output,&outputlength,freq_pre,rate,0.25,0,&offset);
 881  		else {
 882  			appendtone(&output,&outputlength,770,rate,4.0,0,&offset);
 883  			appendtone(&output,&outputlength,2500,rate,0,0.5,&offset);
 884  			appendtone(&output,&outputlength,2000,rate,0,0.5,&offset);
 885  		}
 886  
 887  		// now the code
 888  		if(fast) {
 889  			freq0 = 12000;
 890  			freq1 = 8000;
 891  		}
 892  		if(cd) {
 893  			freq0 = 11025;
 894  			freq1 = 7350;
 895  		}
 896  		if(k8) {
 897  			freq0 = 12000;
 898  			freq1 = 6000;
 899  		}
 900  
 901  		if(qr) {
 902  			char loading[]="LOADING ";
 903  			outputlength = 0;
 904  
 905  			// 0.25 sec
 906  			appendtone(&output,&outputlength,freq_pre,rate,0.25,0,&offset);
 907  
 908  			checksum = 0xff;
 909  
 910  			// parameters, 12 bytes
 911  			for(i=0;i<sizeof(table)/sizeof(char);i++) {
 912  				WRITEBYTE(table[i]);
 913  				checksum ^= table[i];
 914  			}
 915  
 916  			// LOADING
 917  			for(i=0;i<strlen(loading);i++) {
 918  				byte = loading[i] + 0x80;
 919  				WRITEBYTE(byte);
 920  				checksum ^= byte;
 921  			}
 922  
 923  			// append to loader the name of the file
 924  			for(i=0;i<strlen(segments[0].filename);i++) {
 925  				byte = toupper(segments[0].filename[i]) + 0x80;
 926  				if(segments[0].filename[i] == '_')
 927  					byte = toupper(' ') + 0x80;
 928  				WRITEBYTE(byte);
 929  				checksum ^= byte;
 930  			}
 931  
 932  			// append to loader the ETA
 933  			for(i=0;i<strlen(eta);i++) {
 934  				byte = toupper(eta[i]) + 0x80;
 935  				WRITEBYTE(byte);
 936  				checksum ^= byte;
 937  			}
 938  
 939  			for(i=0;i<60-strlen(segments[0].filename)-strlen(eta)-strlen(loading);i++) {
 940  				WRITEBYTE(0x00);
 941  				checksum ^= 0x00;
 942  			}
 943  
 944  			WRITEBYTE(checksum);
 945  
 946  			// end of parameters
 947  			appendtone(&output,&outputlength,freq_end,rate,0,2,&offset);
 948  
 949  			// time to processes
 950  			appendtone(&output,&outputlength,freq_pre,rate,0.25,0,&offset);
 951  		}
 952  
 953  		checksum = 0xff;
 954  		for(j=0;j<segments[0].length;j++) {
 955  			WRITEBYTE(segments[0].data[j]);
 956  			checksum ^= segments[0].data[j];
 957  		}
 958  
 959  		if(compress) {
 960  			for(j=0;j<sizeof(inflatecode)/sizeof(char);j++) {
 961  				WRITEBYTE(inflatecode[j]);
 962  				checksum ^= inflatecode[j];
 963  			}
 964  		}
 965  
 966  		if(fast + cd + k8 == 0) {	// hack so that standard method matches others
 967  			WRITEBYTE(0x00);
 968  			WRITEBYTE(0x00);
 969  		}
 970  
 971  		WRITEBYTE(checksum);
 972  
 973  		if(fast || cd || k8)
 974  			//appendtone(&output,&outputlength,freq_end,rate,0,1,&offset);
 975  			appendtone(&output,&outputlength,freq_end,rate,0,10,&offset);
 976  		else
 977  			//appendtone(&output,&outputlength,1000,rate,0,1,&offset);
 978  			appendtone(&output,&outputlength,1000,rate,0,10,&offset);
 979  
 980  		if(!qr) {
 981  			if(basicload) {
 982  				fprintf(stderr,"To load up and run on your Apple %s, type:\n\n\tLOAD\n",modeltypes[model]);
 983  				if(warm)
 984  					fprintf(stderr,"\t%XG\n",segments[0].start);
 985  			}
 986  			else {
 987  				fprintf(stderr,"To load up and run on your Apple %s, type:\n\n\t800.%XR 800G\n",modeltypes[model],0x800 + length + 1);
 988  			}
 989  		}
 990  		else {
 991  			fprintf(stderr,"To load up and run on your Apple %s, use the client disk.\n",modeltypes[model]);
 992  		}
 993  		fprintf(stderr,"\n");
 994  	}
 995  
 996  	if(dsk) {
 997  		char eta[40];
 998  		unsigned char byte, checksum=0xff, *cmp_data, start_table[21], *diskloadcode;
 999  		unsigned long ones=0, zeros=0, diskloadcode_len;
1000  		size_t cmp_len;
1001  		unsigned int length, start_table_len = 0;
1002  		int i, j;
1003  		double inflate_times[5];
1004  
1005  		if(k8) {
1006  			diskloadcode = diskload8000;
1007  			diskloadcode_len = sizeof(diskload8000)/sizeof(char);
1008  		}
1009  		else {
1010  			diskloadcode = diskload9600;
1011  			diskloadcode_len = sizeof(diskload9600)/sizeof(char);
1012  		}
1013  
1014  		rate = 48000;
1015  		appendtone(&output,&outputlength,770,rate,4.0+tape,0,&offset);
1016  		appendtone(&output,&outputlength,2500,rate,0,0.5,&offset);
1017  		appendtone(&output,&outputlength,2000,rate,0,0.5,&offset);
1018  
1019  		for(j=0;j<sizeof(diskloadcode2)/sizeof(char);j++) {
1020  			byte=diskloadcode2[j];
1021  			for(i=0;i<8;i++) {
1022  				if(byte & 0x80)
1023  					ones++;
1024  				else
1025  					zeros++;
1026  				byte <<= 1;
1027  			}
1028  		}
1029  
1030  		// compute pad length, assuming 4 pages max for code
1031  		zeros += 8*(4 * 256 - sizeof(diskloadcode2)/sizeof(char));
1032  
1033  		for(j=0;j<sizeof(diskloadcode3)/sizeof(char);j++) {
1034  			byte=diskloadcode3[j];
1035  			for(i=0;i<8;i++) {
1036  				if(byte & 0x80)
1037  					ones++;
1038  				else
1039  					zeros++;
1040  				byte <<= 1;
1041  			}
1042  		}
1043  
1044  		for(j=0;j<sizeof(dosboot1)/sizeof(char);j++) {
1045  			byte=dosboot1[j];
1046  			for(i=0;i<8;i++) {
1047  				if(byte & 0x80)
1048  					ones++;
1049  				else
1050  					zeros++;
1051  				byte <<= 1;
1052  			}
1053  		}
1054  
1055  		for(j=0;j<sizeof(dosboot2)/sizeof(char);j++) {
1056  			byte=dosboot2[j];
1057  			for(i=0;i<8;i++) {
1058  				if(byte & 0x80)
1059  					ones++;
1060  				else
1061  					zeros++;
1062  				byte <<= 1;
1063  			}
1064  		}
1065  
1066  		freq0 = 12000;
1067  		freq1 = 8000;
1068  		if(k8)
1069  			freq1 = 6000;
1070  		sprintf(eta,"%d SEC. ",(int) (ones/(float)freq1 + zeros/(float)freq0 + 0.5 + 0.25));
1071  
1072  		//length = sizeof(basic)/sizeof(char) + sizeof(diskloadcode)/sizeof(char);
1073  		length = sizeof(basic)/sizeof(char) + diskloadcode_len;
1074  		header[0] = length & 0xFF;
1075  		header[1] = length >> 8;
1076  
1077  		freq0 = 2000;
1078  		freq1 = 1000;
1079  		for(i=0;i<3;i++) {
1080  			WRITEBYTE(header[i]);
1081  			checksum ^= header[i];
1082  		}
1083  		WRITEBYTE(checksum);
1084  
1085  		appendtone(&output,&outputlength,1000,rate,0,1,&offset);
1086  		appendtone(&output,&outputlength,770,rate,4.0,0,&offset);
1087  		appendtone(&output,&outputlength,2500,rate,0,0.5,&offset);
1088  		appendtone(&output,&outputlength,2000,rate,0,0.5,&offset);
1089  
1090  		// write out basic program
1091  		checksum = 0xff;
1092  		for(i=0;i<sizeof(basic)/sizeof(char);i++) {
1093  			WRITEBYTE(basic[i]);
1094  			checksum ^= basic[i];
1095  		}
1096  
1097  		// patch in ETA
1098  		for(i=0;i<strlen(eta);i++)
1099  			diskloadcode[0x84F - 0x80C + i] = eta[i] + 0x80;
1100  
1101  		// write out move and load code
1102  		//for(i=0;i<sizeof(diskloadcode)/sizeof(char);i++) {
1103  		for(i=0;i<diskloadcode_len;i++) {
1104  			WRITEBYTE(diskloadcode[i]);
1105  			checksum ^= diskloadcode[i];
1106  		}
1107  
1108  		// end of basic and diskloadcode
1109  		WRITEBYTE(0xff);
1110  		checksum ^= 0xff;
1111  
1112  		WRITEBYTE(checksum);
1113  
1114  		appendtone(&output,&outputlength,1000,rate,0,1,&offset);
1115  		square=0;
1116  		freq0 = 12000;
1117  		if(k8) {
1118  			freq1 = 6000;
1119  			appendtone(&output,&outputlength,2000,rate,0.25,0,&offset);
1120  		}
1121  		else {
1122  			freq1 = 8000;
1123  			appendtone(&output,&outputlength,6000,rate,0.25,0,&offset);
1124  		}
1125  
1126  		checksum = 0xff;
1127  		for(i=0;i<sizeof(dosboot1)/sizeof(char);i++) {
1128  			WRITEBYTE(dosboot1[i]);
1129  			checksum ^= dosboot1[i];
1130  		}
1131  
1132  		// time to compress and compute start location and length
1133  		// patch loadcode2 with start locations and ETA
1134  		for(i=0;i<numseg;i++) {
1135  			int k, err;
1136  			double orig_len;
1137  			unsigned char checksum=0xff;
1138  
1139  			inflate_times[i] = 0;
1140  			
1141  			cmp_data = tdefl_compress_mem_to_heap(segments[i].data, segments[i].length, &cmp_len, TDEFL_MAX_PROBES_MASK);
1142  
1143  			//compute inflate time
1144  			//load up inflate code
1145  			for(j=0;j<sizeof(diskloadcode3)/sizeof(char);j++)
1146  				ram[0x9B00 + j] = diskloadcode3[j];
1147  			//load up inflate data
1148  			for(j=0;j<cmp_len;j++) {
1149  				ram[0x8FFF - cmp_len + j] = cmp_data[j];
1150  				checksum ^= cmp_data[j];
1151  			}
1152  			ram[0x8FFF] = checksum;
1153  
1154  			//compute chksum time
1155  			if(k8) {
1156  				for(j=(0x859 - 0x80C);j<diskloadcode_len;j++)
1157  					ram[0x9000 - (0x859 - 0x80C) + j] = diskloadcode[j];
1158  				ram[0x00] = (0x8FFF - cmp_len) & 0xFF;
1159  				ram[0x01] = (0x8FFF - cmp_len) >> 8;
1160  				ram[0x02] = 0x00;
1161  				ram[0x03] = 0x90;
1162  				ram[0x04] = 0xFF;
1163  				ram[0x9089] = 0x85; //STA
1164  				ram[0x908A] = 0x04; //zero page $04
1165  				ram[0x908B] = 0x00; //BRK
1166  
1167  				reset6502();
1168  				exec6502(0x9065);
1169  
1170  				if(ram[0x04] != 0)
1171  					fprintf(stderr,"WARNING: simulated checksum failed: %02X\n",ram[0x04]);
1172  
1173  				inflate_times[i] += clockticks6502/1023000.0;
1174  			}
1175  
1176  			//zero page src
1177  			ram[0x10] = (0x8FFF - cmp_len) & 0xFF;
1178  			ram[0x11] = (0x8FFF - cmp_len) >> 8;
1179  			//zero page dst
1180  			ram[0x12] = 0x00;
1181  			ram[0x13] = 0x10;
1182  			//setup JSR
1183  			ram[0x9000] = 0x20; // JSR $9B00
1184  			ram[0x9001] = 0x00;
1185  			ram[0x9002] = 0x9B;
1186  			ram[0x9003] = 0x00; //BRK to stop simulation
1187  			//run it
1188  			reset6502();
1189  			exec6502(0x9000);
1190  			//compare (just to be safe)
1191  			err=0;
1192  			for(j=0;j<7 * 4096;j++)
1193  				if(ram[0x1000 + j] != segments[i].data[j]) {
1194  					err = 1;
1195  					break;
1196  				}
1197  			if(err)
1198  				fprintf(stderr,"WARNING: simulated inflate failed at %04X\n",j+0x1000);
1199  			inflate_times[i] += clockticks6502/1023000.0;
1200  
1201  			free(segments[i].data);
1202  			segments[i].data = cmp_data;
1203  			orig_len = segments[i].length;
1204  			segments[i].length = cmp_len;
1205  			segments[i].start = 0x8FFF - segments[i].length;
1206  
1207  			// compress ?
1208  			// need to see what is faster, defaulting to compress for now
1209  			// if not compressed do not set start location, change asm code to check for 0,0
1210  			// and not use inflate code
1211  
1212  			// where to load data
1213  			start_table[start_table_len++] = segments[i].start & 0xFF;
1214  			start_table[start_table_len++] = segments[i].start >> 8;
1215  
1216  			ones = zeros = 0;
1217  			for(j=0;j<segments[i].length;j++) {
1218  				byte=segments[i].data[j];
1219  				for(k=0;k<8;k++) {
1220  					if(byte & 0x80)
1221  						ones++;
1222  					else
1223  						zeros++;
1224  					byte <<= 1;
1225  				}
1226  			}
1227  			sprintf(eta,"%d",(int) (ones/(float)freq1 + zeros/(float)freq0 + 0.5 + 0.25));
1228  
1229  			// ETA
1230  			start_table[start_table_len++] = eta[0] + 0x80;
1231  			if(eta[1] != 0)
1232  				start_table[start_table_len++] = eta[1] + 0x80;
1233  			else
1234  				start_table[start_table_len++] = 0;
1235  
1236  			fprintf(stderr,"Segment: %d, start: 0x%04X, length: %5d, deflated: %.02f%%, data time:%s, inflate time:%.02f\n",i,segments[i].start,segments[i].length,100.0*(1-segments[i].length/orig_len),eta,inflate_times[i]);
1237  		}
1238  		fprintf(stderr,"\n");
1239  
1240  		for(i=0;i<sizeof(diskloadcode2)/sizeof(char);i++) {
1241  			WRITEBYTE(diskloadcode2[i]);
1242  			checksum ^= diskloadcode2[i];
1243  		}
1244  
1245  		start_table[start_table_len++] = noformat;
1246  
1247  		for(i=0;i<start_table_len;i++) {
1248  			WRITEBYTE(start_table[i]);
1249  			checksum ^= start_table[i];
1250  		}
1251  
1252  		for(i=0;i<4*256 - sizeof(diskloadcode2)/sizeof(char) - start_table_len;i++) {
1253  			WRITEBYTE(0x00);
1254  			checksum ^= 0x00;
1255  		}
1256  
1257  		for(i=0;i<sizeof(diskloadcode3)/sizeof(char);i++) {
1258  			WRITEBYTE(diskloadcode3[i]);
1259  			checksum ^= diskloadcode3[i];
1260  		}
1261  
1262  		for(i=0;i<sizeof(dosboot2)/sizeof(char);i++) {
1263  			WRITEBYTE(dosboot2[i]);
1264  			checksum ^= dosboot2[i];
1265  		}
1266  
1267  		WRITEBYTE(checksum);
1268  		if(k8) {
1269  			appendtone(&output,&outputlength,770,rate,0,2,&offset);
1270  			appendtone(&output,&outputlength,2000,rate,0.3,0,&offset);
1271  		}
1272  		else {
1273  			appendtone(&output,&outputlength,2000,rate,0,1,&offset);
1274  			appendtone(&output,&outputlength,6000,rate,0.1,0,&offset);
1275  		}
1276  
1277  		for(i=0;i<numseg;i++) {
1278  			//appendtone(&output,&outputlength,6000,rate,1,0,&offset);
1279  
1280  //timing
1281  			if(i==0) {
1282  				if(!noformat)
1283  					j=28;
1284  				else
1285  					j=0;
1286  			}
1287  			else {
1288  				//j = 6 + ceil(inflate_times[i-1]);  // 6 = write track time, may need to make it 7
1289  				// disk ][ verified (format and no-format)
1290  				// Virtual ][ emulator verified (format and no-format, 8K only)
1291  				// CFFA3000 3.1 failed, needs more time
1292  
1293  				j = ceil(6.5 + inflate_times[i-1]);  // 6 = write track time, may need to make it 7
1294  				// disk ][ verified (format and no-format)
1295  				// Apple duodisk verified (format and no-format)
1296  				// CFFA3000 3.1 verified with USB stick (no-format only)
1297  				// CFFA3000 3.1 failed with IBM 4GB Microdrive (too slow)
1298  				// Nishida Radio SDISK // (no-format only)
1299  			}
1300  			if(i==1) // seek time for track 0, just in case
1301  				j+=2;
1302  
1303  /* count down code
1304  			for(;j>=0;j--) {
1305  				checksum = 0xff;
1306  				WRITEBYTE(j/10 + 48 + 0x80);
1307  				checksum ^= (j/10 + 48 + 0x80);
1308  				WRITEBYTE(j%10 + 48 + 0x80);
1309  				checksum ^= (j%10 + 48 + 0x80);
1310  				WRITEBYTE(0x00);
1311  				checksum ^= 0x00;
1312  				WRITEBYTE(checksum);
1313  				appendtone(&output,&outputlength,2000,rate,0,1,&offset);
1314  				appendtone(&output,&outputlength,6000,rate,1,0,&offset);
1315  			}
1316  */
1317  
1318  			if(k8)
1319  				appendtone(&output,&outputlength,2000,rate,j,0,&offset);
1320  			else
1321  				appendtone(&output,&outputlength,6000,rate,j,0,&offset);
1322  
1323  			checksum = 0xff;
1324  			for(j=0;j<segments[i].length;j++) {
1325  				WRITEBYTE(segments[i].data[j]);
1326  				checksum ^= segments[i].data[j];
1327  			}
1328  			WRITEBYTE(checksum);
1329  			if(k8)
1330  				//appendtone(&output,&outputlength,770,rate,0,2,&offset);
1331  				appendtone(&output,&outputlength,770,rate,0,10,&offset);
1332  			else
1333  				//appendtone(&output,&outputlength,2000,rate,0,1,&offset);
1334  				appendtone(&output,&outputlength,2000,rate,0,10,&offset);
1335  		}
1336  
1337  		fprintf(stderr,"To load up and run on your Apple %s, type:\n\n\tLOAD\n\n",modeltypes[model]);
1338  	}
1339  
1340  	// append zero to zero out last wave
1341  	appendtone(&output,&outputlength,0,rate,0,1,&offset);
1342  
1343  	// 0.1 sec quiet to help some emulators
1344  	appendtone(&output,&outputlength,0,rate,0.1,0,&offset);
1345  
1346  	// 0.4 sec quiet to help some IIs
1347  	// appendtone(&output,&outputlength,0,rate,0.4,0,&offset);
1348  
1349  	// write it
1350  	if(outputtype == AIFF)
1351  		Write_AIFF(ofp,output,outputlength,rate,bits,amp);
1352  	else if(outputtype == WAVE)
1353  		Write_WAVE(ofp,output,outputlength,rate,bits,amp);
1354  
1355  	fclose(ofp);
1356  	return 0;
1357  }
1358  
1359  void appendtone(double **sound, long *length, int freq, int rate, double time, double cycles, int *offset)
1360  {
1361  	long i, n=time*rate;
1362  	static long grow = 0;
1363  	double *tmp = NULL;
1364  
1365  	if(freq && cycles)
1366  		n=cycles*rate/freq;
1367  
1368  	if(n == 0)
1369  		n=cycles;
1370  
1371  /*
1372  	if((tmp = (double *)realloc(*sound, (*length + n) * sizeof(double))) == NULL)
1373  		abort();
1374  	*sound = tmp;
1375  */
1376  
1377  // new code for speed up Windows realloc
1378  	if(*length + n > grow) {
1379  		grow = *length + n + 10000000;
1380  		if((tmp = (double *)realloc(*sound, (grow) * sizeof(double))) == NULL)
1381  			abort();
1382  		*sound = tmp;
1383  	}
1384  
1385  //tmp -> (*sound)
1386  	if(square) {
1387  		int j;
1388  
1389  		if(freq)
1390  			for (i = 0; i < n; i++) {
1391  				for(j = 0;j < rate / freq / 2;j++)
1392  					(*sound)[*length + i++] = 1;
1393  				for(j = 0;j < rate / freq / 2;j++)
1394  					(*sound)[*length + i++] = -1;
1395  				i--;
1396  			}
1397  		else
1398  			for (i = 0; i < n; i++)
1399  				(*sound)[*length + i] = 0;
1400  	}
1401  	else
1402  		for(i=0;i<n;i++)
1403  			(*sound)[*length+i] = sin(2*M_PI*i*freq/rate + *offset*M_PI);
1404  
1405  	if(cycles - (int)cycles == 0.5)
1406  		*offset = (*offset == 0);
1407  
1408  	*length += n;
1409  }
1410  
1411  char *getext(char *filename)
1412  {
1413  	char stack[256], *rval;
1414  	int i, sp = 0;
1415  
1416  	for(i=strlen(filename)-1;i>=0;i--) {
1417  		if(filename[i] == '.')
1418  			break;
1419  		stack[sp++] = filename[i];
1420  	}
1421  	stack[sp] = '\0';
1422  
1423  	if(sp == strlen(filename) || sp == 0)
1424  		return(NULL);
1425  
1426  	if((rval = (char *)malloc(sp * sizeof(char))) == NULL)
1427  		; //do error code
1428  
1429  	rval[sp] = '\0';
1430  	for(i=0;i<sp+i;i++)
1431  		rval[i] = stack[--sp];
1432  
1433  	return(rval);
1434  }
1435  
1436  void usage()
1437  {
1438  	fprintf(stderr,"%s",usagetext);
1439  }
1440  
1441  // Code below from http://paulbourke.net/dataformats/audio/
1442  /*
1443     Write an AIFF sound file
1444     Only do one channel, only support 16 bit.
1445     Supports sample frequencies of 11, 22, 44KHz (default).
1446     Little/big endian independent!
1447  */
1448  
1449  // egan: changed code to support any Hz and 8 bit.
1450  
1451  void Write_AIFF(FILE * fptr, double *samples, long nsamples, int nfreq, int bits, double amp)
1452  {
1453  	unsigned short v;
1454  	int i;
1455  	unsigned long totalsize;
1456  	double themin, themax, scale, themid;
1457  	unsigned char bit80[10];
1458  
1459  	// Write the form chunk
1460  	fprintf(fptr, "FORM");
1461  	totalsize = 4 + 8 + 18 + 8 + (bits / 8) * nsamples + 8;
1462  	fputc((totalsize & 0xff000000) >> 24, fptr);
1463  	fputc((totalsize & 0x00ff0000) >> 16, fptr);
1464  	fputc((totalsize & 0x0000ff00) >> 8, fptr);
1465  	fputc((totalsize & 0x000000ff), fptr);
1466  	fprintf(fptr, "AIFF");
1467  
1468  	// Write the common chunk
1469  	fprintf(fptr, "COMM");
1470  	fputc(0, fptr);				// Size
1471  	fputc(0, fptr);
1472  	fputc(0, fptr);
1473  	fputc(18, fptr);
1474  	fputc(0, fptr);				// Channels = 1
1475  	fputc(1, fptr);
1476  	fputc((nsamples & 0xff000000) >> 24, fptr);	// Samples
1477  	fputc((nsamples & 0x00ff0000) >> 16, fptr);
1478  	fputc((nsamples & 0x0000ff00) >> 8, fptr);
1479  	fputc((nsamples & 0x000000ff), fptr);
1480  	fputc(0, fptr);				// Size = 16
1481  	fputc(bits, fptr);
1482  
1483  	ConvertToIeeeExtended(nfreq, bit80);
1484  	for (i = 0; i < 10; i++)
1485  		fputc(bit80[i], fptr);
1486  
1487  	// Write the sound data chunk
1488  	fprintf(fptr, "SSND");
1489  	fputc((((bits / 8) * nsamples + 8) & 0xff000000) >> 24, fptr);	// Size
1490  	fputc((((bits / 8) * nsamples + 8) & 0x00ff0000) >> 16, fptr);
1491  	fputc((((bits / 8) * nsamples + 8) & 0x0000ff00) >> 8, fptr);
1492  	fputc((((bits / 8) * nsamples + 8) & 0x000000ff), fptr);
1493  	fputc(0, fptr);				// Offset
1494  	fputc(0, fptr);
1495  	fputc(0, fptr);
1496  	fputc(0, fptr);
1497  	fputc(0, fptr);				// Block
1498  	fputc(0, fptr);
1499  	fputc(0, fptr);
1500  	fputc(0, fptr);
1501  
1502  	// Find the range
1503  	themin = samples[0];
1504  	themax = themin;
1505  	for (i = 1; i < nsamples; i++) {
1506  		if (samples[i] > themax)
1507  			themax = samples[i];
1508  		if (samples[i] < themin)
1509  			themin = samples[i];
1510  	}
1511  	if (themin >= themax) {
1512  		themin -= 1;
1513  		themax += 1;
1514  	}
1515  	themid = (themin + themax) / 2;
1516  	themin -= themid;
1517  	themax -= themid;
1518  	if (ABS(themin) > ABS(themax))
1519  		themax = ABS(themin);
1520  //  scale = amp * 32760 / (themax);
1521  	scale = amp * ((bits == 16) ? 32760 : 124) / (themax);
1522  
1523  	// Write the data
1524  	for (i = 0; i < nsamples; i++) {
1525  		if (bits == 16) {
1526  			v = (unsigned short) (scale * (samples[i] - themid));
1527  			fputc((v & 0xff00) >> 8, fptr);
1528  			fputc((v & 0x00ff), fptr);
1529  		} else {
1530  			v = (unsigned char) (scale * (samples[i] - themid));
1531  			fputc(v, fptr);
1532  		}
1533  	}
1534  }
1535  
1536  /*
1537     Write an WAVE sound file
1538     Only do one channel, only support 16 bit.
1539     Supports any (reasonable) sample frequency
1540     Little/big endian independent!
1541  */
1542  
1543  // egan: changed code to support 8 bit.
1544  
1545  void Write_WAVE(FILE * fptr, double *samples, long nsamples, int nfreq, int bits, double amp)
1546  {
1547  	unsigned short v;
1548  	int i;
1549  	unsigned long totalsize, bytespersec;
1550  	double themin, themax, scale, themid;
1551  
1552  	// Write the form chunk
1553  	fprintf(fptr, "RIFF");
1554  	totalsize = (bits / 8) * nsamples + 36;
1555  	fputc((totalsize & 0x000000ff), fptr);	// File size
1556  	fputc((totalsize & 0x0000ff00) >> 8, fptr);
1557  	fputc((totalsize & 0x00ff0000) >> 16, fptr);
1558  	fputc((totalsize & 0xff000000) >> 24, fptr);
1559  	fprintf(fptr, "WAVE");
1560  	fprintf(fptr, "fmt ");		// fmt_ chunk
1561  	fputc(16, fptr);			// Chunk size
1562  	fputc(0, fptr);
1563  	fputc(0, fptr);
1564  	fputc(0, fptr);
1565  	fputc(1, fptr);				// Format tag - uncompressed
1566  	fputc(0, fptr);
1567  	fputc(1, fptr);				// Channels
1568  	fputc(0, fptr);
1569  	fputc((nfreq & 0x000000ff), fptr);	// Sample frequency (Hz)
1570  	fputc((nfreq & 0x0000ff00) >> 8, fptr);
1571  	fputc((nfreq & 0x00ff0000) >> 16, fptr);
1572  	fputc((nfreq & 0xff000000) >> 24, fptr);
1573  	bytespersec = (bits / 8) * nfreq;
1574  	fputc((bytespersec & 0x000000ff), fptr);	// Average bytes per second
1575  	fputc((bytespersec & 0x0000ff00) >> 8, fptr);
1576  	fputc((bytespersec & 0x00ff0000) >> 16, fptr);
1577  	fputc((bytespersec & 0xff000000) >> 24, fptr);
1578  	fputc((bits / 8), fptr);		// Block alignment
1579  	fputc(0, fptr);
1580  	fputc(bits, fptr);			// Bits per sample
1581  	fputc(0, fptr);
1582  	fprintf(fptr, "data");
1583  	totalsize = (bits / 8) * nsamples;
1584  	fputc((totalsize & 0x000000ff), fptr);	// Data size
1585  	fputc((totalsize & 0x0000ff00) >> 8, fptr);
1586  	fputc((totalsize & 0x00ff0000) >> 16, fptr);
1587  	fputc((totalsize & 0xff000000) >> 24, fptr);
1588  
1589  	// Find the range
1590  	themin = samples[0];
1591  	themax = themin;
1592  	for (i = 1; i < nsamples; i++) {
1593  		if (samples[i] > themax)
1594  			themax = samples[i];
1595  		if (samples[i] < themin)
1596  			themin = samples[i];
1597  	}
1598  	if (themin >= themax) {
1599  		themin -= 1;
1600  		themax += 1;
1601  	}
1602  	themid = (themin + themax) / 2;
1603  	themin -= themid;
1604  	themax -= themid;
1605  	if (ABS(themin) > ABS(themax))
1606  		themax = ABS(themin);
1607  //  scale = amp * 32760 / (themax);
1608  	scale = amp * ((bits == 16) ? 32760 : 124) / (themax);
1609  
1610  	// Write the data
1611  	for (i = 0; i < nsamples; i++) {
1612  		if (bits == 16) {
1613  			v = (unsigned short) (scale * (samples[i] - themid));
1614  			fputc((v & 0x00ff), fptr);
1615  			fputc((v & 0xff00) >> 8, fptr);
1616  		} else {
1617  			v = (unsigned char) (scale * (samples[i] - themid));
1618  			fputc(v + 0x80, fptr);
1619  		}
1620  	}
1621  }
1622  
1623  
1624  /*
1625   * C O N V E R T   T O   I E E E   E X T E N D E D
1626   */
1627  
1628  /* Copyright (C) 1988-1991 Apple Computer, Inc.
1629   * All rights reserved.
1630   *
1631   * Machine-independent I/O routines for IEEE floating-point numbers.
1632   *
1633   * NaN's and infinities are converted to HUGE_VAL or HUGE, which
1634   * happens to be infinity on IEEE machines.  Unfortunately, it is
1635   * impossible to preserve NaN's in a machine-independent way.
1636   * Infinities are, however, preserved on IEEE machines.
1637   *
1638   * These routines have been tested on the following machines:
1639   *    Apple Macintosh, MPW 3.1 C compiler
1640   *    Apple Macintosh, THINK C compiler
1641   *    Silicon Graphics IRIS, MIPS compiler
1642   *    Cray X/MP and Y/MP
1643   *    Digital Equipment VAX
1644   *
1645   *
1646   * Implemented by Malcolm Slaney and Ken Turkowski.
1647   *
1648   * Malcolm Slaney contributions during 1988-1990 include big- and little-
1649   * endian file I/O, conversion to and from Motorola's extended 80-bit
1650   * floating-point format, and conversions to and from IEEE single-
1651   * precision floating-point format.
1652   *
1653   * In 1991, Ken Turkowski implemented the conversions to and from
1654   * IEEE double-precision format, added more precision to the extended
1655   * conversions, and accommodated conversions involving +/- infinity,
1656   * NaN's, and denormalized numbers.
1657   */
1658  
1659  #ifndef HUGE_VAL
1660  #define HUGE_VAL HUGE
1661  #endif							/*HUGE_VAL */
1662  
1663  #define FloatToUnsigned(f) ((unsigned long)(((long)(f - 2147483648.0)) + 2147483647L) + 1)
1664  
1665  void ConvertToIeeeExtended(double num, unsigned char *bytes)
1666  {
1667  	int sign;
1668  	int expon;
1669  	double fMant, fsMant;
1670  	unsigned long hiMant, loMant;
1671  
1672  	if (num < 0) {
1673  		sign = 0x8000;
1674  		num *= -1;
1675  	} else {
1676  		sign = 0;
1677  	}
1678  
1679  	if (num == 0) {
1680  		expon = 0;
1681  		hiMant = 0;
1682  		loMant = 0;
1683  	} else {
1684  		fMant = frexp(num, &expon);
1685  		if ((expon > 16384) || !(fMant < 1)) {	/* Infinity or NaN */
1686  			expon = sign | 0x7FFF;
1687  			hiMant = 0;
1688  			loMant = 0;			/* infinity */
1689  		} else {				/* Finite */
1690  			expon += 16382;
1691  			if (expon < 0) {	/* denormalized */
1692  				fMant = ldexp(fMant, expon);
1693  				expon = 0;
1694  			}
1695  			expon |= sign;
1696  			fMant = ldexp(fMant, 32);
1697  			fsMant = floor(fMant);
1698  			hiMant = FloatToUnsigned(fsMant);
1699  			fMant = ldexp(fMant - fsMant, 32);
1700  			fsMant = floor(fMant);
1701  			loMant = FloatToUnsigned(fsMant);
1702  		}
1703  	}
1704  
1705  	bytes[0] = expon >> 8;
1706  	bytes[1] = expon;
1707  	bytes[2] = hiMant >> 24;
1708  	bytes[3] = hiMant >> 16;
1709  	bytes[4] = hiMant >> 8;
1710  	bytes[5] = hiMant;
1711  	bytes[6] = loMant >> 24;
1712  	bytes[7] = loMant >> 16;
1713  	bytes[8] = loMant >> 8;
1714  	bytes[9] = loMant;
1715  }
1716  
1717  uint8_t read6502(uint16_t address)
1718  {
1719  	return ram[address];
1720  }
1721  
1722  void write6502(uint16_t address, uint8_t value)
1723  {
1724  	ram[address] = value;
1725  }