private void MidiOutComboBox_SelectedIndexChanged(object sender, EventArgs e) { if (null != _outputStream && _outputStream.IsOpen) { _outputStream.Close(); _outputStream = null; } _outputStream = MidiOutComboBox.SelectedItem as MidiStream; }
private void PreviewButton_Click(object sender, EventArgs e) { if ("Stop" == PreviewButton.Text) { if (null != _play) { _play.Close(); } MidiFileBox.Enabled = true; BrowseButton.Enabled = true; OutputComboBox.Enabled = true; PreviewButton.Text = "Preview"; return; } if (null != _play) { _play.Close(); } MidiFileBox.Enabled = false; BrowseButton.Enabled = false; OutputComboBox.Enabled = false; PreviewButton.Text = "Stop"; if (_dirty) { _processedFile = _ProcessFile(); } var mf = _processedFile; _play = (OutputComboBox.SelectedItem as MidiOutputDevice).Stream; var stm = _play; // we use 100 events, which should be safe and allow // for some measure of SYSEX messages in the stream // without bypassing the 64kb limit const int MAX_EVENT_COUNT = 100; const int RATE_TICKS = 500; // our current cursor pos var pos = 0; // for tracking deltas var ofs = 0; // for tracking the song position var songPos = 0; // merge our file for playback var seq = MidiSequence.Merge(mf.Tracks); var events = seq.Events; // the number of events in the seq var len = events.Count; // stores the next set of events var eventList = new List <MidiEvent>(MAX_EVENT_COUNT); // open the stream stm.Open(); // start it stm.Start(); // first set the timebase stm.TimeBase = mf.TimeBase; // set up our send complete handler stm.SendComplete += delegate(object s, EventArgs ea) { try { BeginInvoke(new Action(delegate() { // clear the list eventList.Clear(); mf = _processedFile; if (_dirty) { if (_reseekDirty) { var time = _processedFile.Tracks[0].GetContext(songPos, _processedFile.TimeBase).Time; _processedFile = _ProcessFile(); songPos = _processedFile.Tracks[0].GetPositionAtTime(time, _processedFile.TimeBase); mf = _processedFile; seq = MidiSequence.Merge(mf.Tracks); events = new List <MidiEvent>(seq.GetNextEventsAtPosition(songPos, true)); len = events.Count; pos = 0; } else { _processedFile = _ProcessFile(); mf = _processedFile; seq = MidiSequence.Merge(mf.Tracks); events = seq.Events; } Visualizer.Sequence = seq; Visualizer.Width = Math.Max(VisualizerPanel.Width, Visualizer.Sequence.Length / 4); } ofs = 0; len = events.Count; // iterate through the next events var next = pos + MAX_EVENT_COUNT; for (; pos < next && ofs <= RATE_TICKS; ++pos) { // if it's past the end, loop it if (len <= pos) { pos = 0; songPos = 0; events = seq.Events; break; } var ev = events[pos]; ofs += ev.Position; songPos += pos; if (ev.Position < RATE_TICKS && RATE_TICKS < ofs) { break; } // otherwise add the next event eventList.Add(ev); } // send the list of events if (MidiStreamState.Closed != stm.State && 0 != eventList.Count) { stm.SendDirect(eventList); } })); } catch { } }; // add the first events for (pos = 0; pos < MAX_EVENT_COUNT && ofs <= RATE_TICKS; ++pos) { // if it's past the end, loop it if (len <= pos) { pos = 0; songPos = 0; events = seq.Events; break; } var ev = events[pos]; ofs += ev.Position; if (ev.Position < RATE_TICKS && RATE_TICKS < ofs) { break; } // otherwise add the next event eventList.Add(ev); } // send the list of events if (0 != eventList.Count) { stm.SendDirect(eventList); } }
private void PlayButton_Click(object sender, EventArgs e) { // we use 100 events, which should be safe and allow // for some measure of SYSEX messages in the stream // without bypassing the 64kb limit const int MAX_EVENT_COUNT = 100; const int RATE_TICKS = 500; if ("Stop" == PlayButton.Text) { if (null != _play) // sanity check { _play.Close(); } PlayButton.Text = "Play"; PatternComboBox.Enabled = true; BarsUpDown.Enabled = true; OutputComboBox.Enabled = true; return; } PatternComboBox.Enabled = false; BarsUpDown.Enabled = false; OutputComboBox.Enabled = false; PlayButton.Text = "Stop"; _play = (OutputComboBox.SelectedItem as MidiOutputDevice).Stream; var mf = _CreateMidiFile(); var stm = _play; // our current cursor pos int pos = 0; // for tracking deltas var ofs = 0; // merge our file for playback var seq = MidiSequence.Merge(mf.Tracks); // the number of events in the seq int len = seq.Events.Count; // stores the next set of events var eventList = new List <MidiEvent>(MAX_EVENT_COUNT); // open the stream stm.Open(); // start it stm.Start(); // first set the timebase stm.TimeBase = mf.TimeBase; // set up our send complete handler stm.SendComplete += delegate(object s, EventArgs ea) { try { BeginInvoke(new Action(delegate() { // clear the list eventList.Clear(); mf = _CreateMidiFile(); seq = MidiSequence.Merge(mf.Tracks); ofs = 0; len = seq.Events.Count; // iterate through the next events var next = pos + MAX_EVENT_COUNT; for (; pos < next && ofs <= RATE_TICKS; ++pos) { // if it's past the end, loop it if (len <= pos) { pos = 0; break; } var ev = seq.Events[pos]; ofs += ev.Position; if (ev.Position < RATE_TICKS && RATE_TICKS < ofs) { break; } // otherwise add the next event eventList.Add(ev); } // send the list of events if (MidiStreamState.Closed != stm.State) { stm.SendDirect(eventList); } })); } catch { } }; // add the first events for (pos = 0; pos < MAX_EVENT_COUNT && ofs <= RATE_TICKS; ++pos) { // if it's past the end, loop it if (len <= pos) { pos = 0; break; } var ev = seq.Events[pos]; ofs += ev.Position; if (ev.Position < RATE_TICKS && RATE_TICKS < ofs) { break; } // otherwise add the next event eventList.Add(ev); } // send the list of events stm.SendDirect(eventList); }
private void PlayButton_Click(object sender, EventArgs e) { if ("Stop" == PlayButton.Text) { PlayButton.Text = "Play"; if (null != _outputStream) { _outputStream.Close(); } MidiOutComboBox.Enabled = true; FileTextBox.Enabled = true; FileBrowseButton.Enabled = true; Visualizer.ShowCursor = false; return; } PlayButton.Text = "Stop"; Visualizer.CursorPosition = 0; Visualizer.ShowCursor = true; MidiOutComboBox.Enabled = false; FileTextBox.Enabled = false; FileBrowseButton.Enabled = false; var mf = MidiFile.ReadFrom(FileTextBox.Text); if (null != _outputStream) { // BUG: For some reason recycling the output stream // screws up playback on successive uses. I have had // no luck tracking down why so far. The following // causes the MidiStream class to be recreated // instead of recycled var stm = _outputStream = MidiDevice.Streams[_outputStream.Index]; // we use 100 events, which should be safe and allow // for some measure of SYSEX messages in the stream // without bypassing the 64kb limit const int MAX_EVENT_COUNT = 100; // the lower this is, the more more CPU it takes. // the higher it is, the less accurate the cursor // position will be: const int RATE_TICKS = 10; // our current cursor pos var pos = 0; // for tracking deltas var ofs = 0; // for tracking the song position var songPos = 0; var songTicks = 0; // merge our file for playback var seq = MidiSequence.Merge(mf.Tracks); var events = seq.Events; // the number of events in the seq var len = events.Count; // stores the next set of events var eventList = new List <MidiEvent>(MAX_EVENT_COUNT); // open the stream stm.Open(); if (MidiOutputDeviceVolumeSupport.None != stm.VolumeSupport) { stm.Volume = new MidiVolume((byte)VolumeKnob.Value, (byte)VolumeKnob.Value); } // start it stm.Start(); // first set the timebase stm.TimeBase = mf.TimeBase; // set up our send complete handler stm.SendComplete += delegate(object s, EventArgs ea) { try { BeginInvoke(new Action(delegate() { // clear the list eventList.Clear(); ofs = 0; len = events.Count; // iterate through the next events var next = pos + MAX_EVENT_COUNT; for (; pos < next && ofs <= RATE_TICKS; ++pos) { // if it's past the end, loop it if (len <= pos) { pos = 0; songPos = 0; songTicks = 0; events = seq.Events; break; } var ev = events[pos]; ofs += ev.Position; songTicks += ev.Position; songPos += pos; if (ev.Position < RATE_TICKS && RATE_TICKS < ofs) { break; } // otherwise add the next event eventList.Add(ev); } // send the list of events if (MidiStreamState.Closed != stm.State && 0 != eventList.Count) { stm.SendDirect(eventList); } Visualizer.CursorPosition = songTicks; })); } catch { } }; // add the first events for (pos = 0; pos < MAX_EVENT_COUNT && ofs <= RATE_TICKS; ++pos) { // if it's past the end, loop it if (len <= pos) { pos = 0; songPos = 0; songTicks = 0; events = seq.Events; break; } var ev = events[pos]; ofs += ev.Position; songTicks += ev.Position; if (ev.Position < RATE_TICKS && RATE_TICKS < ofs) { break; } // otherwise add the next event eventList.Add(ev); } Visualizer.CursorPosition = songTicks; // send the list of events if (0 != eventList.Count) { stm.SendDirect(eventList); } } }
public PrintInstrument(MidiStream stream) { Stream = stream; }