Path: news.uiowa.edu!hobbes.physics.uiowa.edu!math.ohio-state.edu!cs.utexas.edu!uunet!dziuxsolim.rutgers.edu!igor.rutgers.edu!yoko.rutgers.edu!jac From: jac@yoko.rutgers.edu (Jonathan A. Chandross) Newsgroups: comp.sources.apple2 Subject: v001SRC088: Synthfile -- Print Contents of Midi Synth Files (Unix/GS) Message-ID: Date: 23 Jul 93 03:13:15 GMT Organization: Rutgers Univ., New Brunswick, N.J. Lines: 1680 Approved: jac@paul.rutgers.edu Submitted-by: Dave Tribby (tribby@cup.hp.com) Posting-number: Volume 1, Source:88 Archive-name: util/gs/midi/synthfile_v1.1 Architecture: UNIX,2gs Version-number: 1.1 Synthfile is a program that prints the contents of (and plays) MIDI Synth files. It is designed to be run under the GNO or ORCA shell. The source can be compiled and run under a Unix shell to print (but not play) MIDI Synth files that have been copied to Unix. Enjoy. =Read.Me - -Synthfile - -Synthfile is a program that prints the contents of (and plays) MIDI Synth -files. It is designed to be run under the GNO or ORCA shell. The source can -be compiled and run under a Unix shell to print (but not play) MIDI Synth -files that have been copied to Unix. - -Synthfile is freeware and may be distributed without charge, but commercial -rights are retained by the author, Dave Tribby. If Synthfile is included in -a collection of shareware/freeware programs, please send a copy to: - Dave Tribby - 1529 Fantail Ct. - Sunnyvale CA 94087 - -Portions of this code may be used in other freeware programs if requested -and if appropriate credit is given to synthfile. Contact Dave Tribby at -the address above or at the following electronic mail addresses: - GEnie: D.TRIBBY - Internet: tribby@cup.hp.com - -Copyright 1993 by Dave Tribby, All Rights Reserved. - -Dave Tribby -tribby@cup.hp.com -GEnie: D.TRIBBY - -Version 1.1 -July 1993 =synthfile.doc -Synthfile is a program that prints the contents of (and plays) MIDI Synth -files. It is designed to be run under the GNO or ORCA shell. The source can -be compiled and run under a Unix shell to print (but not play) MIDI Synth -files that have been copied to Unix. - -Before running synthfile, you must be in the directory containing the -MIDI Synth files (so synthfile can locate referenced files). - -Synopsis: - synthfile [-v] [-p] file1 [file2 ...] - where - -v indicates verbose output - -p requests that sequence files be played (GS only) - file1, file2, etc., are MIDI Synth sequence, instrument, or - wavebank files. - -Output is sent to standard out. (Errors are printed on standard error.) - -You can listen to a group of files on your GS with (for example) - synthfile -p Kawai1.SEQ Obladi.Oblada Old.French PIANO.MAN Africa -If you type - synthfile -p * -under GNO, synthfile will open every file in the directory, ignore -all non-MIDI-Synth files, print a brief report on MIDI Synth files, and -play MIDI Synth sequence files. With synthfile 1.1 you can enter - synthfile -p * > .NULL & -to play songs as a background process under GNO. - -The playing of a song can be prematurely terminated by pressing the -option key. (In version 1.0 the open-apple key causes synthfile to -stop. I removed it in 1.1 so users can access the control panel.) - -Synthfile is freeware and may be distributed without charge, but -commercial rights are retained by the author, Dave Tribby. If it is -included in a collection of shareware/freeware programs, please send -a copy to Dave Tribby, 1529 Fantail Ct., Sunnyvale CA 94087. - -Portions of this code may be used in other freeware programs if requested -and if appropriate credit is given to synthfile. Contact Dave Tribby at -the address above or at the following electronic mail addresses: - GEnie: D.TRIBBY Internet: tribby@cup.hp.com =synthfile.c -/* Synthfile version 1.1: July 1993 */ -/* */ -/* Print contents of (and play) MIDI Synth files */ -/* */ -/* Designed to be run under GNO or ORCA shell. It can also be compiled */ -/* and run under a Unix shell, except it will not play a sequence. */ -/* The compiler variable __ORCAC__ is used to choose code that runs on */ -/* GS vs. non-GS systems. */ -/* */ -/* To execute synthfile, you must make the directory containing the */ -/* MIDI Synth files the current directory. */ -/* */ -/* Synopsis: */ -/* synthfile [-v] [-p] file1 [file2 ...] */ -/* where */ -/* -v indicates verbose output */ -/* -p requests that sequence files be played and printed (GS only) */ -/* and the files are MIDI Synth sequence, instrument, and wavebank. */ -/* Output is sent to standard out. */ - -/* Synthfile is freeware and may be distributed without charge, but */ -/* commercial rights are retained by Dave Tribby, the author. If it is */ -/* included in a collection of shareware/freeware programs, please send */ -/* a copy to Dave Tribby, 1529 Fantail Ct., Sunnyvale CA 94087. */ - -/* Portions of this code can be used in other freeware programs after */ -/* approval by Dave Tribby; he can be contacted at the address above or */ -/* at the following electronic mail addresses: */ -/* GEnie: D.TRIBBY Internet: tribby@cup.hp.com */ -/* */ - - -/* Choose C headers if on GS; otherwise use own declarations */ - -#ifdef __ORCAC__ -#include -/* The 1991 & 1992 versions of MidiSynth.h contain these errors: */ -/* Change WavAddrB to WaveAddrB in WavelistRec */ -/* Change SetBasicChannel() to SetBasicChan() */ -/* Change "FindTuneA" to "FineTuneA" */ -#include -#include -#include -#include -#include -#endif - -#ifndef __ORCAC__ -/* Types required by MidiSynth.h and synthlab.c; based on */ -/* Types.h, but modified so as not to assume a 16-bit int */ -/* and avoid defining strings with unsigned char[] */ -#define TRUE 1 -#define FALSE 0 -#define String(size) struct {unsigned char textLength; char text[size];} -typedef unsigned char byte, Byte; -typedef unsigned short word, Word; -typedef char *ptr, *Ptr, *pointer, *Pointer; - -/* Declarations from MidiSynth.h */ -typedef struct { - word measureNumber; - word beatNumber; - word msRemainder; - } MeasureRec, *MeasureRecPtr, **MeasureRecHndl; - -typedef struct { - byte AttackLevel; - byte AttackRate; - byte Decay1Level; - byte Decay1Rate; - byte Decay2Level; - byte Decay2Rate; - byte SustainLevel; - byte Decay3Rate; - byte Release1Level; - byte Release1Rate; - byte Release2Level; - byte Release2Rate; - byte Release3Rate; - byte DecayGain; - byte VelocityGain; - byte PitchBendRange; - } EnvelopeRec, *EnvelopeRecPtr, **EnvelopeRecHndl; - -typedef struct { - byte TopKey; - byte OscConfig; - byte Stereo; - byte Detune; - byte WaveAddrA; - byte WaveSizeA; - byte VolumeA; - byte OctaveA; - byte SemitoneA; - byte FineTuneA; - byte WaveAddrB; - byte WaveSizeB; - byte VolumeB; - byte OctaveB; - byte SemitoneB; - byte FineTuneB; - } WavelistRec, *WavelistRecPtr, **WavelistRecHndl; - -typedef struct { - EnvelopeRec gen1EnvRec; - WavelistRec gen1WaveRecs[8]; - EnvelopeRec gen2EnvRec; - WavelistRec gen2WaveRecs[8]; - } InstrumentRec, *InstrumentRecPtr, **InstrumentRecHndl; - -typedef struct { - byte TrackNum; - byte TimeStampHigh; - byte TimeStampLow; - byte TimeStampMid; - byte DataByteCount; - byte MIDIStat; - byte DataByte1; - byte DataByte2; - } SeqItemRec, *SeqItemRecPtr, **SeqItemRecHndl; - -#endif - -#include -#include -#include -#include - -#ifdef __ORCAC__ -#pragma lint -1 -#endif - -/* Define a Pascal string type with 15 chars + length byte */ -typedef String(15) pstr15; - - -/* Offsets into wave data file */ -#define WAVE_TABLE_OFFSET 0x0100 -#define WAVE_BANK_OFFSET 0x0900 - -/* Offsets into instrument file */ -#define INST_NAME_OFFSET 0x0300 -#define INST_REC_OFFSET 0x0400 - -/* Offsets into sequence file */ -#define SEQ_TRAKNAME_OFFSET 0x0028 -#define SEQ_INIT_OFFSET 0x0128 -#define SEQUENCE_OFFSET 0x01D2 - - -/* Entries in the wave data file */ -typedef struct { - char file_type[4]; - word version; - word wav_offset; - char app[16]; - byte num_waves; - } WavHeader; - -typedef struct { - pstr15 wavename; - char fill1; - byte waveaddr; - char fill2; - byte wavesize; - char fill[12]; - } FWvEntry; - - -/* Entries in the instrument file */ -typedef struct { - char file_type[4]; - word version; - word head_size; - char app[16]; - pstr15 wavname; - byte semi_tone_tune; - byte fine_tune; - byte fill1; - byte volume; - byte num_inst; - } InsHeader; - - -/* Entries in the sequence file */ -typedef struct { - char file_type[4]; - word version; - word seq_offset; - char app[16]; - pstr15 bnkname; - } SeqHeader; - -typedef struct SeqInit { - word c_volume[16]; - word t_channel[16]; - word t_play[16]; - word rec_track; - word tempo; - word beat_p_meas; - word beat_val; - word ticks_p_beat; - word t_out[16]; - } SeqInit; - - -/*----------------------------------------------------------------------*/ -/* Global variables -/*----------------------------------------------------------------------*/ - -/* Files to be read */ -FILE *file, *seqfile=NULL, *bnkfile=NULL, *wavfile=NULL; -char seqname_c[16], bnkname_c[16], wavname_c[16]; - - -/* Run-time options and default values : */ -int verbose=FALSE; /* Print detailed listing of information? */ -#ifdef __ORCAC__ -int play=FALSE; /* Play the sequence as it is interpreted */ -#endif - - -/* Information in the wave data file */ -WavHeader wav_head; -FWvEntry wave_data[64]; - -/* Information in the instrument file */ -InsHeader ins_head; -pstr15 instname[16]; -InstrumentRec instrument[16]; - -/* Information in the sequence file */ -SeqHeader seq_head; -pstr15 trackname[16]; -SeqInit seq_init; -void *sequence_pnt = NULL; -SeqItemRecPtr last_entry; -size_t seq_size; -word track_chan[16]; /* Channels used on each track */ - -/* Used to calculate measure and beat from tick count */ -unsigned int ticks_per_beat; -unsigned int beats_per_meas; -unsigned long ticks_per_meas; - - -#ifdef __ORCAC__ -/* Required to play sequences */ -int playing=FALSE; /* Is a particular seq file being played? */ -CallBackRec callback_procs; /* List of callback procedures */ -Handle sound_zero_page = NULL; -byte *button0 = (byte *)0x00E0C061; -byte *button1 = (byte *)0x00E0C062; -SeqPlayRec play_seq; -#endif - - -/*----------------------------------------------------------------------*/ -/* Many Unix systems (e.g. HP 9000) store words with byte order the */ -/* opposite of the Apple II GS. Define macro to swap bytes in a word. */ -#define SwapBytes(w) w = (word)(((byte)w & 0xFF)<<8) + (w>>8) -/*----------------------------------------------------------------------*/ - -#ifdef __ORCAC__ -/*----------------------------------------------------------------------*/ -/* ===== MIDISynth callback routines ===== */ -/*----------------------------------------------------------------------*/ - -/* NOTE: Although it's not used in this program, here's code to make */ -/* GetMSData call, since glue routine is missing from library. */ -/* Assumes global variable for MIDI Synth direct page pointer */ -/* msDirectPagePtr dirpg; */ -/* -/* asm { -/* PHA ; Reserve room -/* PHA ; on stack -/* PHA ; for -/* PHA ; results. -/* LDX #0x1F23 ; _GetMSData -/* JSL 0xE10000 -/* PLA ; Save pointer -/* STA dirpg ; to direct page -/* PLA ; values in -/* STA dirpg+2 ; program variable. -/* PLA ; Discard reserved -/* PLA ; long value. -/* } - */ - -/* Flags set by callback routines */ -int beat = FALSE; -int Mstart = FALSE; -int Mstop = FALSE; -int PacketIn = FALSE; -int PgmChange = FALSE; -int Mcontinue = FALSE; -int SMarker = FALSE; - -#pragma databank 1 -void EndSeqCallback(void) - { - playing = FALSE; - } /* EndSeqCallback */ - -void BeatCallback(void) - { - beat = TRUE; - } /* BeatCallback */ - -void MstartCallback(void) - { - Mstart = TRUE; - } /* MstartCallback */ - -void MstopCallback(void) - { - Mstop = TRUE; - } /* MstopCallback */ - -void PacketInCallback(void) - { - PacketIn = TRUE; - } /* PacketInCallback */ - -void PgmChangeCallback(void) - { - PgmChange = TRUE; - } /* PgmChangeCallback */ - -void McontinueCallback(void) - { - Mcontinue = TRUE; - } /* McontinueCallback */ - -void SMarkerCallback(void) - { - SMarker = TRUE; - } /* SMarkerCallback */ -#pragma databank 0 -#endif - -/* Convert "wave size" value used by MIDI Synth to number of pages -/* (See table on page 134 of System 6.0 reference) -/*----------------------------------------------------------------------*/ -word ConvWvSize2Pg(word size) -/*----------------------------------------------------------------------*/ - { - switch (size) { - case 0: return (1); - case 1: return (2); - case 2: return (4); - case 3: return (8); - case 4: return (16); - case 5: return (32); - case 6: return (64); - } - return (128) ; - } /* ConvWvSize2Pg */ - - - -/* Print the "created by" application name--Pascal or C string -/*----------------------------------------------------------------------*/ -void PrintCreatedBy(char *name) -/*----------------------------------------------------------------------*/ - { - int len, i; - /* First, try Pascal string... */ - len = name[0]; - if (len > 15) { - /* If length is > 15, must not be a Pascal string. */ - len = 15; - i = 0; - } - else { - i = 1; - } - printf("Created by "); - while (i <= len) { - printf("%c", name[i]); - i++; - if (name[i] == 0) i = len+1; - } - printf("\n"); - } /* PrintCreatedBy */ - - - -/* Read 1st 4 bytes of a file and determine its type -/*----------------------------------------------------------------------*/ -int GetFileType(FILE *f) -/*----------------------------------------------------------------------*/ - { - char filetype[4]; - - /* Read the first 4 bytes of the file and see if they match */ - if (fread(filetype, 1, 4, f) == 4) { - if (strncmp(filetype, "MSEQ", 4) == 0) return(1); - if (strncmp(filetype, "INST", 4) == 0) return(2); - if (strncmp(filetype, "WAVE", 4) == 0) return(3); - } - /* Either a file error or invalid data */ - return(-1); - } /* GetFileType */ - - -/* Convert a numeric MIDI note value to ASCII -/*----------------------------------------------------------------------*/ -void PrintNoteValue(word value) -/*----------------------------------------------------------------------*/ - { - div_t note; - char a_note; - int sharp; - - if ( (value < 24) || (value > 127) ) - printf("%3d ", value); - else { - sharp = FALSE; - note = div((int) (value), 12); - switch (note.rem) { - case 11: - a_note = 'B'; - break; - case 10: - sharp = TRUE; - case 9: - a_note = 'A'; - break; - case 8: - sharp = TRUE; - case 7: - a_note = 'G'; - break; - case 6: - sharp = TRUE; - case 5: - a_note = 'F'; - break; - case 4: - a_note = 'E'; - break; - case 3: - sharp = TRUE; - case 2: - a_note = 'D'; - break; - case 1: - sharp = TRUE; - case 0: - a_note = 'C'; - break; - } - if (sharp) - printf("%c#%d ", a_note,note.quot-2); - else - printf(" %c%d ", a_note,note.quot-2); - } - } /* PrintNoteValue */ - - - -/*----------------------------------------------------------------------*/ -/* ===== WAVE DATA FILE INFORMATION ===== */ -/*----------------------------------------------------------------------*/ - - -/* Get information from the wave data file -/*----------------------------------------------------------------------*/ -void GetWavData(void) -/*----------------------------------------------------------------------*/ - { - int i, j, len, unused, column; - - /* Read the wave file header and check for error */ - if ( (fread(&wav_head, sizeof(wav_head), 1, wavfile) != 1) || - (strncmp(wav_head.file_type, "WAVE", 4) != 0) ) { - fprintf(stderr, "ERROR: %s is not a MIDI Synth wave data file\n", - wavname_c); - return; - } - - /* For non-65816 systems, need to swap the order of bytes in words */ -#ifndef __ORCAC__ - SwapBytes(wav_head.version); - SwapBytes(wav_head.wav_offset); -#endif - - printf("MIDI Synth Wavebank File %s (version %d.%d) ", - wavname_c, wav_head.version>>8, wav_head.version & 0xFF); - PrintCreatedBy(wav_head.app); - - /* Read the wave table */ - fseek(wavfile, WAVE_TABLE_OFFSET, SEEK_SET); - fread(wave_data, sizeof(FWvEntry), 64, wavfile); - - /* Interpret the results */ - if (verbose) { - printf(" Entry Name Page# Pages\n"); - /* dd sssssssssssssss $xx $xx */ - } - column = 0; - for (i=0; i 78) { - printf("\n"); - column = 19; - } - } - printf(" "); - for (j=0; jAttackLevel, envPtr->Decay1Level, envPtr->Decay2Level, - envPtr->SustainLevel, envPtr->Release1Level, envPtr->Release2Level); - - printf(" Rates: %3d %3d %3d %3d %3d %3d %3d\n", - envPtr->AttackRate, envPtr->Decay1Rate, envPtr->Decay2Rate, - envPtr->Decay3Rate, envPtr->Release1Rate, envPtr->Release2Rate, - envPtr->Release3Rate); - - printf(" Decay gain: %d Velocity Gain: %d Pitch bend range: %d\n", - envPtr->DecayGain, envPtr->VelocityGain, envPtr->PitchBendRange); - } /* PrintEnvelope */ - - -/* Print Wavelist Record information -/*----------------------------------------------------------------------*/ -void PrintWavelist(WavelistRecPtr wavePtr) -/*----------------------------------------------------------------------*/ - { - printf( - "%4d %7d %7d $%02X $%02X %3d %3d %3d %3d $%02X $%02X %3d %3d %3d %3d\n", - wavePtr->OscConfig, wavePtr->Stereo, wavePtr->Detune, - wavePtr->WaveAddrA, ConvWvSize2Pg(wavePtr->WaveSizeA), wavePtr->VolumeA, - wavePtr->OctaveA, wavePtr->SemitoneA, wavePtr->FineTuneA, - wavePtr->WaveAddrB, ConvWvSize2Pg(wavePtr->WaveSizeB), wavePtr->VolumeB, - wavePtr->OctaveB, wavePtr->SemitoneB, wavePtr->FineTuneB); - } /* PrintWavelist */ - - -/* Get information from the instrument file -/*----------------------------------------------------------------------*/ -void GetBnkData(void) -/*----------------------------------------------------------------------*/ - { - int inst_num, wave_num, j, len, error; - byte topkey; - - /* Read the instrument file header and check for error */ - if ( (fread(&ins_head, sizeof(ins_head), 1, bnkfile) != 1) || - (strncmp(ins_head.file_type, "INST", 4) != 0) ) { - fprintf(stderr, "ERROR: %s is not a MIDI Synth instrument file\n", - bnkname_c); - return; - } - - /* For non-65816 systems, need to swap the order of bytes in words */ -#ifndef __ORCAC__ - SwapBytes(ins_head.version); - SwapBytes(ins_head.head_size); -#endif - - printf("MIDI Synth Instrument File %s (version %d.%d) ", - bnkname_c, ins_head.version>>8, ins_head.version & 0xFF); - PrintCreatedBy(ins_head.app); - printf("\n"); - - /* Change the name of the wave data file from Pascal to C string */ - len = ins_head.wavname.textLength; - strncpy(wavname_c, ins_head.wavname.text, 15); - wavname_c[len] = 0; - - printf("%d instruments defined\n", ins_head.num_inst); - if (verbose) { - printf("Master tuning: %d semi-tone and %d fine\nMaster volume: %d\n", - ins_head.semi_tone_tune, ins_head.fine_tune, - ins_head.volume); - } - printf("\n"); - - /* Open the wave file */ - if ( (wavfile = fopen(wavname_c,"r")) == NULL) { - printf("uses wave data file %s\n", wavname_c); - fprintf(stderr, "ERROR opening wave data file %s", wavname_c); - perror(""); - } - else { - printf("uses "); - GetWavData(); - fclose(wavfile); - } - - /* Read the 16 instrument names and records */ - fseek(bnkfile, INST_NAME_OFFSET, SEEK_SET); - fread(instname, sizeof(pstr15), 16, bnkfile); - fread(instrument, sizeof(InstrumentRec), 16, bnkfile); - - for (inst_num=0; inst_num<16; inst_num++) { - printf("\nInstrument %d =", inst_num+1); - if ( (len=instname[inst_num].textLength) == 0 ) { - printf(" ----- unused -----\n"); - } - else { - printf(" "); - for (j=0; jtopkey) { - topkey = instrument[inst_num].gen1WaveRecs[wave_num].TopKey; - PrintNoteValue(topkey); - PrintWavelist(&(instrument[inst_num].gen1WaveRecs[wave_num])); - printf("%28s", " "); - PrintWaveAt( - instrument[inst_num].gen1WaveRecs[wave_num].WaveAddrA); - printf("%8s", " "); - PrintWaveAt( - instrument[inst_num].gen1WaveRecs[wave_num].WaveAddrB); - printf("\n"); - } - printf("Generator 2:\n"); - PrintEnvelope(&(instrument[inst_num].gen2EnvRec)); - printf(" Osc ------- Wave A -------- ------- Wave B --------\n"); - printf(" Cnfig Stereo Detune Adr Pgs Vol Oct Sem Fin Adr Pgs Vol Oct Sem Fin\n"); - topkey = 0; - for (wave_num=0; wave_num<8; wave_num++) - if (instrument[inst_num].gen1WaveRecs[wave_num].TopKey>topkey) { - topkey = instrument[inst_num].gen1WaveRecs[wave_num].TopKey; - printf(" "); - PrintWavelist(&(instrument[inst_num].gen2WaveRecs[wave_num])); - printf("%28s", " "); - PrintWaveAt( - instrument[inst_num].gen2WaveRecs[wave_num].WaveAddrA); - printf("%8s", " "); - PrintWaveAt( - instrument[inst_num].gen2WaveRecs[wave_num].WaveAddrB); - printf("\n"); - } - } /* if (verbose) */ - else { - printf("TopKey --Gen.1-Wave A-- --Gen.1-Wave B-- --Gen.2-Wave A-- --Gen.2-Wave B--\n"); - topkey = 0; - for (wave_num=0; wave_num<8; wave_num++) { - if (instrument[inst_num].gen1WaveRecs[wave_num].TopKey>topkey) { - topkey = instrument[inst_num].gen1WaveRecs[wave_num].TopKey; - printf(" "); - PrintNoteValue(topkey); - printf(" "); - PrintWaveAt( - instrument[inst_num].gen1WaveRecs[wave_num].WaveAddrA); - PrintWaveAt( - instrument[inst_num].gen1WaveRecs[wave_num].WaveAddrB); - PrintWaveAt( - instrument[inst_num].gen2WaveRecs[wave_num].WaveAddrA); - PrintWaveAt( - instrument[inst_num].gen2WaveRecs[wave_num].WaveAddrB); - printf("\n"); - } - } - } /* not verbose */ - } - } /* for inst_num */ - } /* GetBnkData */ - - - -/*----------------------------------------------------------------------*/ -/* ====== SEQUENCE FILE INFORMATION ===== */ -/*----------------------------------------------------------------------*/ - - -#ifdef __ORCAC__ -/* Load MIDI Synth information from instrument -/* and waveform files and play the sequence. -/*----------------------------------------------------------------------*/ -int LoadAndPlay(void) -/*----------------------------------------------------------------------*/ - { - int inst_num; - byte *wavebank_pnt; - int error; - int len; - int track_num; - - if ( (bnkfile = fopen(bnkname_c,"r")) == NULL) { - fprintf(stderr, "ERROR opening instrument file %s", bnkname_c); - perror(""); - return FALSE; - } - - /* Load header information from instrument file */ - if ( (fread(&ins_head, sizeof(ins_head), 1, bnkfile) != 1) || - (strncmp(ins_head.file_type, "INST", 4) != 0) ) { - fprintf(stderr, "ERROR: %s is not a MIDI Synth instrument file\n", - bnkname_c); - fclose(bnkfile); - return FALSE; - } - - /* Read the 16 instrument records */ - fseek(bnkfile, INST_REC_OFFSET, SEEK_SET); - fread(instrument, sizeof(InstrumentRec), 16, bnkfile); - fclose(bnkfile); - - /* Change the name of the wave data file from Pascal to C string */ - len = ins_head.wavname.textLength; - strncpy(wavname_c, ins_head.wavname.text, 15); - wavname_c[len] = 0; - - /* Open the wave file */ - if ( (wavfile = fopen(wavname_c,"r")) == NULL) { - fprintf(stderr, "ERROR opening wave data file %s", wavname_c); - perror(""); - return FALSE; - } - - - /* Read the wave file header and check for error */ - if ( (fread(&wav_head, sizeof(wav_head), 1, wavfile) != 1) || - (strncmp(wav_head.file_type, "WAVE", 4) != 0) ) { - fprintf(stderr, "ERROR: %s is not a MIDI Synth wave data file\n", - wavname_c); - fclose(wavfile); - return FALSE; - } - - if ((wavebank_pnt = malloc(0x10000)) == NULL) { - fprintf(stderr, "ERROR: cannot allocate memory for wave bank!\n"); - fclose(wavfile); - return FALSE; - } - - /* Read the wave bank */ - fseek(wavfile, WAVE_BANK_OFFSET, SEEK_SET); - clearerr(wavfile); - fread(wavebank_pnt, 1, 0x10000, wavfile); - fclose(wavfile); - - /* Copy waveform into DOC memory (with interrupts off) */ - asm { - PHP ; Save current status values on stack - SEI ; Disable interrupts - }; - WriteRamBlock(wavebank_pnt, 0, 0xFFFF); - asm { - PLP ; Restore previous status values - }; - error = toolerror(); - free(wavebank_pnt); - if (error) { - fprintf(stderr, "TOOL ERROR $%04X from WriteRamBlock\n",error); - return FALSE; - } - - /* Set values of instruments */ - for (inst_num=0; inst_num<16; inst_num++) { - SetInstrument(&instrument[inst_num], inst_num); - if (error=toolerror()) { - fprintf(stderr, "TOOL ERROR $%04X setting instrument %d\n", - error,inst_num+1); - } - } - - SetMetro(0,0,NULL); /* Use default values for metronome */ - - /* Set values of system parameters */ - SetMIDIMode(2); /* Multi mode (basic channel is ignored) */ - SetBeat(seq_init.ticks_p_beat); - SetMIDIPort(0, 0); /* MIDI input/output is disabled */ - SetTempo((seq_init.tempo << 1) - 10); - - for (track_num=0; track_num<16; track_num++) { - TrackToChannel(track_num, seq_init.t_channel[track_num]); - SetPlayTrack(track_num, seq_init.t_play[track_num]); - SetTrackOut (track_num, seq_init.t_out[track_num]); - } - -/* --- Need to call SetTuningTable with info from Instrument header ??? */ -/* --- Unused items from seqinit - unsigned int beat_p_meas; - --- */ - - /* Make sure nothing is left over from any previous notes */ - KillAllNotes(); - - /* Set volume of each instrument */ - for (inst_num=0; inst_num"); - switch (seq_init.t_out[track_num]) { - case 0: /* Output to both MIDI and Synth */ - printf("M&S"); - break; - case 1: /* Output to MIDI port only */ - printf(" M "); - break; - case 2: /* Output to Synthisizer only */ - printf(" S "); - break; - } - /* Is this track being mapped to a particular channel? */ - if (seq_init.t_channel[track_num] > 15) - printf(" "); - else - printf("=%2d ", seq_init.t_channel[track_num]+1); - len = trackname[track_num].textLength; - /* Print the track name, spaced out to 20 characters */ - for (j=0; jDataByteCount, seq_pnt->MIDIStat, - seq_pnt->DataByte1, seq_pnt->DataByte2); - } /* PrintHex */ - - - -/* Print a single MIDI sequence entry -/*----------------------------------------------------------------------*/ -void PrintSeqEntry (SeqItemRecPtr seq_pnt) -/*----------------------------------------------------------------------*/ - { - unsigned long timestamp; - unsigned int stat; - unsigned int channel; - int measure, tick; - ldiv_t long_div; - div_t beat; - - timestamp = seq_pnt->TimeStampHigh; - timestamp = timestamp << 16; - timestamp = (long) seq_pnt->TimeStampLow - + (long) (seq_pnt->TimeStampMid << 8 ) - + timestamp; - - long_div = ldiv((long)timestamp, (long)ticks_per_meas); - measure = long_div.quot + 1; - tick = long_div.rem; - beat = div((int)tick, (int)ticks_per_beat); - - stat = seq_pnt->MIDIStat >> 4; - channel = seq_pnt->MIDIStat & 0x0F; - - printf("%7ld %4d:%2d:%3d%3d ", - timestamp, measure, beat.quot+1, beat.rem, seq_pnt->TrackNum+1); - - if (seq_pnt->DataByteCount > 2) { - printf("Illegal data byte count: "); - PrintHex(seq_pnt); - printf("\n"); - return; - } - - /* Is this a command that uses a channel? */ - if ( (stat > 7) && (stat < 0xF) ) { - printf("Ch %-2d ", channel+1); - track_chan[seq_pnt->TrackNum] |= 1<DataByte1,seq_pnt->DataByte2); - break; - case 2: - printf("Set_ticks/beat $%02X $%02X", - seq_pnt->DataByte1,seq_pnt->DataByte2); - break; - case 4: - printf("Add_to_tempo $%02X $%02X", - seq_pnt->DataByte1,seq_pnt->DataByte2); - break; - default: - PrintHex(seq_pnt); - break; - } - break; - case 8: - printf("Note_off "); - PrintNoteValue(seq_pnt->DataByte1); - printf(" vel %3d", seq_pnt->DataByte2); - break; - case 9: - printf("Note_on "); - PrintNoteValue(seq_pnt->DataByte1); - printf(" vel %3d", seq_pnt->DataByte2); - break; - case 0xA: - printf("Poly_pressure "); - PrintNoteValue(seq_pnt->DataByte1); - printf(" = %d", seq_pnt->DataByte2); - break; - case 0xB: - switch (seq_pnt->DataByte1) { - case 1: - printf("Modulation_Wheel = %d", seq_pnt->DataByte2); - break; - case 2: - printf("Breath_Control = %d", seq_pnt->DataByte2); - break; - case 4: - printf("Foot_Controller = %d", seq_pnt->DataByte2); - break; - case 5: - printf("Portamento_Time = %d", seq_pnt->DataByte2); - break; - case 6: - printf("Data_Entry = %d", seq_pnt->DataByte2); - break; - case 7: - printf("Main_Volume = %d", seq_pnt->DataByte2); - break; - case 33: - printf("Modulation_Wheel_LSB = %d", seq_pnt->DataByte2); - break; - case 34: - printf("Breath_Control_LSB = %d", seq_pnt->DataByte2); - break; - case 36: - printf("Foot_Controller_LSB = %d", seq_pnt->DataByte2); - break; - case 37: - printf("Portamento_Time_LSB = %d", seq_pnt->DataByte2); - break; - case 38: - printf("Data_Entry_LSB = %d", seq_pnt->DataByte2); - break; - case 39: - printf("Main_Volume_LSB = %d", seq_pnt->DataByte2); - break; - case 64: - printf("Sustain_Pedal "); - if (seq_pnt->DataByte2) printf("ON"); - else printf("OFF"); - break; - case 65: - printf("Portamento_Pedal "); - if (seq_pnt->DataByte2) printf("ON"); - else printf("OFF"); - break; - case 66: - printf("Sustenuto_Pedal "); - if (seq_pnt->DataByte2) printf("ON"); - else printf("OFF"); - break; - case 67: - printf("Soft_Pedal "); - if (seq_pnt->DataByte2) printf("ON"); - else printf("OFF"); - break; - case 122: - printf("Local_Control "); - if (seq_pnt->DataByte2) printf("ON"); - else printf("OFF"); - break; - case 123: - printf("All_Notes_Off"); - break; - case 124: - printf("Omni_&_All_Notes_Off"); - break; - case 125: - printf("Omni_On_&_All_Notes_Off"); - break; - case 126: - printf("All_Notes_Off_&_Poly %d", seq_pnt->DataByte2); - break; - case 127: - printf("Poly_On_&_All_Notes_Off"); - break; - default: - printf("Control %d = %d", - seq_pnt->DataByte1,seq_pnt->DataByte2); - break; - } - break; - case 0xC: - printf("Program_Change # %d", seq_pnt->DataByte1); - break; - case 0xD: - printf("Aftertouch_Presure %d", seq_pnt->DataByte1); - break; - case 0xE: - printf("Pitch_Bend %d:%d", - seq_pnt->DataByte2-64,seq_pnt->DataByte1); - break; - case 0xF: - switch (channel) { - case 0: - printf("System_Exclusive "); - PrintHex(seq_pnt); - break; - case 2: - printf("Song_Position %d", - seq_pnt->DataByte1+seq_pnt->DataByte2<<7); - break; - case 3: - printf("Song_Select %d", seq_pnt->DataByte1); - break; - case 6: - printf("Tune_Request"); - break; - case 7: - printf("End_Exclusive "); - PrintHex(seq_pnt); - break; - case 8: - printf("Sequence_Timing_Clock"); - break; - case 0xA: - printf("Start_Sequence"); - break; - case 0xB: - printf("Continue_Sequence"); - break; - case 0xC: - printf("Stop_Sequence"); - break; - case 0xE: - printf("Active_Sensing"); - break; - default: - PrintHex(seq_pnt); - break; - } - break; - default: - PrintHex(seq_pnt); - } - printf("\n"); - } /* PrintSeqEntry */ - - -/* Decode and print the contents of a MIDI sequence -/*----------------------------------------------------------------------*/ -void PrintSequence (void) -/*----------------------------------------------------------------------*/ - { - SeqItemRecPtr next_entry; - int t, c; - word mask; - - /* Mark all track channels as unused */ - memset(track_chan, 0, sizeof(track_chan)); - - printf("\nMIDI Sequence\n"); - printf(" Time=Meas:Bt:Tik Trk Command\n"); - next_entry = (SeqItemRecPtr) sequence_pnt; - while ((next_entry <= last_entry) && (next_entry->TrackNum != 0xFF)) { - PrintSeqEntry(next_entry); - next_entry++; - } - printf("*** EOS ***\n\n"); - printf("Track Channels used\n"); - for (t=0; t<16; t++) { - if (track_chan[t]) { - printf("%4d ",t+1); - mask = 1; - for (c=0; c<16; c++) { - if (track_chan[t] & mask) - printf("%4d", c+1); - else - printf(" "); - mask <<= 1; - } /* for c */ - printf("\n"); - } - } /* for t */ - } /* PrintSequence */ - - - -/* Get detailed information from the sequence file -/*----------------------------------------------------------------------*/ -void GetSeqData(void) -/*----------------------------------------------------------------------*/ - { - int i, len; - byte *last_entry_byte; - unsigned long last_tick; - ldiv_t long_div; - div_t timing; - int est_seconds; - float est_minutes; - - /* Read sequence file header */ - fread(&seq_head, sizeof(seq_head), 1, seqfile); - - /* For non-65816 systems, need to swap the order of bytes in words */ -#ifndef __ORCAC__ - SwapBytes(seq_head.version); - SwapBytes(seq_head.seq_offset); -#endif - - printf("MIDI Synth Sequence File %s (version %d.%d) ", - seqname_c, seq_head.version>>8, seq_head.version & 0xFF); - PrintCreatedBy(seq_head.app); - - /* Change the name of the instrument file from Pascal to C string */ - len = seq_head.bnkname.textLength; - strncpy(bnkname_c,seq_head.bnkname.text,15); - bnkname_c[len] = 0; - printf("Uses instrument file %s\n", bnkname_c); - - ReadSequence(); - printf("MIDI sequence contains %ld bytes\n", seq_size); - - /* Read track names and sequence initialization values */ - fseek(seqfile, (long) SEQ_TRAKNAME_OFFSET, SEEK_SET); - fread(trackname, sizeof(pstr15), 16, seqfile); - fread(&seq_init, sizeof(seq_init), 1, seqfile); - - /* For non-65816 systems, need to swap the order of bytes in words */ -#ifndef __ORCAC__ - SwapBytes(seq_init.rec_track); - SwapBytes(seq_init.tempo); - SwapBytes(seq_init.beat_p_meas); - SwapBytes(seq_init.beat_val); - SwapBytes(seq_init.ticks_p_beat); - for (i=0; i<16; i++) { - SwapBytes(seq_init.c_volume[i]); - SwapBytes(seq_init.t_channel[i]); - SwapBytes(seq_init.t_play[i]); - SwapBytes(seq_init.t_out[i]); - } -#endif - - -#ifdef __ORCAC__ - /* If play option selected, open the instrument file and play sequence */ - if (play) { - playing = LoadAndPlay(); - } -#endif - - /* Set global values used to determine measure & beat */ - ticks_per_beat = seq_init.ticks_p_beat; - beats_per_meas = seq_init.beat_p_meas; - ticks_per_meas = ticks_per_beat*beats_per_meas; - - /* Estimate how long the sequence will play */ - last_entry_byte = (byte *)sequence_pnt + seq_size - 1; - while (*last_entry_byte == 0xFF) last_entry_byte--; - last_entry = (SeqItemRecPtr) (last_entry_byte-7); - last_tick = last_entry->TimeStampHigh; - last_tick = last_tick << 16; - last_tick = (long) last_entry->TimeStampLow - + (long) (last_entry->TimeStampMid << 8 ) - + last_tick; - - long_div = ldiv((long)last_tick, (long)ticks_per_beat); - est_seconds = (long_div.quot+1)*30/seq_init.tempo + 1; - /* Correction from version 1.0: est_seconds didn't produce correct */ - /* value when ticks_per_beat wasn't 96 (quarter note). So it looks */ - /* like last_tick/seq_init.tempo should always be multiplied by */ - /* 30/96 = 5/16, which is the same as multiplying and shifting left*/ - est_seconds = 1 + (last_tick*5/seq_init.tempo) >> 4; - timing = div(est_seconds, 60); - printf("Estimated playing time is %d:%02d\n", timing.quot,timing.rem); - - /* Print detailed sequence file information if verbose flag was set */ - if (verbose) { - printf("\nTracks--\n"); - for (i=0; i<8; i++) { - PrintTrackEntry(i); - PrintTrackEntry(i+8); - printf("\n"); - } - - printf("Record on track %d", seq_init.rec_track+1); - if (seq_init.rec_track > 15) printf(" (off) "); - printf("\n"); - - printf("\nChannel volumes--\n"); - for (i=0; i<16; i++) { - printf("%5d:%3d", i+1,seq_init.c_volume[i]); - if ((i & 7) == 7) printf("\n"); - } - - printf("\nTempo: %d beats/min; %d ticks/beat\n", - seq_init.tempo, seq_init.ticks_p_beat); - printf(" %d beats/measure, with ", seq_init.beat_p_meas); - switch (seq_init.beat_val) { - case 0: - printf("half"); - break; - case 1: - printf("quarter"); - break; - case 2: - printf("eighth"); - break; - default: - printf("1/%d", 2<<(seq_init.beat_val)); - break; - } - printf(" note getting one beat\n"); - if (sequence_pnt != NULL) { - PrintSequence(); - } - } /* End of verbose sequence output */ - -#ifdef __ORCAC__ - if (playing) { - while (playing) { - if (beat) { - /* Here's where a more sophisticated program could */ - /* look at the direct page variables and display */ - /* the current beat and measure numbers. */ - beat = FALSE; - } - if (Mstart) { - if (verbose) fprintf(stderr, " Mstart "); - Mstart = FALSE; - } - if (Mstop) { - if (verbose) fprintf(stderr, " Mstop "); - Mstop = FALSE; - } - if (PacketIn) { - if (verbose) fprintf(stderr, " PacketIn "); - PacketIn = FALSE; - } - if (PgmChange) { - if (verbose) fprintf(stderr, " PgmChange "); - PgmChange = FALSE; - } - if (Mcontinue) { - if (verbose) fprintf(stderr, " Mcontinue "); - Mcontinue = FALSE; - } - if (SMarker) { - if (verbose) fprintf(stderr, " SMarker "); - SMarker = FALSE; - } - - /* Check gameport button 1 (option key) for early termination */ - if ( *button1 > 127 ) { - play_seq.PbufStart = NULL; - play_seq.RbufStart = NULL; - play_seq.RbufEnd = NULL; - play_seq.SeqFlags = 0; - play_seq.theClock = 0; - SeqPlayer(&play_seq); - KillAllNotes(); - playing = FALSE; - if (verbose) fprintf(stderr, " Stopping song"); - } - } /* while playing */ - if (verbose) fprintf(stderr, "\n"); - } -#endif - - if (sequence_pnt != NULL) { - free(sequence_pnt); - sequence_pnt = NULL; - } - } /* GetSeqData */ - - - -#ifdef __ORCAC__ -/* Load and start the sound and MIDI Synth tool sets -/*----------------------------------------------------------------------*/ -int LoadAndStartTools(void) -/*----------------------------------------------------------------------*/ - { - Word my_memory_id; - static ToolTable tools; - int error; - - tools.toolCount = 2; - tools.theTools[0].toolNumber = 8; tools.theTools[0].minVersion = 0x0100; - tools.theTools[1].toolNumber = 35; tools.theTools[1].minVersion = 0x0100; - LoadTools((Pointer) &tools); - if (error=toolerror()) { - fprintf(stderr, "TOOL ERROR $%04X loading toolsets\n",error); - return FALSE; - } - - /* Start the toolsets */ - sound_zero_page = NewHandle(0x0100, /* Allocate 1 page */ - my_memory_id = MMStartUp(), /* User ID for mem blocks */ - attrLocked+attrFixed+attrPage+attrBank, /* Attributes */ - (Pointer) 0); /* Start in bank 0 */ - if (error=toolerror()) { - fprintf(stderr, "TOOL ERROR $%04X allocating zero-page memory\n",error); - return FALSE; - } - SoundStartUp((Word)(*sound_zero_page)); - if (error=toolerror()) { - fprintf(stderr, "TOOL ERROR $%04X starting sound tool\n",error); - return FALSE; - } - - MSStartUp(); - if (error=toolerror()) { - fprintf(stderr, "TOOL ERROR $%04X starting MIDI Synth tool\n",error); - SoundShutDown(); - DisposeHandle(sound_zero_page); - return FALSE; - } - - return TRUE; - } /* LoadAndStartTools */ -#endif - - -/*----------------------------------------------------------------------*/ -int main (int argc, char **argv) -/*----------------------------------------------------------------------*/ -{ -int p_num; /* Parameter number */ - - -/* Parse the option parameters, if provided */ -p_num = 1; -while ((p_num < argc) && (argv[p_num][0] == '-') ) { - switch ( argv[p_num][1] ) { - case 'v': - verbose = TRUE; - break; -#ifdef __ORCAC__ - case 'p': - play = TRUE; - break; -#endif - default: - fprintf(stderr, "Illegal option %s ignored\n", argv[p_num]); - } - p_num++; - } - -/* A file name parameter must be provided */ -if ( argc < p_num+1 ) { - fprintf(stderr, -"\nSynthFile: MIDI Synth file decoder Version 1.1 (%s)\n", __DATE__); - fprintf(stderr, -" written by Dave Tribby (GEnie: D.TRIBBY; Internet: tribby@cup.hp.com)\n\n"); -#ifdef __ORCAC__ - fprintf(stderr, -"usage: %s [-v] [-p] filename1 [filename2 ...]\n", argv[0]); -#endif -#ifndef __ORCAC__ - fprintf(stderr, -"usage: %s [-v] filename1 [filename2 ...]\n", argv[0]); -#endif - fprintf(stderr, -" where -v indicates verbose output\n"); -#ifdef __ORCAC__ - fprintf(stderr, -" -p indicates the sequence should be played\n"); -#endif - fprintf(stderr, -" and the name of at least one MIDI Synth sequence, instrument, or wave\n"); - fprintf(stderr, -" file is provided\n"); -#ifdef __ORCAC__ - fprintf(stderr, -"You can press the option key to stop the playing of a sequence file.\n"); - fprintf(stderr, -"\nThis program contains material from the ORCA/C Run-Time Libraries,\n"); - fprintf(stderr, -"copyright 1987-1992 by Byte Works, Inc. Used with permission.\n\n"); -#endif - return -1; - } - -#ifdef __ORCAC__ -/* If "play" option was selected, turn on Sound and MIDI Synth tool sets */ -if (play) { - /* Load and start the sound and MIDI Synth tool sets */ - play = LoadAndStartTools(); - if (!play) - fprintf(stderr, "The 'play' option will be ignored\n"); - else { - /* Set the callback procedures */ - callback_procs.EndSeq = (ProcPtr) &EndSeqCallback; - callback_procs.UserMeter = (ProcPtr) &BeatCallback; - callback_procs.Mstart = (ProcPtr) &MstartCallback; - callback_procs.Mstop = (ProcPtr) &MstopCallback; - callback_procs.PacketIn = (ProcPtr) &PacketInCallback; - callback_procs.SeqEvent = (ProcPtr) NULL; - callback_procs.SysEx = (ProcPtr) NULL; - callback_procs.PacketOut = (ProcPtr) NULL; - callback_procs.PgmChange = (ProcPtr) &PgmChangeCallback; - callback_procs.Mcontinue = (ProcPtr) &McontinueCallback; - callback_procs.SMarker = (ProcPtr) &SMarkerCallback; - callback_procs.RecBufFull = (ProcPtr) NULL; - callback_procs.Reserved1 = (ProcPtr) NULL; - callback_procs.Reserved2 = (ProcPtr) NULL; - SetCallBack(&callback_procs); - } - } -#endif - -/* Loop through files passed as parameters */ -while (p_num < argc) { - /* Open the file */ - errno = 0; - - if ( (file = fopen(argv[p_num],"r")) == NULL) { - printf("Cannot open file %s\n\n", argv[p_num]); - } - else { - /* Determine the kind of file by looking at the first 4 chars */ - switch (GetFileType(file)) { - case 1: - /* Sequence file */ - rewind(file); - strncpy(seqname_c,argv[p_num],15); - seqfile = file; - GetSeqData(); - break; - case 2: - /* Instrument file */ - rewind(file); - strncpy(bnkname_c,argv[p_num],15); - bnkfile = file; - GetBnkData(); - break; - case 3: - /* Waveform data file */ - rewind(file); - strncpy(wavname_c,argv[p_num],15); - wavfile = file; - GetWavData(); - break; - default: - printf("ERROR: %s is not a MIDI Synth file\n", argv[p_num]); - break; - } - fclose(file); - } - - /* Separate output from different files with 2 blank lines */ - if (++p_num < argc) printf("\n\n"); - } - -#ifdef __ORCAC__ -if (play) { - MSShutDown(); - SoundShutDown(); - DisposeHandle(sound_zero_page); - } -#endif - -return 0; -} + END OF ARCHIVE