MainForm.cs

//**********************************************************

//* MidiOut exaple                                         *

//* Author: D. Zouchinski                                  *

//* http://zouchinski.co.uk                                *

//* Copyright @ 2011-2012                                  *

//**********************************************************

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

 

namespace MidiOutExample

{

    public partial class MainForm : Form

    {

        private MidiOut.Controller controller;

        private uint note;

        private bool major;

        private bool minor;

 

        public MainForm()

        {

            InitializeComponent();

 

            Rectangle area = Screen.PrimaryScreen.WorkingArea;

            this.StartPosition = FormStartPosition.Manual;

            this.Location = new Point(area.Left, area.Top);

            this.Width = Screen.PrimaryScreen.WorkingArea.Width;

 

            foreach (string device in MidiOut.Controller.GetMidiOutDevices())

                cmbDevices.Items.Add(device);

            cmbDevices.SelectedIndex = 0;

        }

 

        protected override void OnLoad(EventArgs e)

        {

            base.OnLoad(e);

        }

 

        private void cmbDevices_SelectedIndexChanged(object sender, EventArgs e)

        {

            if (controller != null)

            {

                controller.Dispose();

                controller = null;

            }

 

            if (cmbDevices.SelectedIndex < 0)

                return;

 

            controller = new MidiOut.Controller((uint)cmbDevices.SelectedIndex);

 

            // Update instrument list

            cmbChannel.Items.Clear();

            cmbChannel.Items.AddRange(Categories());

            cmbChannel.SelectedIndex = 0;

        }

 

        private uint GetNote(Point location)

        {

            uint note = (uint)((128 * location.X) / boxKeys.ClientRectangle.Width);

 

            uint octave = note / 12;

            uint key = note % 12;

 

            if (location.Y * 3 > boxKeys.ClientRectangle.Height * 2)

            {

                Rectangle rect = boxKeys.ClientRectangle;

                Rectangle keyRect = rect;

                keyRect.X = ((int)note * rect.Width) / 128;

                keyRect.Width = (((int)note + 1) * rect.Width) / 128 - keyRect.X;

 

                switch (key)

                {

                    case 1:

                    case 3:

                    case 6:

                    case 8:

                    case 10:

                        if (location.X - keyRect.X < keyRect.Width / 2)

                            note -= 1;

                        else

                            note += 1;

                        break;

                }

            }

 

            return note;

        }

 

        private void PlayNote(Point location)

        {

            note = GetNote(location);

            controller.PlayNote(0, note);

            if (ModifierKeys == Keys.Shift)

            {

                controller.PlayNote(0, note + 4);

                controller.PlayNote(0, note + 7);

                major = true;

            }

            if (ModifierKeys == Keys.Control)

            {

                controller.PlayNote(0, note + 3);

                controller.PlayNote(0, note + 7);

                minor = true;

            }

        }

 

        private void StopNote()

        {

            controller.StopNote(0, note);

            if (major)

            {

                controller.StopNote(0, note + 4);

                controller.StopNote(0, note + 7);

                major = false;

            }

            if (minor)

            {

                controller.StopNote(0, note + 3);

                controller.StopNote(0, note + 7);

                minor = false;

            }

        }

 

        private void boxKeys_MouseDown(object sender, MouseEventArgs e)

        {

            if (cmbChannel.SelectedIndex < 0)

                return;

 

            if (e.Button != MouseButtons.Left)

                return;

 

            boxKeys.Capture = true;

            PlayNote(e.Location);

        }

 

        private void boxKeys_MouseUp(object sender, MouseEventArgs e)

        {

            if (cmbChannel.SelectedIndex < 0)

                return;

 

            if (e.Button != MouseButtons.Left)

                return;

 

            boxKeys.Capture = false;

            StopNote();

        }

 

        private void boxKeys_MouseMove(object sender, MouseEventArgs e)

        {

            if (cmbChannel.SelectedIndex < 0)

                return;

 

            if (e.Button != MouseButtons.Left)

                return;

 

            if (note == GetNote(e.Location))

                return;

 

            StopNote();

            PlayNote(e.Location);

        }

 

        private void boxKeys_Paint(object sender, PaintEventArgs e)

        {

            Rectangle rect = boxKeys.ClientRectangle;

            Graphics dc = e.Graphics;

 

            using (Brush brush = new SolidBrush(Color.White))

                dc.FillRectangle(brush, rect);

 

            for (int note = 0; note < 128; note++)

            {

                Rectangle keyRect = rect;

                keyRect.X = (note * rect.Width) / 128;

                keyRect.Width = ((note + 1) * rect.Width) / 128 - keyRect.X;

 

                int octave = note / 12;

                int key = note % 12;

 

                switch (key)

                {

                    case 0:

                    case 5:

                        keyRect.Width += rect.Width / 256;

                        break;

 

                    case 2:

                    case 7:

                    case 9:

                        keyRect.X -= rect.Width / 256;

                        keyRect.Width += (rect.Width / 256) * 2;

                        break;

 

                    case 4:

                    case 11:

                        keyRect.X -= rect.Width / 256;

                        keyRect.Width += rect.Width / 256;

                        break;

 

                    case 1:

                    case 3:

                    case 6:

                    case 8:

                    case 10:

                        keyRect.Height -= keyRect.Height / 3;

                        break;

                }

 

                switch (key)

                {

                    case 0:

                    case 2:

                    case 4:

                    case 5:

                    case 7:

                    case 9:

                    case 11:

                        using (Pen pen = new Pen(Color.Black))

                            dc.DrawRectangle(pen, keyRect);

                        break;

 

                    case 1:

                    case 3:

                    case 6:

                    case 8:

                    case 10:

                        using (Brush brush = new SolidBrush(Color.Black))

                            dc.FillRectangle(brush, keyRect);

                        break;

                }

            }

        }

 

        private void boxKeys_SizeChanged(object sender, EventArgs e)

        {

            boxKeys.Invalidate();

        }

 

        private void cmbChannel_SelectedIndexChanged(object sender, EventArgs e)

        {

            if (boxKeys.Capture)

            {

                boxKeys.Capture = false;

                StopNote();

            }

 

            PopulateInstruments();

        }

 

        private void cmbInstrument_SelectedIndexChanged(object sender, EventArgs e)

        {

            if (boxKeys.Capture)

            {

                boxKeys.Capture = false;

                StopNote();

            }

 

            if (cmbChannel.SelectedIndex >= 0 && cmbInstrument.SelectedIndex >= 0)

            {

                int instrument = cmbChannel.SelectedIndex * 8 + cmbInstrument.SelectedIndex;

                controller.SetInstrument(0, (uint)instrument);

            }

        }

 

        private string[] Categories()

        {

            List<string> list = new List<string>();

            var categories = MidiOut.Controller.GetInstrumentCategories();

            foreach (var item in categories)

                list.Add(item.Name);

            return list.ToArray();

        }

 

        private string[] Instruments()

        {

            if (cmbChannel.SelectedIndex < 0)

                return new string[] { };

 

            var categories = MidiOut.Controller.GetInstrumentCategories();

            return categories[cmbChannel.SelectedIndex].Instruments;

        }

 

        private void PopulateInstruments()

        {

            cmbInstrument.Items.Clear();

            foreach(string item in Instruments())

                cmbInstrument.Items.Add(item);

            cmbInstrument.SelectedIndex = 0;

        }

    }

}