internal MidiInputDevice(int deviceIndex) { if (0 > deviceIndex) { throw new ArgumentOutOfRangeException("deviceIndex"); } _handle = IntPtr.Zero; _callback = new MidiInProc(_MidiInProc); _index = deviceIndex; _state = MidiInputDeviceState.Closed; _recordingLastTimestamp = 0L; _recordingPos = 0; _recordingTrack0 = null; _recordingSequence = null; _microTempo = 500000; // 120BPM _timeBase = 96; _timingTimestamp = 0L; _tempoSynchMininumTempo = 50d; _tempoSynchEnabled = 0; // false _tempoSyncFrequency = 0L; _tempoSyncTimestamp = 0L; _CheckInResult(midiInGetDevCaps(deviceIndex, ref _caps, Marshal.SizeOf(typeof(MIDIINCAPS)))); }
/// <summary> /// Reads a MIDI file from the specified stream /// </summary> /// <param name="stream">The stream to read from</param> /// <returns>A MIDI file object representing the MIDI data in the stream</returns> public static MidiFile ReadFrom(Stream stream) { KeyValuePair <string, byte[]> chunk; if (!_TryReadChunk(stream, out chunk) || "MThd" != chunk.Key || 6 > chunk.Value.Length) { throw new InvalidDataException("The stream is not a MIDI file format."); } var type = BitConverter.ToInt16(chunk.Value, 0); var trackCount = BitConverter.ToInt16(chunk.Value, 2); var timeBase = BitConverter.ToInt16(chunk.Value, 4); if (BitConverter.IsLittleEndian) { type = MidiUtility.Swap(type); trackCount = MidiUtility.Swap(trackCount); timeBase = MidiUtility.Swap(timeBase); } var result = new MidiFile(type, timeBase); var fileStream = stream as FileStream; if (null != fileStream) { result.FilePath = fileStream.Name; } while (_TryReadChunk(stream, out chunk)) { if ("MTrk" == chunk.Key) { var tstm = new MemoryStream(chunk.Value, false); var trk = MidiSequence.ReadFrom(tstm); result.Tracks.Add(trk); } } return(result); }
/// <summary> /// Concatenates this sequence with other MIDI sequences /// </summary> /// <param name="sequences">The sequences to concatenate this sequence with</param> /// <returns>A new MIDI sequence that is the concatenation of this sequence and <paramref name="sequences"/></returns> public static MidiSequence Concat(IEnumerable <MidiSequence> sequences) { var result = new MidiSequence(); var endDelta = 0; var sawEnd = false; foreach (var seq in sequences) { int rs = 0; foreach (var e in seq.Events) { var m = e.Message; if (0 != m.Status) { rs = m.Status; } if (0xFF == rs) { var mbs = m as MidiMessageMeta; if (0x2F == mbs.Data1) { sawEnd = true; endDelta = e.Position; break; } } result.Events.Add(new MidiEvent(e.Position + endDelta, m)); endDelta = 0; } } if (sawEnd) // add an end marker back to the track { result.Events.Add(new MidiEvent(endDelta, new MidiMessageMeta(0xFF, 0x2F, new byte[0]))); } return(result); }
/// <summary> /// Plays the file over the specified device /// </summary> /// <param name="deviceIndex">The index of the device to use</param> /// <param name="loop">Indicates whether to loop playback or not</param> public void Preview(int deviceIndex = 0, bool loop = false) { MidiSequence.Merge(Tracks).Preview(TimeBase, deviceIndex, loop); }
/// <summary> /// Plays the file over the specified device /// </summary> /// <param name="device">The MIDI output device to use</param> /// <param name="loop">Indicates whether to loop playback or not</param> public void Preview(MidiOutputDevice device = null, bool loop = false) { MidiSequence.Merge(Tracks).Preview(TimeBase, device, loop); }
/// <summary> /// Merges this sequence with other MIDI sequences /// </summary> /// <param name="right">The sequence to merge this sequence with</param> /// <returns>A new MIDI sequence that is a merge of this sequence and <paramref name="right"/></returns> public MidiSequence Merge(MidiSequence right) => Merge(this, right);
/// <summary> /// Concatenates this sequence with another MIDI sequence /// </summary> /// <param name="right">The sequence to concatenate this sequence with</param> /// <returns>A new MIDI sequence that is the concatenation of this sequence and <paramref name="right"/></returns> public MidiSequence Concat(MidiSequence right) => Concat(this, right);
internal static MidiSequence ReadFrom(Stream stream) { MidiSequence result = new MidiSequence(); var rs = (byte)0; var delta = _ReadVarlen(stream); if (BitConverter.IsLittleEndian) { delta = _Swap(delta); } var i = stream.ReadByte(); while (-1 != i) { var hasStatus = false; var b = (byte)i; if (0x7F < b) { hasStatus = true; rs = b; i = stream.ReadByte(); if (-1 != i) { b = (byte)i; } else { b = 0; } } var st = hasStatus ? rs : (byte)0; var m = (MidiMessage)null; switch (rs & 0xF0) { case 0x80: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageNoteOff(b, (byte)stream.ReadByte(), unchecked ((byte)(st & 0x0F))); break; case 0x90: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageNoteOn(b, (byte)stream.ReadByte(), unchecked ((byte)(st & 0x0F))); break; case 0xA0: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageKeyPressure(b, (byte)stream.ReadByte(), unchecked ((byte)(st & 0x0F))); break; case 0xB0: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageCC(b, (byte)stream.ReadByte(), unchecked ((byte)(st & 0x0F))); break; case 0xC0: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessagePatchChange(b, unchecked ((byte)(st & 0x0F))); break; case 0xD0: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageChannelPressure(b, unchecked ((byte)(st & 0x0F))); break; case 0xE0: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageChannelPitch(b, (byte)stream.ReadByte(), unchecked ((byte)(st & 0x0F))); break; case 0xF0: switch (rs & 0xF) { case 0xF: if (i == -1) { throw new EndOfStreamException(); } var l = _ReadVarlen(stream); //if (BitConverter.IsLittleEndian) // l = _Swap(l); var ba = new byte[l]; if (l != stream.Read(ba, 0, ba.Length)) { throw new EndOfStreamException(); } m = new MidiMessageMeta(st, b, ba); break; case 0x0: case 0x7: if (i == -1) { throw new EndOfStreamException(); } l = _ReadVarlen(b, stream); //if (BitConverter.IsLittleEndian) // l = _Swap(l); ba = new byte[l]; if (l != stream.Read(ba, 0, ba.Length)) { throw new EndOfStreamException(); } m = new MidiMessageSysex(st, ba); break; case 0x2: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageWord(st, b, (byte)stream.ReadByte()); break; case 0x3: if (i == -1) { throw new EndOfStreamException(); } m = new MidiMessageByte(st, b); break; case 0x6: case 0x8: case 0xA: case 0xB: case 0xC: // status *was* specified if we got here m = new MidiMessage(st); break; default: throw new NotSupportedException("The MIDI message is not recognized."); } break; } result.Events.Add(new MidiEvent(delta, m)); i = _ReadVarlen(stream); if (-1 == i) { break; } delta = i; i = stream.ReadByte(); } return(result); }