home *** CD-ROM | disk | FTP | other *** search
- /*
- ** SMUSMIDI.C Copyright © 1991 Thomas E. Janzen
- ** Converts a DMCS .SMUS file to a standard MIDI file.
- ** Don't expect it to work on SMUS files from programs other than DMCS.
- ** 7-7-91 resumed work on it.
- ** 25 July 91 works pretty well
- ** 27 July remove double math to avoid linking math lib.
- ** 15 Aug 91
- ** 17 August 1991 Works well enough for me. Version 1.0
- */
- /* Copyright (c) 1990 by Thomas E. Janzen
- All Rights Reserved
-
- THIS SOFTWARE IS FURNISHED FREE OF CHARGE FOR STUDY AND USE AND MAY
- BE COPIED ONLY FOR PERSONAL USE OR COMPLETELY AS OFFERED WITH NO
- CHANGES FOR FREE DISTRIBUTION. NO TITLE TO AND OWNERSHIP OF THE
- SOFTWARE IS HEREBY TRANSFERRED. THOMAS E. JANZEN ASSUMES NO
- RESPONSBILITY FOR THE USE OR RELIABILITY OF THIS SOFTWARE.
-
- THOMAS E. JANZEN ASSUMES NO RESPONSIBILITY FOR THE USE OF THIS
- SOFTWARE TO COPY MUSICAL SCORE FILES PROTECTED BY COPYRIGHT LAWS.
- THIS SOFTWARE IS FOR USE ONLY WITHIN ANY AND ALL APPLICABLE LAWS.
-
- Thomas E. Janzen
- 58A School St. Apt. 2-L
- Hudson, MA 01749
- (508)562-1295
- */
- /*
- ** FACILITY:
- **
- ** SMUSMIDI file format convertor on Commodore (TM) Amiga (TM)
- ** compiled with SAS/C (TM) 5.10a
- **
- ** ABSTRACT:
- **
- ** SMUSMIDI.c converts SMUS files from DMCS (TM Electronic Arts)
- ** into standard MIDI file format files.
- **
- ** AUTHOR: Thomas E. Janzen
- **
- ** CREATION DATE: 17-AUG-1991
- **
- ** MODIFICATION HISTORY:
- ** DATE NAME DESCRIPTION
- **--
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <proto/exec.h>
- #include "iff/iff.h"
- #include "iff/smus.h"
-
- #define MIDI_FILE_TYPE ".MID"
- #define IDLEN 4
- #define TRUE 1
- #define FALSE 0
- #define SINGLMULTTRAK 0
- #define MULTITRACK 1
- #define MIDIHDRLEN 14
- #define MIDITRKHDRLEN 8
- #define SYSEXLEN 4
- #define NTRK_POS 12
- #define TICKS_PER_QUARTER 240
- #define NOTEON 0X90
- #define NOTEOFF 0X80
- #define META_EVENT 0XFF
- #define SEQ_NUM 0X00
-
- #define TEXT_EVENT 0X01
- #define COPY_EVENT 0X02
- #define TRACK_NAME 0X03
- #define INST_NAME 0X04
- #define LYRIC_EVENT 0X05
- #define MARKER_EVENT 0X06
- #define CUE_POINT 0X07
- #define CHAN_PREFIX 0X20
- #define EOT_EVENT 0X2F
- #define TEMPO_EVENT 0X51
- #define TIME_SIG_EVENT 0X58
- #define KEY_EVENT 0X59
- #define MAX_TIES 32
- #define MAX_CHORDS 32
- #define NOT_OLD_CHORD 0x40000000
-
- struct MIDI_Note_struct {
- unsigned char Status_Channel,
- Note_Number,
- Velocity;
- };
- typedef struct MIDI_Note_struct MIDI_NOTE_TYPE;
-
- struct MIDI_Header {
- unsigned int Chunk_Type;
- unsigned int Chunk_Len;
- unsigned short int Format;
- unsigned short int Num_Tracks;
- unsigned short int Division; /* of time, usu. 24 MIDI ticks or SMPTE */
- };
- typedef struct MIDI_Header MIDI_HEADER_TYPE;
-
- struct MIDI_Track {
- unsigned int Chunk_Type;
- unsigned int Chunk_Len;
- };
- typedef struct MIDI_Track MIDI_TRACK_TYPE;
-
- struct Chord_Struct {
- unsigned char Pitch,
- Tied,
- Tied_Back,
- Delete;
- };
- typedef struct Chord_Struct CHORD_TYPE;
-
- static char *MIDItoPitchName (int NoteNum, char *PitchName);
- static int SMUS_Len_to_MIDI_Delay (SEvent *Note);
- static int Variable_Length_Values (int Number, unsigned char *Array);
- static int Search_Tied_Array (char Pitch, char *Tied_Array,
- int Tied_Index);
- static int Remove_Tied_Note (int Pitch, char *Tied_Array, int Tied_Index);
- static void Insert_Null (unsigned int *MIDI_Index,
- unsigned char *MIDI_Score);
- static void Insert_Meta_Event (unsigned int *MIDI_Index,
- unsigned char *MIDI_Score,
- unsigned char Event_Type,
- unsigned int Event_Len);
- static void Send_a_Note ( unsigned int *MIDI_Index,
- unsigned char *MIDI_Score,
- unsigned char Current_Channel,
- unsigned char Current_Dynamic,
- unsigned char Pitch,
- unsigned char *Running_Status);
- static void Shutdown (void);
- static int Remove_Chord_Notes ( CHORD_TYPE *Chord_Array,
- int Chord_Array_Len);
- static int Check_Tie (char *SMUS_Score, int SMUS_Index, SEvent Note,
- int FORM_Size);
- static int Search_Chord_Array ( char Pitch,
- CHORD_TYPE *Chord_Array,
- int Chord_Index,
- int Tied);
- static int Add_Chord_Array (CHORD_TYPE *Chord_Array, unsigned char Pitch,
- int Tie, int Tie_Back, int Chord_Index);
-
- static unsigned char *SMUS_Score = NULL,
- *MIDI_Score = NULL;
- static FILE *SMUS_File = NULL,
- *MIDI_File = NULL;
- static unsigned int Just_Did_a_Delay = FALSE;
-
- void main (int argc, char *argv[])
- {
- static unsigned char
- Track_String[32],
- Current_Channel,
- Current_Dynamic = 127,
- Tied_Array[MAX_TIES],
- key;
- static CHORD_TYPE Chord_Array[MAX_CHORDS];
- static MIDI_HEADER_TYPE MIDI_FileHdr =
- {MakeID('M','T','h','d'), 6,
- MULTITRACK, 1, TICKS_PER_QUARTER};
- auto MIDI_TRACK_TYPE *MIDI_Track_ptr;
- auto unsigned char Score_Name[128],
- Running_Status = 0;
- static char SMUS_File_Name[128] = "Score.smus",
- MIDI_File_Name[128] = "ram:Score",
- filemode[2] = "r";
- static SScoreHeader Header;
- auto unsigned int FORM_Size = 0,
- Instrument_Index,
- Track,
- Temp_ID,
- MIDI_Track_Index,
- status,
- tempint,
- ID_int,
- MIDI_Delay = 0,
- len,
- Real_Tie;
- #ifdef DEBUG
- auto int debug_stopper = 62;
- #endif
- auto int Chord_Index = 0,
- Chord_Counter = 0,
- Tied_Index = 0,
- Notes_per_Track,
- Chord_Note;
- static unsigned int Start_of_Tracks_Index,
- SMUS_Index = 0,
- MIDI_Index = 0,
- Caesura = TICKS_PER_QUARTER / 24;
- static RefInstrument Instruments[32];
- static SEvent Note;
- static int Note_Counter;
- union {
- unsigned int Tempo_int;
- unsigned char Tempo_char[4];
- } MIDI_Tempo;
-
- if (argc != 3)
- {
- printf ("usage: SMUSMIDI {SMUS_file} {MIDI_file(no type)}\n");
- exit (1);
- }
- strcpy (SMUS_File_Name, argv[1]);
- if ((SMUS_File = fopen (SMUS_File_Name, filemode)) == NULL)
- {
- printf ("Can't open SMUS input file.\n");
- exit (1);
- }
- strcpy (filemode, "w");
- strcpy (MIDI_File_Name, argv[2]);
- strcat (MIDI_File_Name, MIDI_FILE_TYPE);
- if ((MIDI_File = fopen (MIDI_File_Name, filemode)) == NULL)
- {
- printf ("Can't open MIDI output file.\n");
- Shutdown ();
- }
- status = fread ((char *)&ID_int, sizeof (int), 1, SMUS_File);
- if (ID_int != FORM)
- {
- printf ("Not a FORM file\n");
- Shutdown ();
- }
- status = fread ((char *)&FORM_Size, sizeof (int), 1, SMUS_File);
- printf ("FORM is: %d bytes.\n", FORM_Size);
-
- SMUS_Score = malloc (FORM_Size);
- if (SMUS_Score == NULL)
- {
- printf ("Insufficient memory for SMUS Score\n");
- Shutdown ();
- exit (0);
- }
- MIDI_Score = malloc (4 * FORM_Size);
- memset (MIDI_Score, '\0', 4 * FORM_Size);
- if (MIDI_Score == NULL)
- {
- printf ("Insufficient memory for MIDI Score\n");
- Shutdown ();
- }
- /* Copy whole file into RAM */
- fread (SMUS_Score, FORM_Size, 1, SMUS_File);
- fclose (SMUS_File);
- SMUS_File = NULL;
-
- /* check for SMUS */
- SMUS_Index = 0;
- memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], 4);
- if (ID_int != ID_SMUS)
- {
- printf ("Input file was not an SMUS file!?\n");
- Shutdown ();
- }
- SMUS_Index += 4;
- /* check for SHDR */
- memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], 4);
- if (ID_int != ID_SHDR)
- {
- printf ("No SHDR chunk!\n");
- Shutdown ();
- }
- /* Get the header */
- SMUS_Index += 8;
- memcpy ((char *)&Header, &SMUS_Score[SMUS_Index],
- sizeof (SScoreHeader));
- MIDI_FileHdr.Num_Tracks = Header.ctTrack + 1;
- /* hope it's < 256 tracks! + tempo track */
- printf ("HEADER:\n Tempo: MM %d; %d Tracks\n",
- Header.tempo / 128, Header.ctTrack);
- SMUS_Index += sizeof (SScoreHeader);
-
- /* Start MIDI_Score */
- MIDI_Index = 0;
- memcpy (&MIDI_Score[MIDI_Index], &MIDI_FileHdr,
- sizeof (MIDI_HEADER_TYPE));
- MIDI_Index += sizeof (MIDI_HEADER_TYPE);
- /* Check for NAME */
- memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], sizeof (int));
- if (ID_int != ID_NAME)
- {
- printf ("ID Name didn't show up.\n");
- Shutdown ();
- }
- /* Get NAME */
- SMUS_Index += IDLEN;
- memcpy ((char *)&tempint, &SMUS_Score[SMUS_Index], sizeof (int));
- SMUS_Index += sizeof (int);
- memcpy ((char *)Score_Name, &SMUS_Score[SMUS_Index], tempint);
- Score_Name[tempint] = '\0';
- printf ("SCORE: %s\n", Score_Name);
- SMUS_Index += tempint + (tempint % 2);
-
- /* Check for INS1 */
- do
- {
- memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], sizeof (int));
- if (ID_int != ID_INS1)
- {
- printf ("No more instruments.\n");
- break;
- }
- SMUS_Index += IDLEN;
- /* copy NAME */
- memcpy ((char *)&tempint, &SMUS_Score[SMUS_Index], sizeof (int));
- SMUS_Index += sizeof (int);
- Instrument_Index = 0;
- memcpy ( &Instruments[Instrument_Index],
- &SMUS_Score[SMUS_Index], tempint);
- Instruments[Instrument_Index].name[tempint - 4] = '\0';
- /* terminate name */
- printf (" Instrument: %s\n",
- Instruments[Instrument_Index].name);
- SMUS_Index += tempint + (tempint % 2);
- if (Instruments[Instrument_Index].type == INS1_MIDI)
- {
- printf ("MIDI instrument, channel %d, preset %d\n",
- Instruments[Instrument_Index].data1,
- Instruments[Instrument_Index].data2);
- }
- } while (status = TRUE);
- /* Instrument index is the number of instruments now.*/
- /* I hope all the instruments have been listed by now.*/
- /*
- ** DO THE TEMPO TRACK
- */
- Start_of_Tracks_Index = SMUS_Index;
- MIDI_Track_ptr = (MIDI_TRACK_TYPE *)(&(MIDI_Score[MIDI_Index]));
- MIDI_Track_Index = MIDI_Index;
- Temp_ID = MakeID ('M', 'T', 'r', 'k');
- memcpy ((char *)&MIDI_Track_ptr->Chunk_Type, (char *)&Temp_ID,
- sizeof (int));
- MIDI_Index += sizeof (MIDI_TRACK_TYPE);
- memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], sizeof (int));
- SMUS_Index += sizeof (int);
- memcpy ((char *)&tempint, &SMUS_Score[SMUS_Index], sizeof (int));
- SMUS_Index += sizeof (int);
- printf ("Length of track: %d bytes\n", tempint);
- Notes_per_Track = tempint / sizeof (SEvent);
-
- MIDI_Score[MIDI_Index] = 0; /* must have a delay before an Event */
- MIDI_Index++;
- MIDI_Score[MIDI_Index] = META_EVENT;
- MIDI_Index++;
- MIDI_Score[MIDI_Index] = TRACK_NAME;
- MIDI_Index++;
- len = Variable_Length_Values (5, &MIDI_Score[MIDI_Index]);
- MIDI_Index += len;
- strcpy (&MIDI_Score[MIDI_Index], "Tempo");
- MIDI_Index += 5;
-
- Just_Did_a_Delay = FALSE;
- MIDI_Delay = 0;
- for (Note_Counter = 0; Note_Counter < Notes_per_Track;
- Note_Counter++)
- {
- memcpy (&Note, &SMUS_Score[SMUS_Index], sizeof (SEvent));
- SMUS_Index += sizeof (SEvent);
- switch (Note.sID)
- {
- case SID_Rest:
- do {
- MIDI_Delay += SMUS_Len_to_MIDI_Delay (&Note);
- memcpy (&Note, &SMUS_Score[SMUS_Index], sizeof (SEvent));
- SMUS_Index += sizeof (SEvent);
- Note_Counter++;
- } while ((Note.sID == SID_Rest)
- && (Note_Counter < Notes_per_Track));
- Note_Counter--;
- SMUS_Index -= sizeof (SEvent);
- Just_Did_a_Delay = TRUE;
- break;
- case SID_Instrument:
- break;
- case SID_TimeSig:
- MIDI_Index = MIDI_Index
- + Variable_Length_Values
- (MIDI_Delay, &MIDI_Score[MIDI_Index]);
- MIDI_Delay = 0;
- Just_Did_a_Delay = TRUE;
- Insert_Meta_Event (&MIDI_Index, MIDI_Score, TIME_SIG_EVENT, 4);
- MIDI_Score[MIDI_Index] = TimeNSig (Note.data) + 1;
- MIDI_Index++;
- MIDI_Score[MIDI_Index] = TimeDSig (Note.data);
- MIDI_Index++;
- MIDI_Score[MIDI_Index] = 24;
- MIDI_Index++;
- MIDI_Score[MIDI_Index] = 0x08;
- MIDI_Index++;
- Just_Did_a_Delay = FALSE;
- break;
- case SID_KeySig:
- case SID_Dynamic:
- case SID_MIDI_Chnl:
- case SID_MIDI_Preset:
- case SID_Clef:
- break;
- case SID_Tempo:
- MIDI_Index = MIDI_Index
- + Variable_Length_Values
- (MIDI_Delay, &MIDI_Score[MIDI_Index]);
- MIDI_Delay = 0;
- Just_Did_a_Delay = TRUE;
- Insert_Meta_Event (&MIDI_Index, MIDI_Score, TEMPO_EVENT, 3);
- MIDI_Tempo.Tempo_int = (60 * 1000000) / Note.data;
- memcpy (&MIDI_Score[MIDI_Index],
- &(MIDI_Tempo.Tempo_char[1]), 3);
- MIDI_Index += 3;
- break;
- case SID_Mark:
- break;
- default:
- if ((SID_FirstNote <= Note.sID) && (Note.sID <= SID_LastNote))
- {
- if (!IsChord (Note.data)) /* if the note is chorded */
- {
- MIDI_Delay += SMUS_Len_to_MIDI_Delay (&Note);
- }
- }
- }
- }
- MIDI_Index = MIDI_Index
- + Variable_Length_Values
- (MIDI_Delay, &MIDI_Score[MIDI_Index]);
- MIDI_Delay = 0;
- Just_Did_a_Delay = TRUE;
- Insert_Meta_Event (&MIDI_Index, MIDI_Score, EOT_EVENT, 0);
- Temp_ID = MIDI_Index - MIDI_Track_Index - 8;
- memcpy ((char *)&MIDI_Track_ptr->Chunk_Len, (char *)&Temp_ID,
- sizeof (int));
- Running_Status = 0;
- /*
- ** end of tempo track
- */
- SMUS_Index = Start_of_Tracks_Index;
- for (Track = 0; Track < Header.ctTrack; Track++)
- {
- MIDI_Track_ptr = (MIDI_TRACK_TYPE *)(&(MIDI_Score[MIDI_Index]));
- MIDI_Track_Index = MIDI_Index;
- Temp_ID = MakeID ('M', 'T', 'r', 'k');
- memcpy ((char *)&MIDI_Track_ptr->Chunk_Type, (char *)&Temp_ID,
- sizeof (int));
- MIDI_Index += sizeof (MIDI_TRACK_TYPE);
- /* Make sure you put in the chunk length at the end! */
- memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], sizeof (int));
- if (ID_int != ID_TRAK)
- {
- printf ("There are no Tracks!\n");
- }
- SMUS_Index += sizeof (int);
- memcpy ((char *)&tempint, &SMUS_Score[SMUS_Index], sizeof (int));
- SMUS_Index += sizeof (int);
- MIDI_Score[MIDI_Index] = 0; /* must have a delay before an Event */
- MIDI_Index++;
- MIDI_Score[MIDI_Index] = META_EVENT;
- MIDI_Index++;
- MIDI_Score[MIDI_Index] = TRACK_NAME;
- MIDI_Index++;
- sprintf (Track_String, "Track %d", Track);
- len = Variable_Length_Values (strlen (Track_String),
- &MIDI_Score[MIDI_Index]);
- MIDI_Index += len;
- strcpy (&MIDI_Score[MIDI_Index], Track_String);
- MIDI_Index += strlen (Track_String);
- Notes_per_Track = tempint / sizeof (SEvent);
- Just_Did_a_Delay = FALSE;
- for (Note_Counter = 0; Note_Counter < Notes_per_Track;
- Note_Counter++)
- {
- memcpy (&Note, &SMUS_Score[SMUS_Index], sizeof (SEvent));
- SMUS_Index += sizeof (SEvent);
- switch (Note.sID)
- {
- case SID_Rest:
- MIDI_Delay = 0;
- do
- {
- MIDI_Delay += SMUS_Len_to_MIDI_Delay (&Note);
- memcpy (&Note, &SMUS_Score[SMUS_Index], sizeof (SEvent));
- SMUS_Index += sizeof (SEvent);
- Note_Counter++;
- } while ((Note.sID == SID_Rest)
- && (Note_Counter < Notes_per_Track));
- Note_Counter--;
- SMUS_Index -= sizeof (SEvent);
- if (Just_Did_a_Delay) /* 2 delays can't appear together */
- {
- Insert_Null (&MIDI_Index, MIDI_Score);
- }
- MIDI_Index = MIDI_Index
- + Variable_Length_Values
- (MIDI_Delay, &MIDI_Score[MIDI_Index]);
- Just_Did_a_Delay = TRUE;
- break;
- case SID_Instrument:
- case SID_TimeSig:
- break;
- case SID_KeySig:
- switch (Note.data)
- {
- case 0: case 1: case 2: case 3: case 4: case 5:
- case 6: case 7:
- key = Note.data & 0x7F;
- break;
- case 8: case 9: case 10: case 11:
- case 12: case 13: case 14:
- key = ((7 - Note.data) & 0x7F);
- break;
- default:
- break;
- }
- Insert_Meta_Event (&MIDI_Index, MIDI_Score, KEY_EVENT, 2);
- MIDI_Score[MIDI_Index] = key;
- MIDI_Index++;
- MIDI_Score[MIDI_Index] = 0x00;
- MIDI_Index++;
- break;
- case SID_Dynamic:
- Current_Dynamic = Note.data;
- break;
- case SID_MIDI_Chnl:
- Current_Channel = Note.data;
- Insert_Meta_Event (&MIDI_Index, MIDI_Score, CHAN_PREFIX, 1);
- MIDI_Score[MIDI_Index] = Note.data;
- MIDI_Index++;
- break;
- case SID_MIDI_Preset:
- if (!Just_Did_a_Delay)
- {
- MIDI_Score[MIDI_Index] = 0;
- MIDI_Index++;
- }
- MIDI_Score[MIDI_Index] = 0xC0 | Current_Channel;
- MIDI_Index++;
- MIDI_Score[MIDI_Index] = Note.data;
- MIDI_Index++;
- Running_Status = 0xC0 | Current_Channel;
- break;
- case SID_Clef:
- case SID_Tempo:
- case SID_Mark:
- break;
- default:
- if ((SID_FirstNote <= Note.sID) /* if it's a pitch number */
- && (Note.sID <= SID_LastNote))
- {
- Real_Tie = Check_Tie (SMUS_Score, SMUS_Index,
- Note, FORM_Size);
- /*
- ** The following tedious logic decides
- ** whether to send a note
- ** whether to delay
- ** whether to stop the note
- ** on the basis of
- ** whether the note is in the tied array
- ** whether the note is in the chord array
- ** whether the note is chorded forward
- ** whether the note is tied forward
- */
- #ifdef DEBUG
- if (Note.sID == debug_stopper)
- {
- puts ("stopit");
- }
- #endif
- if (Real_Tie) /* if the note is tied forward */
- {
- if (Search_Tied_Array (Note.sID, Tied_Array,
- Tied_Index)) /* and if the note is tied backward*/
- {
- if (IsChord (Note.data)) /* and if it's Chorded */
- {
- if (Search_Chord_Array (Note.sID, Chord_Array,
- Chord_Index, Real_Tie) != NOT_OLD_CHORD)
- /* and if it's not in an old chord */
- {
- ;
- }
- else
- {
- Chord_Index = Add_Chord_Array (Chord_Array,
- Note.sID, Real_Tie, TRUE, Chord_Index);
- }
- }
- else /* tied forward and backward,but not chorded*/
- /* this means that we are at the end of a chord
- ** and should play off the non-tied notes in chord
- */
- {
- if (Search_Chord_Array (Note.sID, Chord_Array,
- Chord_Index, Real_Tie) != NOT_OLD_CHORD)
- /* tied forward/backward;old chord, not chord */
- {
- if (Just_Did_a_Delay)
- {
- Insert_Null (&MIDI_Index, MIDI_Score);
- }
- MIDI_Delay = SMUS_Len_to_MIDI_Delay (&Note)
- - Caesura;
- MIDI_Index = MIDI_Index
- + Variable_Length_Values
- (MIDI_Delay, &MIDI_Score[MIDI_Index]);
- Just_Did_a_Delay = TRUE;
- /* send note off for chord notes */
- for ( Chord_Counter = 0;
- Chord_Counter < Chord_Index;
- Chord_Counter++)
- {
- if (!Chord_Array[Chord_Counter].Tied)
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, 0,
- Chord_Array[Chord_Counter].Pitch,
- &Running_Status);
- Chord_Array[Chord_Counter].Delete
- = TRUE;
- Tied_Index =
- Remove_Tied_Note (
- Chord_Array[Chord_Counter].Pitch,
- Tied_Array, Tied_Index);
- }
- }
- if (Just_Did_a_Delay)
- {
- Insert_Null (&MIDI_Index, MIDI_Score);
- }
- MIDI_Score[MIDI_Index] = Caesura;
- MIDI_Index++;
- Just_Did_a_Delay = TRUE;
- }
- else /* tied forward/backward, but
- ** not in an old chord and not chorded */
- {
- if (Just_Did_a_Delay)
- {
- Insert_Null (&MIDI_Index, MIDI_Score);
- }
- MIDI_Delay = SMUS_Len_to_MIDI_Delay (&Note)
- - Caesura;
- MIDI_Index = MIDI_Index
- + Variable_Length_Values
- (MIDI_Delay, &MIDI_Score[MIDI_Index]);
- Just_Did_a_Delay = TRUE;
- /* send note off for non-tied chord notes */
- for ( Chord_Counter = 0;
- Chord_Counter < Chord_Index;
- Chord_Counter++)
- {
- if (!Chord_Array[Chord_Counter].Tied)
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, 0,
- Chord_Array[Chord_Counter].Pitch,
- &Running_Status);
- Chord_Array[Chord_Counter].Delete
- = TRUE;
- Tied_Index =
- Remove_Tied_Note (
- Chord_Array[Chord_Counter].Pitch,
- Tied_Array, Tied_Index);
- }
- }
- if (Just_Did_a_Delay)
- {
- Insert_Null (&MIDI_Index, MIDI_Score);
- }
- MIDI_Score[MIDI_Index] = Caesura;
- MIDI_Index++;
- Just_Did_a_Delay = TRUE;
- }
- }
- }
- else /* tied forward but not backward */
- {
- /* add to Tied_Array */
- Tied_Array[Tied_Index] = Note.sID;
- Tied_Index++;
- if (IsChord (Note.data)) /*if the note is chorded*/
- {
- if ((Chord_Note =
- Search_Chord_Array (Note.sID, Chord_Array,
- Chord_Index, Real_Tie)) == NOT_OLD_CHORD)
- /* if not in chord array */
- {
- Chord_Index = Add_Chord_Array (Chord_Array,
- Note.sID, Real_Tie, FALSE, Chord_Index);
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, Current_Dynamic,
- Note.sID, &Running_Status);
- }
- else
- {
- if (!Chord_Array[Chord_Note].Tied_Back)
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, Current_Dynamic,
- Note.sID, &Running_Status);
- }
- }
- }
- else /* tied forward, not tied back, not chord */
- /* we are at the end of a chord, so we have to play
- ** all the non-tied chord notes */
- {
- Chord_Note =
- Search_Chord_Array (Note.sID, Chord_Array,
- Chord_Index, Real_Tie);
- if (Chord_Note != NOT_OLD_CHORD)
- {
- if (!Chord_Array[Chord_Note].Tied_Back)
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, Current_Dynamic,
- Note.sID, &Running_Status);
- }
- }
- else
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, Current_Dynamic,
- Note.sID, &Running_Status);
- }
- if (Just_Did_a_Delay)
- {
- Insert_Null (&MIDI_Index, MIDI_Score);
- }
- MIDI_Delay = SMUS_Len_to_MIDI_Delay (&Note)
- - Caesura;
- MIDI_Index = MIDI_Index
- + Variable_Length_Values
- (MIDI_Delay, &MIDI_Score[MIDI_Index]);
- Just_Did_a_Delay = TRUE;
- /* send note off for non-tied chord notes */
- for ( Chord_Counter = 0;
- Chord_Counter < Chord_Index;
- Chord_Counter++)
- {
- if (!Chord_Array[Chord_Counter].Tied)
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, 0,
- Chord_Array[Chord_Counter].Pitch,
- &Running_Status);
- Chord_Array[Chord_Counter].Delete = TRUE;
- Tied_Index =
- Remove_Tied_Note (
- Chord_Array[Chord_Counter].Pitch,
- Tied_Array, Tied_Index);
- }
- }
- if (Just_Did_a_Delay)
- {
- Insert_Null (&MIDI_Index, MIDI_Score);
- }
- MIDI_Score[MIDI_Index] = Caesura;
- MIDI_Index++;
- Just_Did_a_Delay = TRUE;
- }
- }
- }
- else /* it's not tied to the next note */
- {
- /* if the note is in the tied array */
- if (Search_Tied_Array (Note.sID, Tied_Array,
- Tied_Index))
- {
- Tied_Index =
- Remove_Tied_Note (Note.sID, Tied_Array,
- Tied_Index);
- if (IsChord (Note.data)) /* if chorded */
- {
- if (Search_Chord_Array (Note.sID, Chord_Array,
- Chord_Index, Real_Tie) == NOT_OLD_CHORD)
- /* if not in chord array */
- {
- Chord_Index = Add_Chord_Array (Chord_Array,
- Note.sID, Real_Tie, TRUE, Chord_Index);
- }
- }
- else /* tied backward not forward, not a chord */
- {
- if (Just_Did_a_Delay)
- {
- Insert_Null (&MIDI_Index, MIDI_Score);
- }
- MIDI_Delay = SMUS_Len_to_MIDI_Delay (&Note)
- - Caesura;
- /*
- ** Caesura is for time to get in the note off
- ** so the synth doesn't choke
- */
- MIDI_Index = MIDI_Index + Variable_Length_Values
- (MIDI_Delay, &MIDI_Score[MIDI_Index]);
- Just_Did_a_Delay = TRUE;
- if (Search_Chord_Array (Note.sID, Chord_Array,
- Chord_Index, Real_Tie) == NOT_OLD_CHORD)
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, 0,
- Note.sID, &Running_Status);
- }
- /* send note off for all chord notes */
- for ( Chord_Counter = 0;
- Chord_Counter < Chord_Index;
- Chord_Counter++)
- {
- if (!Chord_Array[Chord_Counter].Tied)
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, 0,
- Chord_Array[Chord_Counter].Pitch,
- &Running_Status);
- Tied_Index =
- Remove_Tied_Note (
- Chord_Array[Chord_Counter].Pitch,
- Tied_Array, Tied_Index);
- Chord_Array[Chord_Counter].Delete = TRUE;
- }
- }
- if (Just_Did_a_Delay)
- {
- Insert_Null (&MIDI_Index, MIDI_Score);
- }
- MIDI_Score[MIDI_Index] = Caesura;
- MIDI_Index++;
- Just_Did_a_Delay = TRUE;
- }
- }
- else /* not tied backwards or forwards */
- {
- if (IsChord (Note.data)) /* if chorded */
- {
- if (( Chord_Note = Search_Chord_Array
- (Note.sID, Chord_Array, Chord_Index,
- Real_Tie)) == NOT_OLD_CHORD)
- {
- Chord_Index = Add_Chord_Array (Chord_Array,
- Note.sID, Real_Tie, FALSE, Chord_Index);
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, Current_Dynamic,
- Note.sID, &Running_Status);
- /*this was not sending the extra notes*/
- }
- else
- {
- if (!Chord_Array[Chord_Note].Tied_Back)
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, Current_Dynamic,
- Note.sID, &Running_Status);
- }
- }
- }
- else /* not tied back or forward, not chorded */
- {
- Chord_Note =
- Search_Chord_Array (Note.sID, Chord_Array,
- Chord_Index, Real_Tie);
- if (Chord_Note != NOT_OLD_CHORD)
- {
- if (!Chord_Array[Chord_Note].Tied_Back)
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, Current_Dynamic,
- Note.sID, &Running_Status);
- }
- }
- else
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, Current_Dynamic,
- Note.sID, &Running_Status);
- }
- if (Just_Did_a_Delay)
- {
- Insert_Null (&MIDI_Index, MIDI_Score);
- }
- MIDI_Delay = SMUS_Len_to_MIDI_Delay (&Note)
- - Caesura;
- MIDI_Index = MIDI_Index
- + Variable_Length_Values
- (MIDI_Delay,
- &MIDI_Score[MIDI_Index]);
- Just_Did_a_Delay = TRUE;
- if (Chord_Note == NOT_OLD_CHORD)
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, 0,
- Note.sID, &Running_Status);
- }
- /* send note off for all chord notes */
- for ( Chord_Counter = 0;
- Chord_Counter < Chord_Index;
- Chord_Counter++)
- {
- if (!Chord_Array[Chord_Counter].Tied)
- {
- Send_a_Note (&MIDI_Index, MIDI_Score,
- Current_Channel, 0,
- Chord_Array[Chord_Counter].Pitch,
- &Running_Status);
- Tied_Index =
- Remove_Tied_Note (
- Chord_Array[Chord_Counter].Pitch,
- Tied_Array, Tied_Index);
- Chord_Array[Chord_Counter].Delete
- = TRUE;
- }
- }
- if (Just_Did_a_Delay)
- {
- Insert_Null (&MIDI_Index, MIDI_Score);
- }
- MIDI_Score[MIDI_Index] = Caesura;
- MIDI_Index++;
- Just_Did_a_Delay = TRUE;
- }
- }
- }
- }
- Chord_Index = Remove_Chord_Notes (Chord_Array, Chord_Index);
- break;
- }
- }
- Insert_Meta_Event (&MIDI_Index, MIDI_Score, EOT_EVENT, 0);
- Temp_ID = MIDI_Index - MIDI_Track_Index - 8;
- memcpy ((char *)&MIDI_Track_ptr->Chunk_Len, (char *)&Temp_ID,
- sizeof (int));
- Running_Status = 0;
- Chord_Index = 0;
- Tied_Index = 0;
- }
- fwrite (MIDI_Score, MIDI_Index, 1, MIDI_File);
- fflush (MIDI_File);
- Shutdown ();
- exit (0);
- }
-
- static int SMUS_Len_to_MIDI_Delay (SEvent *Note)
- {
- auto long int Length;
-
- Length = (4 * TICKS_PER_QUARTER) << 15; /* one scaled unit is 0x8000 */
- if (IsDot (Note->data))
- {
- Length *= 3;
- }
-
- switch (NTuplet (Note->data))
- {
- case 1: /* triplet */
- Length *= 2;
- Length /= 3;
- break;
- case 2: /* quintuplet */
- Length *= 4;
- Length /= 5;
- break;
- case 3: /* septuplet */
- Length *= 6;
- Length /= 7;
- break;
- default:
- break;
- }
- if (IsDot (Note->data))
- {
- Length /= 2;
- }
-
- Length = Length >> Division (Note->data);
- Length += 0x4000; /* add a half unit to round off by truncating. */
- Length = Length >> 15;
- return Length;
- }
-
- static int Variable_Length_Values (int Number, unsigned char *Array)
- {
- auto unsigned char Byte4,
- MSByte,
- MIDbyte,
- LSByte;
-
- LSByte = (Number & 0x0000007F);
- MIDbyte = ((Number & 0x00003F80) >> 7) | 0x80;
- MSByte = ((Number & 0x001FC000) >> 14) | 0x80;
- Byte4 = ((Number & 0x0FE00000) >> 21) | 0x80;
- if (Byte4 != 0x80)
- {
- Array[0] = Byte4;
- Array[1] = MSByte;
- Array[2] = MIDbyte;
- Array[3] = LSByte;
- return 4;
- }
- if (MSByte != 0x80)
- {
- Array[0] = MSByte;
- Array[1] = MIDbyte;
- Array[2] = LSByte;
- return 3;
- }
-
- if (MIDbyte != 0x80)
- {
- Array[0] = MIDbyte;
- Array[1] = LSByte;
- return 2;
- }
- Array[0] = LSByte;
-
- return 1;
- }
-
- static int Search_Tied_Array ( char Pitch,
- char *Tied_Array,
- int Tied_Index)
- {
- auto int Tied_Counter;
-
- for (Tied_Counter = 0; Tied_Counter < Tied_Index; Tied_Counter++)
- {
- if (Pitch == Tied_Array[Tied_Counter])
- {
- return TRUE;
- }
- }
- return FALSE;
- }
-
- static int Search_Chord_Array ( char Pitch,
- CHORD_TYPE *Chord_Array,
- int Chord_Index,
- int Tied)
- {
- auto int Chord_Counter;
-
- for (Chord_Counter = 0; Chord_Counter < Chord_Index; Chord_Counter++)
- {
- if (Pitch == Chord_Array[Chord_Counter].Pitch)
- {
- if (Chord_Array[Chord_Counter].Tied)
- {
- Chord_Array[Chord_Counter].Tied_Back = TRUE;
- }
- Chord_Array[Chord_Counter].Tied = Tied;
- return Chord_Counter;
- }
- }
- return NOT_OLD_CHORD;
- }
-
- static int Remove_Tied_Note (int Pitch, char *Tied_Array, int Tied_Index)
- {
- auto int Tied_Counter,
- Inner_Index;
-
- for (Tied_Counter = 0; Tied_Counter < Tied_Index; Tied_Counter++)
- {
- if (Tied_Array[Tied_Counter] == Pitch)
- {
- for ( Inner_Index = Tied_Counter; Inner_Index < Tied_Index;
- Inner_Index++)
- {
- Tied_Array[Inner_Index] = Tied_Array[Inner_Index + 1];
- }
- Tied_Index--;
- break;
- }
- }
- return Tied_Index;
- }
-
- static int Remove_Chord_Notes ( CHORD_TYPE *Chord_Array,
- int Chord_Array_Len)
- {
- auto CHORD_TYPE New_Chord_Array[MAX_CHORDS];
- auto int Chord_Index = 0,
- New_Chord_Counter = 0;
-
- for (Chord_Index = 0; Chord_Index < Chord_Array_Len; Chord_Index++)
- {
- if (!Chord_Array[Chord_Index].Delete)
- {
- New_Chord_Array[New_Chord_Counter] = Chord_Array[Chord_Index];
- New_Chord_Counter++;
- }
- }
- for (Chord_Index = 0; Chord_Index < New_Chord_Counter; Chord_Index++)
- {
- Chord_Array[Chord_Index] =New_Chord_Array[Chord_Index];
- }
- return New_Chord_Counter;
- }
-
- static void Insert_Null (unsigned int *MIDI_Index,
- unsigned char *MIDI_Score)
- {
- Insert_Meta_Event (MIDI_Index, MIDI_Score, TEXT_EVENT, 4);
- strcpy (&MIDI_Score[*MIDI_Index], "NULL");
- (*MIDI_Index) += 4;
- return;
- }
-
- static void Insert_Meta_Event (unsigned int *MIDI_Index,
- unsigned char *MIDI_Score,
- unsigned char Event_Type,
- unsigned int Event_Len)
- {
- if (!Just_Did_a_Delay)
- {
- MIDI_Score[*MIDI_Index] = 0x00;
- (*MIDI_Index)++;
- }
- MIDI_Score[*MIDI_Index] = META_EVENT;
- (*MIDI_Index)++;
- MIDI_Score[*MIDI_Index] = Event_Type;
- (*MIDI_Index)++;
- MIDI_Score[*MIDI_Index] = Event_Len;
- (*MIDI_Index)++;
- Just_Did_a_Delay = FALSE;
- return;
- }
-
- static void Send_a_Note ( unsigned int *MIDI_Index,
- unsigned char *MIDI_Score,
- unsigned char Current_Channel,
- unsigned char Current_Dynamic,
- unsigned char Pitch,
- unsigned char *Running_Status)
- {
- static MIDI_NOTE_TYPE MIDI_Note;
-
- if (!Just_Did_a_Delay)
- {
- MIDI_Score[*MIDI_Index] = 0x00;
- (*MIDI_Index)++;
- }
- MIDI_Note.Status_Channel = NOTEON | Current_Channel;
- MIDI_Note.Note_Number = Pitch;
- MIDI_Note.Velocity = Current_Dynamic;
- if (MIDI_Note.Status_Channel == *Running_Status)
- {
- memcpy ( &MIDI_Score[*MIDI_Index], &(MIDI_Note.Note_Number), 2);
- (*MIDI_Index) += 2;
- }
- else /* running status changed */
- {
- memcpy (&MIDI_Score[*MIDI_Index], &MIDI_Note, sizeof MIDI_Note);
- (*MIDI_Index) += sizeof (MIDI_NOTE_TYPE);
- *Running_Status = MIDI_Note.Status_Channel;
- }
- Just_Did_a_Delay = FALSE;
- return;
- }
-
- static void Shutdown (void)
- {
- if (SMUS_Score) free (SMUS_Score);
- if (MIDI_Score) free (MIDI_Score);
- if (SMUS_File) fclose (SMUS_File);
- if (MIDI_File) fclose (MIDI_File);
- exit (0);
- }
-
- static int Check_Tie (char *SMUS_Score, int SMUS_Index, SEvent Note,
- int FORM_Size)
- {
- auto SEvent Note_temp;
-
- /* Pass the end of the current chord to look into the next chord */
- if (IsChord (Note.data))
- {
- do
- {
- memcpy (&Note_temp, &SMUS_Score[SMUS_Index], sizeof (SEvent));
- SMUS_Index += sizeof (SEvent); /* point to next event */
- } while ((SMUS_Index < FORM_Size) && (IsChord (Note_temp.data)));
- }
- /* Now pointing to beginning of next chord or note */
- if (!IsTied (Note.data)) /* if it's not tied, it's not tied */
- {
- return FALSE;
- }
- /* if it was tied, check that there is a next same pitch to tie to */
- while (SMUS_Index < FORM_Size)
- {
- memcpy (&Note_temp, &SMUS_Score[SMUS_Index], sizeof (SEvent));
- SMUS_Index += sizeof (SEvent);
- if (( SID_FirstNote <= Note_temp.sID) /* if it's a note event */
- && (Note_temp.sID <= SID_LastNote))
- {
- if (!IsChord (Note_temp.data)) /* if at end of next chord */
- {
- if (Note.sID == Note_temp.sID)/*last chance to match tie note*/
- {
- return TRUE;
- }
- return FALSE; /* the last note in next chord didn't match */
- }
- else /* we're in a note inside the next chord */
- {
- if (Note_temp.sID == Note.sID) /* if it matches the tie */
- {
- return TRUE; /* return true */
- }
- } /* otherwise keep looking through this chord */
- }
- }
- return FALSE;
- }
-
- static int Add_Chord_Array (CHORD_TYPE *Chord_Array, unsigned char Pitch,
- int Tie, int Tie_Back, int Chord_Index)
- {
- if (Chord_Index == (MAX_CHORDS - 1))
- {
- puts ("chord array too long");
- Shutdown();
- }
- Chord_Array[Chord_Index].Pitch = Pitch;
- Chord_Array[Chord_Index].Tied = Tie;
- Chord_Array[Chord_Index].Tied_Back = Tie_Back;
- Chord_Array[Chord_Index].Delete = FALSE;
- Chord_Index++;
- return Chord_Index;
- }
-