Friday, July 17, 2015

Create MIDI Tones with C#

After I explained in the previous posts the creation of basic musical tones via Beep, I today want to enhance the sound drastically, which we do with the MIDI format. MIDI is a standard for the exchange of musical control information. It was mainly designed for the communication between synthesizers and consists of messages which describe the playing of tones. With an external library we can play MIDI tones very easily with C#, which also sound pretty well. This kind of surprised and fascinated me - with only some lines of code one can play actual songs.

For this we use the MIDI library midi-dot-net. This has to be downloaded, and then the file "midi.dll" has to be included in the project (Project - Add Reference). After using Midi; then an OutputDevice can be created, which we set via InstalledDevices[0] to our standard speaker. Via SendNoteOn() we then can play a note. For this we have to pass over the desired channel as the first parameter, as a second one the tone and finally the velocity as an int value (it measures, how forcefully the virtual key is pressed).  The note is specified as an object of the enumeration Pitch, which contains a broad spectrum of tones.
I liked the approach from the previous though, to use the keyboard keys, therefore we use this here: We convert the enumeration into an array of the type Pitch and then choose the tone belonging to the pressed key (the desired tone of key n is the entry n + 21).
The tone is played until another command is send, for example we can send SendNoteOff() to turn off the tone. We here simply wait via Sleep() the corresponding tone duration and then play the next one.
The following program plays the anthems from the previous post with MIDI tones:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using Midi;
using System.Threading;

namespace Beep
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            PlayAmericanAnthem();
            PlayGermanAnthem();
        }

        OutputDevice outputDevice;

        public void PlayNote(int key, double duration)
        {
            Pitch Note = ((Pitch[])Enum.GetValues(typeof(Pitch)))[key + 21];
            outputDevice.SendNoteOn(Channel.Channel1, Note, 80);
            Thread.Sleep((int)duration);
        }

        public void PlayGermanAnthem()
        {
            outputDevice = OutputDevice.InstalledDevices[0];
            outputDevice.Open();

            PlayNote(31, 700);
            PlayNote(33, 300);

            PlayNote(35, 500);
            PlayNote(33, 500);
            PlayNote(36, 500);
            PlayNote(35, 500);

            PlayNote(33, 250);
            PlayNote(30, 250);
            PlayNote(31, 500);
            PlayNote(40, 500);
            PlayNote(38, 500);

            PlayNote(36, 500);
            PlayNote(35, 500);
            PlayNote(33, 500);
            PlayNote(35, 250);
            PlayNote(31, 250);

            PlayNote(38, 800);
            outputDevice.Close();
        }

        public void PlayAmericanAnthem()
        {
            outputDevice = OutputDevice.InstalledDevices[0];
            outputDevice.Open();

            PlayNote(20, 300 * 1.3);
            PlayNote(17, 170 * 1.3);

            PlayNote(13, 333 * 1.3);
            PlayNote(17, 333 * 1.3);
            PlayNote(20, 333 * 1.3);

            PlayNote(25, 666 * 1.3);
            PlayNote(29, 200 * 1.3);
            PlayNote(27, 130 * 1.3);

            PlayNote(25, 333 * 1.3);
            PlayNote(17, 333 * 1.3);
            PlayNote(19, 333 * 1.3);

            PlayNote(20, 666 * 1.3);
            PlayNote(20, 170 * 1.3);
            PlayNote(20, 170 * 1.3);

            PlayNote(29, 450 * 1.3);
            PlayNote(27, 220 * 1.3);
            PlayNote(25, 333 * 1.3);

            PlayNote(24, 666 * 1.3);
            PlayNote(22, 200 * 1.3);
            PlayNote(24, 100 * 1.3);

            PlayNote(25, 333 * 1.3);
            PlayNote(25, 333 * 1.3);
            PlayNote(20, 333 * 1.3);

            PlayNote(17, 333 * 1.3);
            PlayNote(13, 333 * 1.3);
            outputDevice.Close();
        }
    }
}

No comments:

Post a Comment