/// <summary> /// Stretches or compresses the MIDI sequence events /// </summary> /// <remarks>If <paramref name="adjustTempo"/> is false this will change the playback speed of the MIDI</remarks> /// <param name="diff">The differential for the size. 1 is the same length, .5 would be half the length and 2 would be twice the length</param> /// <param name="adjustTempo">Indicates whether or not the tempo should be adjusted to compensate</param> /// <returns>A new MIDI sequence that is stretched the specified amount</returns> public MidiSequence Stretch(double diff, bool adjustTempo = false) { var result = new MidiSequence(); if (!adjustTempo) { foreach (var e in Events) { result.Events.Add(new MidiEvent((int)Math.Round(e.Position * diff, MidpointRounding.AwayFromZero), e.Message)); } } else { byte runningStatus = 0; foreach (var e in Events) { if (0 != e.Message.Status) { runningStatus = e.Message.Status; } var m = e.Message; if (-1 == m.PayloadLength) { if (0xFF == runningStatus) { var mbs = m as MidiMessageMeta; if (0x51 == mbs.Data1) { var mt = 0; if (BitConverter.IsLittleEndian) { mt = (mbs.Data[0] << 16) | (mbs.Data[1] << 8) | mbs.Data[2]; } else { mt = (mbs.Data[2] << 16) | (mbs.Data[1] << 8) | mbs.Data[0]; } mt = (int)Math.Round(mt / diff, MidpointRounding.AwayFromZero); var buf = new byte[3]; if (BitConverter.IsLittleEndian) { buf[0] = unchecked ((byte)((mt >> 16) & 0xFF)); buf[1] = unchecked ((byte)((mt >> 8) & 0xFF)); buf[2] = unchecked ((byte)((mt) & 0xFF)); } else { buf[0] = unchecked ((byte)((mt) & 0xFF)); buf[1] = unchecked ((byte)((mt >> 8) & 0xFF)); buf[2] = unchecked ((byte)((mt >> 16) & 0xFF)); } m = new MidiMessageMeta(mbs.Status, mbs.Data1, buf); } } } result.Events.Add(new MidiEvent((int)Math.Round(e.Position * diff, MidpointRounding.AwayFromZero), m)); } } return(result); }
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); }