Freitag, 17. Juli 2015

MIDI Töne mit C# erzeugen

Nachdem ich in den vorigen Posts das Erzeugen grundlegender musikalischer Töne mit Beep erklärt habe, möchte ich heute nun den Klang deutlich verbessern, was wir mit dem MIDI Format tun.
MIDI ist ein Standard zum Austausch musikalischer Steuerinformationen. Hauptsächlich wurde es zur Kommunikation von Synthesizern entworfen, es besteht aus Nachrichten die das Spielen bestimmter Töne beschreiben. Mit einer externen Bibliothek können wir in C# ganz leicht MIDI Töne abspielen, welche auch wirklich gut klingen, was mich sehr überrascht und fasziniert hat - mit ein paar Codezeilen kann man wirklich Lieder abspielen.

Wir verwenden dafür die MIDI Bibliothek midi-dot-net. Diese muss heruntergeladen werden, und dann ist die Datei "midi.dll" ins Projekt einzubinden (Projekt - Verweis hinzufügen). Nach using Midi; kann dann ein OutputDevice angelegt werden, welches wir mit InstalledDevices[0] auf unseren Standardlautsprecher schalten. Mittels SendNoteOn() können wir dann eine Note spielen. Hierzu müssen wir als ersten Parameter einen Channel übergeben, als zweiten die Note und als dritten einen int - Wert für die Anschlagstärke der gedachten Keyboard Taste. Die Note wird als Objekt von der Aufzählung Pitch angegeben, welche ein breites Spektrum von Tönen enthält.
Ich fand jedoch den Ansatz aus dem letzten Post der Benutzung der Klaviertasten ganz schön, deswegen benutzen wir das hier: Wir konvertieren uns die Aufzählung in ein Pitch Array und suchen uns dann den zu der gedrückten Taste gehörigen Ton heraus (der gewünschte Ton der Taste n ist der Eintrag n + 21).
Der Ton wird solange gespielt, bis ein anderer Befehl kommt, z.B. können wir mit SendNoteOff() den Ton ausschalten. Wir warten einfach mittels Sleep() die entsprechende Tonlänge und spielen dann den nächsten.
Das folgende Programm spielt die beidem im vorigen Post gezeigten Hymnen mit MIDI Tönen ab:

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();
        }
    }
}

Keine Kommentare:

Kommentar veröffentlichen