protected virtual void OnEvent(SmfEvent m) { if (EventReceived != null) { EventReceived(m); } }
SmfMessage ReadMessage(int deltaTime) { byte b = PeekByte(); running_status = b < 0x80 ? running_status : ReadByte(); int len; switch (running_status) { case SmfEvent.SysEx1: case SmfEvent.SysEx2: case SmfEvent.Meta: byte metaType = running_status == SmfEvent.Meta ? ReadByte() : (byte)0; len = ReadVariableLength(); byte [] args = new byte [len]; if (len > 0) { ReadBytes(args); } return(new SmfMessage(deltaTime, new SmfEvent(running_status, metaType, 0, args))); default: int value = running_status; value += ReadByte() << 8; if (SmfEvent.FixedDataSize(running_status) == 2) { value += ReadByte() << 16; } return(new SmfMessage(deltaTime, new SmfEvent(value))); } }
public virtual void ProcessEvent(SmfEvent evt) { switch (evt.EventType) { case SmfEvent.NoteOn: Channels [evt.Channel].NoteVelocity [evt.Msb] = evt.Lsb; break; case SmfEvent.NoteOff: Channels [evt.Channel].NoteVelocity [evt.Msb] = 0; break; case SmfEvent.PAf: Channels [evt.Channel].PAfVelocity [evt.Msb] = evt.Lsb; break; case SmfEvent.CC: // FIXME: handle RPNs and NRPNs by DTE switch (evt.Msb) { case SmfCC.NrpnMsb: case SmfCC.NrpnLsb: Channels [evt.Channel].DteTarget = DteTarget.Nrpn; break; case SmfCC.RpnMsb: case SmfCC.RpnLsb: Channels [evt.Channel].DteTarget = DteTarget.Rpn; break; case SmfCC.DteMsb: Channels [evt.Channel].ProcessDte (evt.Lsb, true); break; case SmfCC.DteLsb: Channels [evt.Channel].ProcessDte (evt.Lsb, false); break; case SmfCC.DteIncrement: Channels [evt.Channel].ProcessDteIncrement (); break; case SmfCC.DteDecrement: Channels [evt.Channel].ProcessDteDecrement (); break; } Channels [evt.Channel].Controls [evt.Msb] = evt.Lsb; break; case SmfEvent.Program: Channels [evt.Channel].Program = evt.Msb; break; case SmfEvent.CAf: Channels [evt.Channel].CAf = evt.Msb; break; case SmfEvent.Pitch: Channels [evt.Channel].PitchBend = (short) ((evt.Msb << 7) + evt.Lsb); break; } if (EventReceived != null) EventReceived (evt); }
public MidiPlayer(SmfMusic music, IMidiOutput output, IMidiTimeManager timeManager) { if (music == null) { throw new ArgumentNullException("music"); } if (output == null) { throw new ArgumentNullException("output"); } if (timeManager == null) { throw new ArgumentNullException("timeManager"); } this.output = output; player = new MidiSyncPlayer(music, timeManager); EventReceived += (m) => { switch (m.EventType) { case SmfEvent.SysEx1: case SmfEvent.SysEx2: if (buffer.Length <= m.Data.Length) { buffer = new byte [buffer.Length * 2]; } buffer [0] = m.StatusByte; Array.Copy(m.Data, 0, buffer, 1, m.Data.Length); output.SendAsync(buffer, 0, m.Data.Length + 1, 0); break; case SmfEvent.Meta: // do nothing. break; default: var size = SmfEvent.FixedDataSize(m.StatusByte); buffer [0] = m.StatusByte; buffer [1] = m.Msb; buffer [2] = m.Lsb; output.SendAsync(buffer, 0, size + 1, 0); break; } }; }
public void WriteTrack(SmfTrack track) { stream.Write(Encoding.UTF8.GetBytes("MTrk"), 0, 4); WriteInt(GetTrackDataSize(track)); byte running_status = 0; foreach (SmfMessage e in track.Messages) { Write7BitVariableInteger(e.DeltaTime); switch (e.Event.EventType) { case SmfEvent.Meta: meta_event_writer(false, e, stream); break; case SmfEvent.SysEx1: case SmfEvent.SysEx2: stream.WriteByte(e.Event.EventType); Write7BitVariableInteger(e.Event.Data.Length); stream.Write(e.Event.Data, 0, e.Event.Data.Length); break; default: if (DisableRunningStatus || e.Event.StatusByte != running_status) { stream.WriteByte(e.Event.StatusByte); } int len = SmfEvent.FixedDataSize(e.Event.EventType); stream.WriteByte(e.Event.Msb); if (len > 1) { stream.WriteByte(e.Event.Lsb); } if (len > 2) { throw new Exception("Unexpected data size: " + len); } break; } running_status = e.Event.StatusByte; } }
SmfTrack GenerateTrack(MmlResolvedTrack source) { var rtrk = new SmfTrack (); int cur = 0; foreach (var ev in source.Events) { SmfEvent evt; if (ev.Arguments.Count == 3) evt = new SmfEvent (ev.Arguments [0], ev.Arguments [1], ev.Arguments [2], null); else if (ev.Arguments [0] == 0xFF) evt = new SmfEvent (ev.Arguments [0], ev.Arguments [1], 0, ev.Arguments.Skip (2).ToArray ()); else evt = new SmfEvent (ev.Arguments [0], 0, 0, ev.Arguments.Skip (1).ToArray ()); var msg = new SmfMessage (ev.Tick - cur, evt); rtrk.Messages.Add (msg); cur = ev.Tick; } rtrk.Messages.Add (new SmfMessage (0, new SmfEvent (0xFF, 0x2F, 0, new byte [0]))); return rtrk; }
int GetTrackDataSize(SmfTrack track) { int size = 0; byte running_status = 0; foreach (SmfMessage e in track.Messages) { // delta time size += GetVariantLength(e.DeltaTime); // arguments switch (e.Event.EventType) { case SmfEvent.Meta: size += meta_event_writer(true, e, null); break; case SmfEvent.SysEx1: case SmfEvent.SysEx2: size++; size += GetVariantLength(e.Event.Data.Length); size += e.Event.Data.Length; break; default: // message type & channel if (DisableRunningStatus || running_status != e.Event.StatusByte) { size++; } size += SmfEvent.FixedDataSize(e.Event.EventType); break; } running_status = e.Event.StatusByte; } return(size); }
public SmfMessage(int deltaTime, SmfEvent evt) { DeltaTime = deltaTime; Event = evt; }
public void AddEvent(int deltaInsertAt, SmfEvent e) { e = new SmfEvent (deltaInsertAt - TotalDeltaTime, e.Message); Track.Events.Add (e); TotalDeltaTime = deltaInsertAt; }
// Override it to customize track dispatcher. It would be // useful to split note messages out from non-note ones, // to ease data reading. public virtual int GetTrackID(SmfEvent e) { switch (e.Message.MessageType) { case SmfMessage.Meta: case SmfMessage.SysEx1: case SmfMessage.SysEx2: return -1; default: return e.Message.Channel; } }
// FIXME: it should rather be implemented to iterate all // tracks with index to events, pick the track which contains // the nearest event and push the events into the merged queue. // It's simpler, and costs less by removing sort operation // over thousands of events. SmfMusic GetMergedEvents() { IList<SmfEvent> l = new List<SmfEvent> (); foreach (var track in source.Tracks) { int delta = 0; foreach (var mev in track.Events) { delta += mev.DeltaTime; l.Add (new SmfEvent (delta, mev.Message)); } } if (l.Count == 0) return new SmfMusic () { DeltaTimeSpec = source.DeltaTimeSpec }; // empty (why did you need to sort your song file?) // Sort() does not always work as expected. // For example, it does not always preserve event // orders on the same channels when the delta time // of event B after event A is 0. It could be sorted // either as A->B or B->A. // // To resolve this ieeue, we have to sort "chunk" // of events, not all single events themselves, so // that order of events in the same chunk is preserved // i.e. [AB] at 48 and [CDE] at 0 should be sorted as // [CDE] [AB]. var idxl = new List<int> (l.Count); idxl.Add (0); int prev = 0; for (int i = 0; i < l.Count; i++) { if (l [i].DeltaTime != prev) { idxl.Add (i); prev = l [i].DeltaTime; } } idxl.Sort (delegate (int i1, int i2) { return l [i1].DeltaTime - l [i2].DeltaTime; }); // now build a new event list based on the sorted blocks. var l2 = new List<SmfEvent> (l.Count); int idx; for (int i = 0; i < idxl.Count; i++) for (idx = idxl [i], prev = l [idx].DeltaTime; idx < l.Count && l [idx].DeltaTime == prev; idx++) l2.Add (l [idx]); //if (l.Count != l2.Count) throw new Exception (String.Format ("Internal eror: count mismatch: l1 {0} l2 {1}", l.Count, l2.Count)); l = l2; // now events should be sorted correctly. var waitToNext = l [0].DeltaTime; for (int i = 0; i < l.Count - 1; i++) { if (l [i].Message.Value != 0) { // if non-dummy var tmp = l [i + 1].DeltaTime - l [i].DeltaTime; l [i] = new SmfEvent (waitToNext, l [i].Message); waitToNext = tmp; } } l [l.Count - 1] = new SmfEvent (waitToNext, l [l.Count - 1].Message); var m = new SmfMusic (); m.DeltaTimeSpec = source.DeltaTimeSpec; m.Format = 0; m.Tracks.Add (new SmfTrack (l)); return m; }
public void AddEvent(SmfEvent evt) { events.Add (evt); }
public virtual void HandleEvent(SmfEvent e) { if (e.DeltaTime != 0) { var ms = GetDeltaTimeInMilliseconds (e.DeltaTime); Thread.Sleep (ms); } if (e.Message.StatusByte == 0xFF && e.Message.Msb == SmfMetaType.Tempo) current_tempo = SmfMetaType.GetTempo (e.Message.Data); OnMessage (e.Message); PlayDeltaTime += e.DeltaTime; }
public virtual void ProcessEvent(SmfEvent evt) { switch (evt.EventType) { case SmfEvent.NoteOn: Channels [evt.Channel].NoteVelocity [evt.Msb] = evt.Lsb; break; case SmfEvent.NoteOff: Channels [evt.Channel].NoteVelocity [evt.Msb] = 0; break; case SmfEvent.PAf: Channels [evt.Channel].PAfVelocity [evt.Msb] = evt.Lsb; break; case SmfEvent.CC: // FIXME: handle RPNs and NRPNs by DTE switch (evt.Msb) { case SmfCC.NrpnMsb: case SmfCC.NrpnLsb: Channels [evt.Channel].DteTarget = DteTarget.Nrpn; break; case SmfCC.RpnMsb: case SmfCC.RpnLsb: Channels [evt.Channel].DteTarget = DteTarget.Rpn; break; case SmfCC.DteMsb: Channels [evt.Channel].ProcessDte(evt.Lsb, true); break; case SmfCC.DteLsb: Channels [evt.Channel].ProcessDte(evt.Lsb, false); break; case SmfCC.DteIncrement: Channels [evt.Channel].ProcessDteIncrement(); break; case SmfCC.DteDecrement: Channels [evt.Channel].ProcessDteDecrement(); break; } Channels [evt.Channel].Controls [evt.Msb] = evt.Lsb; break; case SmfEvent.Program: Channels [evt.Channel].Program = evt.Msb; break; case SmfEvent.CAf: Channels [evt.Channel].CAf = evt.Msb; break; case SmfEvent.Pitch: Channels [evt.Channel].PitchBend = (short)((evt.Msb << 7) + evt.Lsb); break; } if (EventReceived != null) { EventReceived(evt); } }
protected virtual void OnEvent(SmfEvent m) { if (EventReceived != null) EventReceived (m); }