//Paint Events public void PaintEvents(PaintEventArgs e) { //Get a copy of currentMidiObjects Events MidiEvent[] CurrentMidiEvents = new MidiEvent[0]; Array.Resize(ref CurrentMidiEvents, CurrentMidiObject.Track.Events.Length); Array.Copy(CurrentMidiObject.Track.Events, CurrentMidiEvents, CurrentMidiObject.Track.Events.Length); if (CurrentMidiEvents != null && CurrentMidiEvents.Length > 0 && CurrentMidiEvents[0] != null) { MidiEvent CurrentEvent = null; for (int EventIndex = 0; EventIndex <= CurrentMidiEvents.Length - 1; EventIndex++) { CurrentEvent = CurrentMidiEvents[EventIndex]; //Paint Tempo Events : Paint all TempoEvents before NoteDown Events, for depth if (CurrentEvent is TempoMidiEvent) { TempoMidiEvent CurrentTempoEvent = (TempoMidiEvent)CurrentEvent; e.Graphics.FillRectangle(Brushes.Yellow, (CurrentTempoEvent.CellPosition * CellWidth) + (CellWidth / 2), 0, (CellWidth / 2), ROWCOUNT * CellHeight); } //Paint InstrumentEvents : Paint all InstrumentEvents before NoteDown Events, for depth if (CurrentEvent is InstrumentMidiEvent) { InstrumentMidiEvent CurrentTempoEvent = (InstrumentMidiEvent)CurrentEvent; e.Graphics.FillRectangle(Brushes.Red, (CurrentTempoEvent.CellPosition * CellWidth), 0, (CellWidth / 2), ROWCOUNT * CellHeight); } } //for each Note for (int EventIndex = 0; EventIndex <= CurrentMidiEvents.Length - 1; EventIndex++) { CurrentEvent = CurrentMidiEvents[EventIndex]; //Paint note events if (CurrentEvent.Type == NOTE_DOWN) { //Paint notes e.Graphics.FillRectangle(NoteFill, CurrentEvent.CellPosition * CellWidth, (127 - CurrentEvent.Paramater1) * CellHeight, CurrentEvent.Length * CellWidth, CellHeight); e.Graphics.DrawRectangle(NoteOutline, CurrentEvent.CellPosition * CellWidth, (127 - CurrentEvent.Paramater1) * CellHeight, CurrentEvent.Length * CellWidth, CellHeight); } } //for each selected note if (SelectedEvents != null && SelectedEvents.Length > 0 && SelectedEvents[0] != null) { for (int EventIndex = 0; EventIndex <= SelectedEvents.Length - 1; EventIndex++) { CurrentEvent = SelectedEvents[EventIndex]; //Paint note events if (CurrentEvent.Type == NOTE_DOWN) { //Paint notes e.Graphics.FillRectangle(Brushes.Red, CurrentEvent.CellPosition * CellWidth, (127 - CurrentEvent.Paramater1) * CellHeight, CurrentEvent.Length * CellWidth, CellHeight); e.Graphics.DrawRectangle(Pens.Black, CurrentEvent.CellPosition * CellWidth, (127 - CurrentEvent.Paramater1) * CellHeight, CurrentEvent.Length * CellWidth, CellHeight); } } } e.Dispose(); } }
//Validate Instrument event, to avoid overlapping public Boolean ValidateInstrumentPlacement(MidiEvent[] CurrentMidiEvents, MidiEvent CurrentEvent) { //Caste current event to TempoEvent InstrumentMidiEvent CurrentTempoEvent = (InstrumentMidiEvent)CurrentEvent; //If there are no events at the moment, return true if (CurrentMidiEvents.Length == 0 || CurrentMidiEvents[0] == null) { return(true); } for (int i = 0; i < CurrentMidiEvents.Length; i++) { //for each event that is a InstrumentMidiEvent, check for overlapping location if (CurrentMidiEvents[i] is InstrumentMidiEvent && CurrentMidiEvents[i].CellPosition == CurrentTempoEvent.CellPosition) { //if there is an overlap, return false. Event will not be placed return(false); } } //If there is no instrument event here, return true return(true); }
//Determine the Instrument number at a certain cell public byte InstrumentAtPosition(int MyCellPosition) { byte Instrument = 0; //Get a copy of currentMidiObjects Events MidiEvent[] CurrentMidiEvents = new MidiEvent[0]; Array.Resize(ref CurrentMidiEvents, CurrentMidiObject.Track.Events.Length); Array.Copy(CurrentMidiObject.Track.Events, CurrentMidiEvents, CurrentMidiObject.Track.Events.Length); //check each event for (int EventIndex = 0; EventIndex < CurrentMidiEvents.Length; EventIndex++) { //Update Current Instrument, to be the Instrument closest to the mouseposition, but still to the left(time) if (CurrentMidiEvents[EventIndex] is InstrumentMidiEvent && CurrentMidiEvents[EventIndex].CellPosition <= MyCellPosition) { InstrumentMidiEvent CurrentInstrumentEvent = (InstrumentMidiEvent)CurrentMidiEvents[EventIndex]; //Parameter1 Holds the Instrument value Instrument = (CurrentInstrumentEvent.Paramater1); } } //If no Instrument event is found, midi assumes instrument 0, Acoustice Grand Piano return(Instrument); }
//Generate Midi Event Bytes, Calculate Delta times in bytes. public void GenerateMidiEventByteArray(MidiEvent[] MidiEventArray) { int ByteIndex = 0; for (int EventIndex = 0; EventIndex <= MidiEventArray.Length - 1; EventIndex++) { //Convert Delta times to Big-Endian bytes (max 4 bytes) if ((MidiEventArray[EventIndex].Delta >> SEVENSHIFT * 3) > 0) { Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = Convert.ToByte(128 | (MidiEventArray[EventIndex].Delta >> SEVENSHIFT * 3)); ByteIndex += 1; } if ((MidiEventArray[EventIndex].Delta >> SEVENSHIFT * 2) > 0) { Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = Convert.ToByte(128 | (MidiEventArray[EventIndex].Delta >> SEVENSHIFT * 2)); ByteIndex += 1; } if ((MidiEventArray[EventIndex].Delta >> SEVENSHIFT) > 0) { Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = Convert.ToByte(128 | MidiEventArray[EventIndex].Delta >> SEVENSHIFT); ByteIndex += 1; } //Final byte Delta Time Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = Convert.ToByte(127 & (MidiEventArray[EventIndex].Delta)); ByteIndex += 1; //Decide how to write event data if (MidiEventArray[EventIndex] is TempoMidiEvent) { //Caste Event TempoMidiEvent CurrentTempoEvent = (TempoMidiEvent)MidiEventArray[EventIndex]; //Meta Event Number Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = CurrentTempoEvent.MetaEventNumber; ByteIndex += 1; //Meta Event Type Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = CurrentTempoEvent.MetaEventType; ByteIndex += 1; //Meta Event Data Length Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = CurrentTempoEvent.MetaEventDataLength; ByteIndex += 1; //Quarter Note Time Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = Convert.ToByte(255 & (CurrentTempoEvent.QuarterNoteTime >> 16)); ByteIndex += 1; //Quarter Note Time Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = Convert.ToByte(255 & (CurrentTempoEvent.QuarterNoteTime >> 8)); ByteIndex += 1; //Quarter Note Time Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = Convert.ToByte(255 & (CurrentTempoEvent.QuarterNoteTime)); ByteIndex += 1; } else if (MidiEventArray[EventIndex] is InstrumentMidiEvent) { //Caste Event InstrumentMidiEvent CurrentTempoEvent = (InstrumentMidiEvent)MidiEventArray[EventIndex]; //Instrument Event Number :channel default zero Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = Convert.ToByte(CurrentTempoEvent.Type << 4); ByteIndex += 1; //Meta Event Type Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = CurrentTempoEvent.Paramater1; ByteIndex += 1; } else { //Event Type & Channel(Zero) TODO:This defaults channel to zero always Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = Convert.ToByte(MidiEventArray[EventIndex].Type << 4); ByteIndex += 1; //Param1 Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = MidiEventArray[EventIndex].Paramater1; ByteIndex += 1; //Param2 Array.Resize(ref TrackChunkBytes, ByteIndex + 1); TrackChunkBytes[ByteIndex] = MidiEventArray[EventIndex].Paramater2; ByteIndex += 1; } } //Add end of Track Event Array.Resize(ref TrackChunkBytes, ByteIndex + 6); TrackChunkBytes[ByteIndex] = EndOfTrack[0]; ByteIndex += 1; TrackChunkBytes[ByteIndex] = EndOfTrack[1]; ByteIndex += 1; TrackChunkBytes[ByteIndex] = EndOfTrack[2]; ByteIndex += 1; TrackChunkBytes[ByteIndex] = EndOfTrack[3]; ByteIndex += 1; TrackChunkBytes[ByteIndex] = EndOfTrack[4]; ByteIndex += 1; TrackChunkBytes[ByteIndex] = EndOfTrack[5]; }
//Create TrackChunk Object from Array of Bytes public void TrackChunkFromBytes(byte[] TrackBytes) { //MidiEvent int Delta = 0; sbyte EventType; sbyte MidiChannel; byte Param1; byte Param2; //TempoEvent int MicroSecondsPerQuarterNote = 1; //InstrumentEvent byte InstrumentNumber = 1; MidiEvent[] OpenedEvents = new MidiEvent[1]; Boolean DeltaRetrieved = false; int NextEventIndex = 0; byte NextByteValue; for (int ByteIndex = TRACKHEADERLENGTH; ByteIndex < TrackBytes.Length - 1; ByteIndex++) { Delta = 0; while (!(DeltaRetrieved)) { NextByteValue = TrackBytes[ByteIndex]; if ((NextByteValue) >= 128) { Delta = NextByteValue & 127; Delta = Delta << SHIFT; } else { Delta = Delta | NextByteValue; DeltaRetrieved = true; } ByteIndex++; } DeltaRetrieved = false; NextByteValue = TrackBytes[ByteIndex]; //If its a Meta Event if (NextByteValue == 0xff) { ByteIndex++; NextByteValue = TrackBytes[ByteIndex]; if ((NextByteValue == 0x2F)) { //EOT found break; } ByteIndex++; NextByteValue = TrackBytes[ByteIndex]; ByteIndex++; MicroSecondsPerQuarterNote = TrackBytes[ByteIndex] << 8; ByteIndex++; MicroSecondsPerQuarterNote = (MicroSecondsPerQuarterNote | TrackBytes[ByteIndex]) << 8; ByteIndex++; MicroSecondsPerQuarterNote = (MicroSecondsPerQuarterNote | TrackBytes[ByteIndex]); if (OpenedEvents[0] == null) { } else { Array.Resize(ref OpenedEvents, OpenedEvents.Length + 1); } OpenedEvents[NextEventIndex] = new TempoMidiEvent(Delta, MicroSecondsPerQuarterNote); NextEventIndex++; } //if its an instrument change event else if (NextByteValue == 0xC0) { MidiChannel = Convert.ToSByte(0x0f & NextByteValue << 4); ByteIndex++; NextByteValue = TrackBytes[ByteIndex]; InstrumentNumber = NextByteValue; if (OpenedEvents[0] == null) { //Do Nothing. Opened events are empty and the first element is free } else //Resize the array for the extra event { Array.Resize(ref OpenedEvents, OpenedEvents.Length + 1); } OpenedEvents[NextEventIndex] = new InstrumentMidiEvent(Delta, 0, MidiChannel, InstrumentNumber); NextEventIndex++; } //Other Midi Event else { EventType = Convert.ToSByte(NextByteValue >> 4); //No ByteIndex++ because EventType& MidiChannel are stored in same byte MidiChannel = Convert.ToSByte(NextByteValue & 0xf); ByteIndex++; NextByteValue = TrackBytes[ByteIndex]; Param1 = NextByteValue; ByteIndex++; NextByteValue = TrackBytes[ByteIndex]; Param2 = NextByteValue; if (OpenedEvents[0] == null) { } else { Array.Resize(ref OpenedEvents, OpenedEvents.Length + 1); } OpenedEvents[NextEventIndex] = new MidiEvent(0, 0, Delta, EventType, MidiChannel, Param1, Param2); NextEventIndex++; } } CalculateScorePositionFromDeltaTimes(OpenedEvents, MidiHeaderChunk.Ticks); CalculateNoteDownLengths(OpenedEvents); MidiTrackChunk = new TrackChunk(OpenedEvents); }
//Remove Instrument/Tempo/Midi Event from CurrentMidi Object public void DeleteEvent(MidiEvent[] CurrentMidiEvents, MouseEventArgs e) { switch (e.Button) { case MouseButtons.Left: for (int EventIndex = 0; EventIndex < CurrentMidiEvents.Length; EventIndex++) { #region Search for Note to Delete if ((CurrentMidiEvents[EventIndex].Type == NOTE_DOWN && CurrentMidiEvents[EventIndex].Paramater1 == 127 - CurrentCellYPosition) && (CurrentCellXPosition >= CurrentMidiEvents[EventIndex].CellPosition && CurrentCellXPosition < CurrentMidiEvents[EventIndex].CellPosition + CurrentMidiEvents[EventIndex].Length)) //if the current Cell is within the bounds of a note { for (int NoteUpIndex = EventIndex + 1; NoteUpIndex < (CurrentMidiEvents.Length); NoteUpIndex++) { if (CurrentMidiEvents[NoteUpIndex].Type == 0x08 && (CurrentMidiEvents[NoteUpIndex].Paramater1 == CurrentMidiEvents[EventIndex].Paramater1)) { for (int i = NoteUpIndex; i < CurrentMidiEvents.Length - 1; i++) { CurrentMidiEvents[i] = CurrentMidiEvents[i + 1]; } for (int i = EventIndex; i < CurrentMidiEvents.Length - 2; i++) { CurrentMidiEvents[i] = CurrentMidiEvents[i + 1]; } if (CurrentMidiEvents.Length == 2) { Array.Resize(ref CurrentMidiEvents, 0); } else { Array.Resize(ref CurrentMidiEvents, CurrentMidiEvents.Length - 2); } //finish EventIndex = CurrentMidiEvents.Length; break; } } } if (EventIndex == CurrentMidiEvents.Length) { break; } #endregion #region Search Instrument Event if (CurrentMidiEvents[EventIndex] is InstrumentMidiEvent && EventIndex != CurrentMidiEvents.Length) //if the current Cell is within the bounds of a note { InstrumentMidiEvent CurrentInstrumentEvent = (InstrumentMidiEvent)CurrentMidiEvents[EventIndex]; if (CurrentInstrumentEvent.CellPosition == CurrentCellXPosition) { for (int i = EventIndex; i < CurrentMidiEvents.Length - 1; i++) { CurrentMidiEvents[i] = CurrentMidiEvents[i + 1]; } if (CurrentMidiEvents.Length == 1) { Array.Resize(ref CurrentMidiEvents, 0); } else { Array.Resize(ref CurrentMidiEvents, CurrentMidiEvents.Length - 1); } //finish EventIndex = CurrentMidiEvents.Length; break; } } if (EventIndex == CurrentMidiEvents.Length) { break; } #endregion } //Update the Track Events CurrentMidiObject.Track.Events = CurrentMidiEvents; break; case MouseButtons.Right: for (int EventIndex = 0; EventIndex < CurrentMidiEvents.Length; EventIndex++) { #region Search tempo event if (CurrentMidiEvents[EventIndex] is TempoMidiEvent && EventIndex != CurrentMidiEvents.Length) //if the current Cell is within the bounds of a note { TempoMidiEvent CurrentTempoEvent = (TempoMidiEvent)CurrentMidiEvents[EventIndex]; if (CurrentTempoEvent.CellPosition == CurrentCellXPosition) { for (int i = EventIndex; i < CurrentMidiEvents.Length - 1; i++) { CurrentMidiEvents[i] = CurrentMidiEvents[i + 1]; } if (CurrentMidiEvents.Length == 1) { Array.Resize(ref CurrentMidiEvents, 0); } else { Array.Resize(ref CurrentMidiEvents, CurrentMidiEvents.Length - 1); } //finish EventIndex = CurrentMidiEvents.Length; break; } } if (EventIndex == CurrentMidiEvents.Length) { break; } #endregion } //Update the Track Events CurrentMidiObject.Track.Events = CurrentMidiEvents; break; default: break; } }