/* SYX2TAPE.c - A program to convert Chroma Cult sysex program dump files */ /* into 22050Hz, 8-bit, signed (SND) audio files. */ /* */ /* Version 0.1 - written 10-AUG-99 by David Clarke */ /* (ac151@freenet.carleton.ca) */ /* Version 0.2 - updated 12-OCT-04 by D. Clarke */ /* (ac151@freenet.carleton.ca) */ /* corrected "%s" string formats in printf statements */ /* */ /* Please feel free to compile, change or do whatever you want with this */ /* utility; however, if you make any significant improvements I'd */ /* appreciate you e-mailing me a copy. Thanks! */ /* */ /* Syntax: */ /* SYX2TAPE FILENAME.SYX */ /* */ /* The program will output 1 file called FILENAME.SND */ /* For a properly formatted sysex file, the resulting SND file will be */ /* just under 1MB. */ /* */ /**************************************************************************/ #include #include #include #include /* Program-wide defines */ #define ZeroLength 18 /* Number of samples for a "zero" */ #define OneLength 9 /* Number of samples for a "one" */ #define AmpUp 64 /* Positive max value in SND file */ #define AmpDown -64 /* Negative max value in SND file */ #define TRUE 1 #define FALSE 0 static int WasUp; /* Keep Track of Zero Crossings in SND file */ static unsigned char ChkSum; /* Running tally of data Check Sum */ static char out[] = ".snd"; /* output file suffix */ static char in[] = ".syx"; /* input file suffix */ char *f1name; /* full input file name */ char f2name[50]; /* full output file name */ FILE *f1, *f2; /* To Write a "Zero" to the cassette interface, you need to cross zero */ /* in the output file, and stay crossed for "ZeroLength" number of */ /* samples */ void WriteZero() { int x; if (WasUp == TRUE) { for (x = 0; x <= ZeroLength; ++x) { fputc(AmpDown, f2); } } else { for (x = 0; x <= ZeroLength; ++x) { fputc(AmpUp, f2); } } WasUp = !WasUp; } /* To Write a "One" to the cassette interface, you need to cross zero */ /* in the output file, for "OneLength" number of samples, and then cross */ /* back for another "OneLength" number of samples */ void WriteOne() { int x; if (WasUp == TRUE) { for (x = 0; x <= OneLength; ++x) { fputc(AmpDown, f2); } for (x = 0; x <= OneLength; ++x) { fputc(AmpUp, f2); } } else { for (x = 0; x <= OneLength; ++x) { fputc(AmpUp, f2); } for (x = 0; x <= OneLength; ++x) { fputc(AmpDown, f2); } } } /* Write the Pre-amble to the tape data (255 0's, followed by one 1) */ void WritePre() { int x; for (x = 1; x <= 255; ++x) WriteZero(); WriteOne(); } /* The "Byte" written with WriteByte is 11 bits long. The data is in the*/ /* following format: SRTB B0 B1 B2 B3 B4 B5 B6 B7 PB STPB */ /* where SRTB is the Start Bit ("0") */ /* B0 - B7 are the 8 bits of the data to be written (in reverse */ /* order) */ /* PB is the Parity Bit */ /* STPB is the Stop Bit ("1") */ void WriteByte(int byte2write) { int x, mult, parity, bit[9]; parity = 0; mult = 1; for (x = 0; x <= 7; ++x) /* convert integer into 8 bits and */ { /* and calculate parity for the 8 bit word */ bit[x] = ((byte2write & mult) >> x); mult = mult * 2; parity = (bit[x] ^ parity); } bit[8] = parity; WriteZero(); /* Output the Start Bit */ for (x = 0; x <= 8; ++x) /* Output 8 data bits and the parity bit */ if (bit[x] == 1) WriteOne(); else WriteZero(); WriteOne(); /* Output the Stop Bit */ } int main(int argc, char *argv[]) { int x, y; unsigned char byte1, byte2; WasUp = FALSE; if (argc == 1) { printf("Syntax: SYX2TAPE {filename.syx} where filename.syx is a valid sysex file\n"); exit(0); } f1name = argv[1]; strncpy(f2name, f1name, strlen(f1name)-4); strcat(f2name, out); if ((f1 = fopen(f1name, "rb")) == NULL) { printf("Can't open %s\n", f1name); exit(0); } if ((f2 = fopen(f2name, "wb")) == NULL) { printf("Can't open %s\n", f2name); exit(0); } for (x = 1; x <= 7; ++x) /* Strip of Sysex header info from sysex file */ { byte1 = fgetc(f1); } WritePre(); /* Start the output with the preamble */ WriteByte(2); /* Indicate a 2-bytes of data to follow */ WriteByte(2); /* Byte 0 = "2" (tells the chroma its a cassette packet) */ WriteByte(1); WriteByte(251); /* Checksum for 2 previous data bytes */ for (x = 1; x <= 50; ++x) /* Do for all 50 programs */ { WritePre(); /* Write preamble */ WriteByte(60); /* Indicate 60 bytes of data to follow */ WriteByte(1); /* Stuff first byte with value of "1" */ ChkSum = 61; /* The checksum to this point */ byte1 = fgetc(f1); /* Strip off/ignore program number from sysex */ for (y = 1; y <= 59; ++y) /* Do for all 59 data bytes in a dump */ { byte1 = fgetc(f1); /* Read 1st byte/nibble */ byte2 = fgetc(f1); /* Read 2nd byte/nibble */ byte1 = (byte1 << 4) + byte2; /* Combine bytes into word */ ChkSum = ChkSum + byte1; /* Update Checksum value */ WriteByte(byte1); /* Format and output word to file */ } ChkSum = ~(ChkSum) + 1; /* checksum = inverse of all data bytes + 1*/ WriteByte(ChkSum); /* store checksum */ ChkSum = 0; /* reset checksum for next packet */ } WritePre(); /* When all done, finish with one more preamble */ WriteByte(1); /* Indicate 1 byte of data to follow */ WriteByte(3); /* Issue a "Stop Packet" command */ WriteByte(252); /* output checksum for Stop Packet Command */ WritePre(); /* Output another preamble - just to have a graceful end */ fclose(f1); /* Close Input File */ fclose(f2); /* Close Output File */ return(0); }