void SendMidiMessage(SmfMessage m) { if ((m.Value & 0xFF) == 0xF0) WriteSysEx (0xF0, m.Data); else if ((m.Value & 0xFF) == 0xF7) WriteSysEx (0xF7, m.Data); else if ((m.Value & 0xFF) == 0xFF) return; // meta. Nothing to send. else output.Write (0, new MidiMessage (m.StatusByte, m.Msb, m.Lsb)); }
// 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(SmfMessage e) { switch (e.Event.EventType) { case SmfEvent.Meta: case SmfEvent.SysEx1: case SmfEvent.SysEx2: return(-1); default: return(e.Event.Channel); } }
public virtual void ProcessMessage(SmfMessage msg) { switch (msg.MessageType) { case SmfMessage.NoteOn: Channels [msg.Channel].NoteVelocity [msg.Msb] = msg.Lsb; break; case SmfMessage.NoteOff: Channels [msg.Channel].NoteVelocity [msg.Msb] = 0; break; case SmfMessage.PAf: Channels [msg.Channel].PAfVelocity [msg.Msb] = msg.Lsb; break; case SmfMessage.CC: // FIXME: handle RPNs and NRPNs by DTE switch (msg.Msb) { case SmfCC.NrpnMsb: case SmfCC.NrpnLsb: Channels [msg.Channel].DteTarget = DteTarget.Nrpn; break; case SmfCC.RpnMsb: case SmfCC.RpnLsb: Channels [msg.Channel].DteTarget = DteTarget.Rpn; break; case SmfCC.DteMsb: Channels [msg.Channel].ProcessDte (msg.Lsb, true); break; case SmfCC.DteLsb: Channels [msg.Channel].ProcessDte (msg.Lsb, false); break; case SmfCC.DteIncrement: Channels [msg.Channel].ProcessDteIncrement (); break; case SmfCC.DteDecrement: Channels [msg.Channel].ProcessDteDecrement (); break; } Channels [msg.Channel].Controls [msg.Msb] = msg.Lsb; break; case SmfMessage.Program: Channels [msg.Channel].Program = msg.Msb; break; case SmfMessage.CAf: Channels [msg.Channel].CAf = msg.Msb; break; case SmfMessage.Pitch: Channels [msg.Channel].PitchBend = (short) ((msg.Msb << 7) + msg.Lsb); break; } if (MessageReceived != null) MessageReceived (msg); }
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; }
public virtual void HandleEvent(SmfMessage m) { if (m.DeltaTime != 0) { var ms = GetDeltaTimeInMilliseconds(m.DeltaTime); time_manager.AdvanceBy(ms); } if (m.Event.StatusByte == 0xFF) { if (m.Event.Msb == SmfMetaType.Tempo) { current_tempo = SmfMetaType.GetTempo(m.Event.Data); } else if (m.Event.Msb == SmfMetaType.TimeSignature && m.Event.Data.Length == 4) { Array.Copy(m.Event.Data, current_time_signature, 4); } } OnEvent(m.Event); PlayDeltaTime += m.DeltaTime; }
// FIXME: it should rather be implemented to iterate all // tracks with index to messages, 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 GetMergedMessages() { IList<SmfMessage> l = new List<SmfMessage> (); foreach (var track in source.Tracks) { int delta = 0; foreach (var mev in track.Messages) { delta += mev.DeltaTime; l.Add (new SmfMessage (delta, mev.Event)); } } 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<SmfMessage> (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 messages should be sorted correctly. var waitToNext = l [0].DeltaTime; for (int i = 0; i < l.Count - 1; i++) { if (l [i].Event.Value != 0) { // if non-dummy var tmp = l [i + 1].DeltaTime - l [i].DeltaTime; l [i] = new SmfMessage (waitToNext, l [i].Event); waitToNext = tmp; } } l [l.Count - 1] = new SmfMessage (waitToNext, l [l.Count - 1].Event); var m = new SmfMusic (); m.DeltaTimeSpec = source.DeltaTimeSpec; m.Format = 0; m.Tracks.Add (new SmfTrack (l)); return m; }
public void AddMessage(SmfMessage msg) { messages.Add (msg); }
void HandleSmfMessage(SmfMessage m) { switch (m.MessageType) { case SmfMessage.NoteOn: if (m.Lsb == 0) goto case SmfMessage.NoteOff; // It is equivalent to note off int note = GetKeyIndexForNote (m.Msb); if (note < 0) break; // out of range key_rectangles [m.Channel, note].Fill = brush_keyon; keyon_meter_panel.ProcessKeyOn (m.Channel, m.Msb, m.Lsb); spectrum_analyzer_panel.ProcessKeyOn (m.Channel, m.Msb, m.Lsb); break; case SmfMessage.NoteOff: note = GetKeyIndexForNote (m.Msb); if (note < 0) break; // out of range Brush c = registers.Channels [m.Channel].Controls [0x40] > 63 ? brush_hold : IsWhiteKey (note) ? brush_white_key : brush_black_key; key_rectangles [m.Channel, note].Fill = c; break; case SmfMessage.Program: keyon_meter_panel.SetProgram (m.Channel, m.Msb); break; case SmfMessage.CC: switch (m.Msb) { case SmfCC.BankSelect: keyon_meter_panel.SetBank (m.Channel, m.Lsb, true); break; case SmfCC.BankSelectLsb: keyon_meter_panel.SetBank (m.Channel, m.Lsb, false); break; case SmfCC.Pan: keyon_meter_panel.SetPan (m.Channel, m.Lsb); break; case SmfCC.Volume: parameter_visualizers [m.Channel].Volume.SetValue (m.Lsb); break; case SmfCC.Expression: parameter_visualizers [m.Channel].Expression.SetValue (m.Lsb); break; case SmfCC.Rsd: parameter_visualizers [m.Channel].Rsd.SetValue (m.Lsb); break; case SmfCC.Csd: parameter_visualizers [m.Channel].Csd.SetValue (m.Lsb); break; case SmfCC.Hold: parameter_visualizers [m.Channel].Hold.Value = (m.Lsb > 63); if (m.Lsb < 64 && key_rectangles != null) { // reset held keys to nothing for (int i = 0; i < 128; i++) { note = GetKeyIndexForNote (i); if (note < 0) continue; var rect = key_rectangles [m.Channel, note]; if (rect == null) continue; if (((SolidColorBrush) rect.Fill).Color == color_hold) key_rectangles [m.Channel, note].Fill = IsWhiteKey (i) ? brush_white_key : brush_black_key; } } break; case SmfCC.PortamentoSwitch: parameter_visualizers [m.Channel].PortamentoSwitch.Value = (m.Lsb > 63); break; case SmfCC.Sostenuto: parameter_visualizers [m.Channel].Sostenuto.Value = (m.Lsb > 63); break; case SmfCC.SoftPedal: parameter_visualizers [m.Channel].SoftPedal.Value = (m.Lsb > 63); break; } break; case SmfMessage.Meta: switch (m.MetaType) { case SmfMetaType.TimeSignature: play_time_status_panel.SetTimeMeterValues (m.Data); break; case SmfMetaType.Tempo: foreach (var view in player_status_views) view.ProcessChangeTempo ((int) ((60.0 / SmfMetaType.GetTempo (m.Data)) * 1000000.0)); break; } break; } }
void DrawNoteOnOff(SmfMessage m) { int note = GetKeyIndexForNote (m.Msb); if (note < 0) return; // out of range int octave = note / 12; int key = note % 12; int channel = m.Channel; bool isKeyOn = m.MessageType == SmfMessage.NoteOn && m.Lsb != 0; float x = octave * key_width * 7; float y = GetChannelYPos (channel) + ch_height - key_height; int k = key_to_keyboard_idx [key]; if (IsWhiteKey (key)) { paint.Color = (isKeyOn ? color_keyon : color_white_key); canvas.DrawCircle(x + k * key_width + 3, y + 12, 2, paint); //keyon_meter_panel.ProcessKeyOn (m.Channel, m.Msb, m.Lsb); //spectrum_analyzer_panel.ProcessKeyOn (m.Channel, m.Msb, m.Lsb); } else { paint.Color = (isKeyOn ? color_keyon : color_black_key); int blackKeyStartX = (int) (x + (k + 0.8) * key_width); canvas.DrawCircle(blackKeyStartX + 2, y + 1 + 5, 1, paint); } needs_redraw = true; }
public SmfEvent(int deltaTime, SmfMessage msg) { DeltaTime = deltaTime; Message = msg; }
protected virtual void OnMessage(SmfMessage m) { if (MessageReceived != null) MessageReceived (m); }
// FIXME: it should rather be implemented to iterate all // tracks with index to messages, 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 GetMergedMessages() { IList <SmfMessage> l = new List <SmfMessage> (); foreach (var track in source.Tracks) { int delta = 0; foreach (var mev in track.Messages) { delta += mev.DeltaTime; l.Add(new SmfMessage(delta, mev.Event)); } } 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 <SmfMessage> (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 messages should be sorted correctly. var waitToNext = l [0].DeltaTime; for (int i = 0; i < l.Count - 1; i++) { if (l [i].Event.Value != 0) // if non-dummy { var tmp = l [i + 1].DeltaTime - l [i].DeltaTime; l [i] = new SmfMessage(waitToNext, l [i].Event); waitToNext = tmp; } } l [l.Count - 1] = new SmfMessage(waitToNext, l [l.Count - 1].Event); var m = new SmfMusic(); m.DeltaTimeSpec = source.DeltaTimeSpec; m.Format = 0; m.Tracks.Add(new SmfTrack(l)); return(m); } }
public void AddMessage(SmfMessage msg) { messages.Add(msg); }
// 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(SmfMessage e) { switch (e.Event.EventType) { case SmfEvent.Meta: case SmfEvent.SysEx1: case SmfEvent.SysEx2: return -1; default: return e.Event.Channel; } }
public void AddMessage(int deltaInsertAt, SmfMessage e) { e = new SmfMessage(deltaInsertAt - TotalDeltaTime, e.Event); Track.Messages.Add(e); TotalDeltaTime = deltaInsertAt; }
public void AddMessage(int deltaInsertAt, SmfMessage e) { e = new SmfMessage (deltaInsertAt - TotalDeltaTime, e.Event); Track.Messages.Add (e); TotalDeltaTime = deltaInsertAt; }
public virtual void HandleEvent(SmfMessage m) { if (m.DeltaTime != 0) { var ms = GetDeltaTimeInMilliseconds (m.DeltaTime); time_manager.AdvanceBy (ms); } if (m.Event.StatusByte == 0xFF) { if (m.Event.Msb == SmfMetaType.Tempo) current_tempo = SmfMetaType.GetTempo (m.Event.Data); else if (m.Event.Msb == SmfMetaType.TimeSignature && m.Event.Data.Length == 4) Array.Copy (m.Event.Data, current_time_signature, 4); } OnEvent (m.Event); PlayDeltaTime += m.DeltaTime; }