using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using Sanford.Multimedia.Midi; using Sanford.Multimedia.Midi.UI; namespace MIDI_Control_Demo { public partial class MIDI_control : Form { // This class helps store info about the note that is playing. private class NoteInfo { public int instr; public int val; public int vol; public int pitch; public int mod; } private OutputDevice outDevice; // Is this always the proper device ID?? private int outDeviceID = 0; private OutputDeviceDialog outDialog; private NoteInfo curNote; private bool midiStarted = false; private bool noteStarted = false; static int VELOCITY = 127; // Local acceleration data: current value private int xac_Scaled; private int yac_Scaled; private int zac_Scaled; // Local accel scaling: min and max recorded values private double xac_min, xac_max; private double yac_min, yac_max; private double zac_min, zac_max; // Signals that this is the first run after a load or MIDI reset private bool firstRunFlag = true; // The little XY plot for testing XY_panel myXYPanel; // public MIDI_control() { InitializeComponent(); myXYPanel = new XY_panel(this); } protected override void OnLoad(EventArgs e) { updateParamDisplay(); base.OnLoad(e); curNote = new NoteInfo(); } private void updateNote(bool forceRestart) { if (!midiStarted) return; if (!noteStarted) { killNote(); curNote = new NoteInfo(); // Reset note info return; } // Build up new note candidate NoteInfo newNote = new NoteInfo(); if(opt_modeMan.Checked) { // All settings manual, no accel control newNote.instr = (int)(instrumentSelect.Value); newNote.val = (int)(noteSelect.Value); newNote.vol = (int)(volumeSelect.Value); newNote.pitch = (int)(pitchBendSelect.Value); newNote.mod = (int)(modSelect.Value); } else if(opt_mode1.Checked) { // X accel controls note value, Y accel controls modulation newNote.instr = (int)(instrumentSelect.Value); // Use WHOLE TONE SCALE for creepy sounds, and rescale for mid-high range notes newNote.val = ((int)((xac_Scaled + 240) / 8)) * 2; newNote.vol = yac_Scaled; newNote.pitch = (int)(pitchBendSelect.Value); newNote.mod = (int)(modSelect.Value); } else if(opt_mode2.Checked) { // X accel controls pitch bend, Y accel controls modulation newNote.instr = (int)(instrumentSelect.Value); newNote.val = (int)(noteSelect.Value); newNote.vol = (int)(volumeSelect.Value); newNote.pitch = xac_Scaled; newNote.mod = yac_Scaled; } else if(opt_mode3.Checked) { // X accel controls pitch bend, Y accel controls volume newNote.instr = (int)(instrumentSelect.Value); newNote.val = (int)(noteSelect.Value); newNote.vol = yac_Scaled; newNote.pitch = xac_Scaled; newNote.mod = (int)(modSelect.Value); } else { // None of the option boxes are checked?! return; } // Keep track; should note be restarted after all channel commands bool restartNote = forceRestart; if (newNote.instr != curNote.instr || forceRestart) { // Change instrument patch (aka program) outDevice.Send(new ChannelMessage(ChannelCommand.ProgramChange, 0, newNote.instr, 0)); restartNote = true; } if (newNote.val != curNote.val) { // Restarting note will update note value restartNote = true; } if (newNote.vol != curNote.vol || forceRestart) { // Change master volume (controller # 0x07) outDevice.Send(new ChannelMessage(ChannelCommand.Controller, 0, 0x07, newNote.vol)); } if (newNote.pitch != curNote.pitch || forceRestart) { // Change pitch wheel setting outDevice.Send(new ChannelMessage(ChannelCommand.PitchWheel, 0, 0, newNote.pitch)); } if (newNote.mod != curNote.mod || forceRestart) { // Change Modulation controller (0x01) setting outDevice.Send(new ChannelMessage(ChannelCommand.Controller, 0, 0x01, newNote.mod)); } // Restart the note based on what was updated... if (restartNote) { outDevice.Send(new ChannelMessage(ChannelCommand.NoteOff, 0, curNote.val, 0)); outDevice.Send(new ChannelMessage(ChannelCommand.NoteOn, 0, newNote.val, VELOCITY)); } curNote = newNote; } private void killNote() { if (!midiStarted) return; outDevice.Send(new ChannelMessage(ChannelCommand.NoteOff, 0, curNote.val, 0)); noteStarted = false; } private void btn_startMIDI_Click(object sender, EventArgs e) { if (midiStarted) { closeMidiOutput(); } else { // Try to open midi out. If successful, initialize other stuff if (!openMidiOutput()) return; updateNote(true); killNote(); firstRunFlag = true; } } private void btn_noteOn_Click(object sender, EventArgs e) { noteStarted = true; updateNote(true); } private void btn_noteOff_Click(object sender, EventArgs e) { killNote(); } public void updateAccelValues(double xac, double yac, double zac) { if (firstRunFlag) { // Don't use initial values sent in by accel demo, as they are garbage. xac_max = yac_max = zac_max = 51; xac_min = yac_min = zac_min = 49; xac = yac = zac = 50; firstRunFlag = false; } else { if (xac > xac_max) xac_max = xac; if (xac < xac_min) xac_min = xac; if (yac > yac_max) yac_max = yac; if (yac < yac_min) yac_min = yac; if (zac > zac_max) zac_max = zac; if (zac < zac_min) zac_min = zac; /* // High pass filter the max/min vals xac_max = 0.9 * xac_max + 0.1 * (xac_max + xac_min) / 2; xac_min = 0.9 * xac_min + 0.1 * (xac_max + xac_min) / 2; yac_max = 0.9 * yac_max + 0.1 * (xac_max + xac_min) / 2; yac_min = 0.9 * yac_min + 0.1 * (xac_max + xac_min) / 2; zac_max = 0.9 * zac_max + 0.1 * (xac_max + xac_min) / 2; zac_min = 0.9 * zac_min + 0.1 * (xac_max + xac_min) / 2; */ // Autoscale based on historical min/max values xac_Scaled = (int)Math.Round(((xac - xac_min) * 127) / (xac_max - xac_min)); yac_Scaled = (int)Math.Round(((yac - yac_min) * 127) / (yac_max - yac_min)); zac_Scaled = (int)Math.Round(((zac - zac_min) * 127) / (zac_max - zac_min)); } this.updateNote(false); } private void openTestPanel_CheckedChanged(object sender, EventArgs e) { if (openTestPanel.Checked) myXYPanel.Show(); else myXYPanel.Hide(); } public void testPanelHidden() { openTestPanel.Checked = false; } private void MIDI_control_FormClosing(object sender, FormClosingEventArgs e) { closeMidiOutput(); if (!myXYPanel.IsDisposed) myXYPanel.Close(); } private bool openMidiOutput() { outDialog = new OutputDeviceDialog(); if (OutputDevice.DeviceCount == 0) { MessageBox.Show("No MIDI output devices available.", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; } else { try { outDevice = new OutputDevice(outDeviceID); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; } } // Flag that MIDI output has successfully initialized midiStarted = true; btn_startMIDI.Text = "Stop MIDI"; btn_startMIDI.BackColor = Color.LightCoral; return true; } private void closeMidiOutput() { // Flag that MIDI out will/has stop(ped) midiStarted = false; btn_startMIDI.Text = "Start MIDI"; btn_startMIDI.BackColor = Color.DarkSeaGreen; try { if (outDevice != null && !outDevice.IsDisposed) outDevice.Dispose(); } catch (Exception e) { } } private void updateParamDisplay() { if (opt_modeMan.Checked) { // All settings manual, no accel control instrumentSelect.Enabled = true; noteSelect.Enabled = true; volumeSelect.Enabled = true; pitchBendSelect.Enabled = true; modSelect.Enabled = true; } else if (opt_mode1.Checked) { // X accel controls note value, Y accel controls modulation instrumentSelect.Enabled = true; noteSelect.Enabled = false; volumeSelect.Enabled = false; pitchBendSelect.Enabled = true; modSelect.Enabled = true; } else if (opt_mode2.Checked) { // X accel controls pitch bend, Y accel controls modulation instrumentSelect.Enabled = true; noteSelect.Enabled = true; volumeSelect.Enabled = true; pitchBendSelect.Enabled = false; modSelect.Enabled = false; } else if (opt_mode3.Checked) { // X accel controls pitch bend, Y accel controls volume instrumentSelect.Enabled = true; noteSelect.Enabled = true; volumeSelect.Enabled = false; pitchBendSelect.Enabled = false; modSelect.Enabled = true; } else { // None of the option boxes are checked?! return; } } private void opt_modeMan_CheckedChanged(object sender, EventArgs e) { updateParamDisplay(); } private void opt_mode1_CheckedChanged(object sender, EventArgs e) { updateParamDisplay(); } private void opt_mode2_CheckedChanged(object sender, EventArgs e) { updateParamDisplay(); } private void opt_mode3_CheckedChanged(object sender, EventArgs e) { updateParamDisplay(); } } }