/// <summary> /// Create a Sysex event /// </summary> /// <param name="data">a String that represents the data for the event.</param> /// <param name="tick">the position of the event in the sequence</param> /// <returns>the created Midi Sysex event</returns> public static MidiEvent CreateSysexEvent(string data, long tick) { var bytes = MidiHelper.StringToByteArray(data, ","); if (bytes.Length == 0) { throw new InvalidProgramException(string.Format("Could not parse the passed sysex event {0}", data)); } var sysexMessage = new SysexMessage(); sysexMessage.SetMessage(bytes, bytes.Length); // use base method to set the whole sysex message in one go var ev = new MidiEvent(sysexMessage, tick); return(ev); }
/// <summary> /// Get the MIDI Sequence found in this input stream. /// <see cref="gnu.sound.midi.spi.MidiFileReader#GetSequence(Stream)"/> /// </summary> public override Sequence GetSequence(Stream stream) { // Good midi spec: // http://www.somascape.org/midi/tech/mfile.html // http://www.ccarh.org/courses/253/handout/smf/ var din = new MidiDataInputStream(stream); var mff = (ExtendedMidiFileFormat)GetMidiFileFormat(din.BaseStream); var seq = new Sequence(mff.DivisionType, mff.Resolution, 0, mff.MidiFileType); int ntracks = mff.NumberOfTracks; while (ntracks-- > 0) { Track track = seq.CreateTrack(); int Mtrk = din.ReadInt32(); if (Mtrk != 0x4D54726B) // "MTrk" { throw new InvalidMidiDataException("Invalid MIDI track header."); } int length = din.ReadInt32(); int runningStatus = -1; int click = 0; // Set this to true when we've hit an End of Track meta event. bool done = false; // Read all events. while (!done) { MidiMessage mm; int deltaTime = din.ReadVariableLengthInt(); click += deltaTime; // in Java bytes are signed (-128, +127) // where in C# it's not (0, 255). int statusByte = din.ReadByte(); if (statusByte < (int)MidiHelper.MidiEventType.SystemExclusive) { ShortMessage shortMessage; switch (statusByte & 0xF0) { case (int)MidiHelper.MidiEventType.NoteOff: case (int)MidiHelper.MidiEventType.NoteOn: case (int)MidiHelper.MidiEventType.AfterTouchPoly: case (int)MidiHelper.MidiEventType.ControlChange: case (int)MidiHelper.MidiEventType.PitchBend: case (int)MidiHelper.MidiEventType.SongPosition: shortMessage = new ShortMessage(); shortMessage.SetMessage(statusByte, din.ReadByte(), din.ReadByte()); runningStatus = statusByte; break; case (int)MidiHelper.MidiEventType.ProgramChange: case (int)MidiHelper.MidiEventType.AfterTouchChannel: case (int)MidiHelper.MidiEventType.SongSelect: case (int)MidiHelper.MidiEventType.BusSelect: shortMessage = new ShortMessage(); shortMessage.SetMessage(statusByte, din.ReadByte(), 0); runningStatus = statusByte; break; case (int)MidiHelper.MidiEventType.TuneRequest: case (int)MidiHelper.MidiEventType.EndOfExclusive: case (int)MidiHelper.MidiEventType.Clock: case (int)MidiHelper.MidiEventType.Start: case (int)MidiHelper.MidiEventType.Continue: case (int)MidiHelper.MidiEventType.Stop: case (int)MidiHelper.MidiEventType.ActiveSensing: case (int)MidiHelper.MidiEventType.SystemReset: shortMessage = new ShortMessage(); shortMessage.SetMessage(statusByte, 0, 0); runningStatus = statusByte; break; default: if (runningStatus != -1) { switch (runningStatus & 0xF0) { case (int)MidiHelper.MidiEventType.NoteOff: case (int)MidiHelper.MidiEventType.NoteOn: case (int)MidiHelper.MidiEventType.AfterTouchPoly: case (int)MidiHelper.MidiEventType.ControlChange: case (int)MidiHelper.MidiEventType.PitchBend: case (int)MidiHelper.MidiEventType.SongPosition: shortMessage = new ShortMessage(); shortMessage.SetMessage(runningStatus, statusByte, din.ReadByte()); break; case (int)MidiHelper.MidiEventType.ProgramChange: case (int)MidiHelper.MidiEventType.AfterTouchChannel: case (int)MidiHelper.MidiEventType.SongSelect: case (int)MidiHelper.MidiEventType.BusSelect: shortMessage = new ShortMessage(); shortMessage.SetMessage(runningStatus, statusByte, 0); continue; case (int)MidiHelper.MidiEventType.TuneRequest: case (int)MidiHelper.MidiEventType.EndOfExclusive: case (int)MidiHelper.MidiEventType.Clock: case (int)MidiHelper.MidiEventType.Start: case (int)MidiHelper.MidiEventType.Continue: case (int)MidiHelper.MidiEventType.Stop: case (int)MidiHelper.MidiEventType.ActiveSensing: case (int)MidiHelper.MidiEventType.SystemReset: shortMessage = new ShortMessage(); shortMessage.SetMessage(runningStatus, 0, 0); continue; default: throw new InvalidMidiDataException("Invalid Short MIDI Event: " + statusByte); } } else { throw new InvalidMidiDataException("Invalid Short MIDI Event: " + statusByte); } break; } mm = shortMessage; } else if (statusByte == (int)MidiHelper.MidiEventType.SystemExclusive || statusByte == (int)MidiHelper.MidiEventType.EndOfExclusive) { // System Exclusive event int sysexLength = din.ReadVariableLengthInt(); var sysexData = din.ReadBytes(sysexLength); var sysexMessage = new SysexMessage(); sysexMessage.SetMessage(statusByte, sysexData, sysexLength); mm = sysexMessage; runningStatus = -1; } else if (statusByte == (int)MidiHelper.META) { // Meta Message byte metaType = din.ReadByte(); int metaLength = din.ReadVariableLengthInt(); var metaData = din.ReadBytes(metaLength); var metaMessage = new MetaMessage(); metaMessage.SetMessage(metaType, metaData, metaLength); mm = metaMessage; // End of Track if (metaType == (byte)MidiHelper.MetaEventType.EndOfTrack) { done = true; } runningStatus = -1; } else { throw new InvalidMidiDataException("Invalid status byte: " + statusByte); } track.Add(new MidiEvent(mm, click)); } } return(seq); }