single.php

C#でMIDI信号を取得する方法(MidiInPort.MessageReceived)

MIDIプログラミングをする際に遭遇した、C#「Windows.Device.Midi」アセンブリのMidiInport.MessageRecieved イベントでMIDI信号を取得する方法について備忘録的に投稿しています。

MidiInport.MessageRecievedイベントで取得

色々やってみて、イベントが発生せずに苦労しましたが公式ページの「UWPアプリを開発する|MIDI」の方法で取得ができました。

同じクラスではなく別途クラスを追加して実装すると、イベントとして取得ができました。

具体的には、次の手順で追加を行います。

1. UWPプロジェクトを作成して[Microsoft.Windows.SDK.Contracts]を追加します。

追加の方法は別記事をご覧ください。

2.[MMainPage.xaml]にリストを追加します。

<ListBox x:Name="midiInPortListBox" SelectionChanged="midiInPortListBox_SelectionChanged"/>

3. プロジェクトにクラスを追加します。(名前は”MyMidiDeviceWatcher” にします)

4. 追加したクラスに、次のコードを追加します。

internal class MyMidiDeviceWatcher
{
    DeviceWatcher deviceWatcher;
    string deviceSelectorString;
    ListBox deviceListBox;
    CoreDispatcher coreDispatcher;

    public DeviceInformationCollection DeviceInformationCollection { get; set; }

    public MyMidiDeviceWatcher(string midiDeviceSelectorString, ListBox midiDeviceListBox, CoreDispatcher dispatcher)
    {
        deviceListBox = midiDeviceListBox;
        coreDispatcher = dispatcher;

        deviceSelectorString = midiDeviceSelectorString;

        deviceWatcher = DeviceInformation.CreateWatcher(deviceSelectorString);
        deviceWatcher.Added += DeviceWatcher_Added;
        deviceWatcher.Removed += DeviceWatcher_Removed;
        deviceWatcher.Updated += DeviceWatcher_Updated;
        deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted;
    }

    private async void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
    {
        await coreDispatcher.RunAsync(CoreDispatcherPriority.High, () =>
        {
            // Update the device list
            UpdateDevices();
        });
    }

    private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
    {
        await coreDispatcher.RunAsync(CoreDispatcherPriority.High, () =>
        {
            // Update the device list
            UpdateDevices();
        });
    }

    private async void DeviceWatcher_EnumerationCompleted(DeviceWatcher sender, object args)
    {
        await coreDispatcher.RunAsync(CoreDispatcherPriority.High, () =>
        {
            // Update the device list
            UpdateDevices();
        });
    }

    private async void DeviceWatcher_Updated(DeviceWatcher sender, DeviceInformationUpdate args)
    {
        await coreDispatcher.RunAsync(CoreDispatcherPriority.High, () =>
        {
            // Update the device list
            UpdateDevices();
        });
    }

    private async void UpdateDevices()
    {
        // Get a list of all MIDI devices
        this.DeviceInformationCollection = await DeviceInformation.FindAllAsync(deviceSelectorString);

        deviceListBox.Items.Clear();

        if (!this.DeviceInformationCollection.Any())
        {
            deviceListBox.Items.Add("No MIDI devices found!");
        }

        foreach (var deviceInformation in this.DeviceInformationCollection)
        {
            deviceListBox.Items.Add(deviceInformation.Name);
        }
    }
    public void StartWatcher()
    {
        deviceWatcher.Start();
    }
    public void StopWatcher()
    {
        deviceWatcher.Stop();
    }
    ~MyMidiDeviceWatcher()
    {
        deviceWatcher.Added -= DeviceWatcher_Added;
        deviceWatcher.Removed -= DeviceWatcher_Removed;
        deviceWatcher.Updated -= DeviceWatcher_Updated;
        deviceWatcher.EnumerationCompleted -= DeviceWatcher_EnumerationCompleted;
        deviceWatcher = null;
    }

}

5. MainPageクラスに次の変数を追加します。

MyMidiDeviceWatcher inputDeviceWatcher;
private async Task EnumerateMidiInputDevices()
{
    string midiInputQueryString = MidiInPort.GetDeviceSelector();
    DeviceInformationCollection midiInputDevices = await DeviceInformation.FindAllAsync(midiInputQueryString);

    midiInPortListBox.Items.Clear();
    if (midiInputDevices.Count == 0)
    {
        this.midiInPortListBox.Items.Add("No MIDI input devices found!");
        this.midiInPortListBox.IsEnabled = false;
        return;
    }
    foreach (DeviceInformation deviceInfo in midiInputDevices)
    {
        this.midiInPortListBox.Items.Add(deviceInfo.Name);
    }
    this.midiInPortListBox.IsEnabled = true;
}

6. MainPageクラスのコンストラクター部分にコードを追加します。

public MainPage()
{
    this.InitializeComponent();

    inputDeviceWatcher =
        new MyMidiDeviceWatcher(MidiInPort.GetDeviceSelector(), midiInPortListBox, Dispatcher);

    inputDeviceWatcher.StartWatcher();
}

7. MainPageクラスに、次のイベントとプロシージャを追加します。

private async void midiInPortListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var deviceInformationCollection = inputDeviceWatcher.DeviceInformationCollection;

    if (deviceInformationCollection == null)
    {
        return;
    }

    DeviceInformation devInfo = deviceInformationCollection[midiInPortListBox.SelectedIndex];

    if (devInfo == null)
    {
        return;
    }

    midiInPort = await MidiInPort.FromIdAsync(devInfo.Id);

    if (midiInPort == null)
    {
        System.Diagnostics.Debug.WriteLine("Unable to create MidiInPort from input device");
        return;
    }
    midiInPort.MessageReceived += MidiInPort_MessageReceived;
}

private void MidiInPort_MessageReceived(MidiInPort sender, MidiMessageReceivedEventArgs args)
{
    IMidiMessage receivedMidiMessage = args.Message;

    System.Diagnostics.Debug.WriteLine(receivedMidiMessage.Timestamp.ToString());

    if (receivedMidiMessage.Type == MidiMessageType.NoteOn)
    {
        System.Diagnostics.Debug.WriteLine(((MidiNoteOnMessage)receivedMidiMessage).Channel);
        System.Diagnostics.Debug.WriteLine(((MidiNoteOnMessage)receivedMidiMessage).Note);
        System.Diagnostics.Debug.WriteLine(((MidiNoteOnMessage)receivedMidiMessage).Velocity);
    }
}

6. すべてを保存してデバッグ実行します。

7. 表示された一覧から取得するMIDI機器名をクリックします。

8. 選択したMIDI機器から信号を送る(キーボードなら鍵盤を押す)と[出力]画面にMIDIコードなどが出力されます。

同じクラスで取得をしましたが、イベントが動作してくれない結果でしたが別クラスでDeviceWatcherを利用した場合にはキチンとイベントが発生してくれるようになりました。

まとめ

今回は短い記事ですが、Visual StudioのC#でMIDI機器からの信号を取得するコードについて書きました。

NuGetからインストールできる[Microsoft.Windows.SDK.Contracts]内のDeviceWatcherを利用することでMIDI機器からの信号を取得することができました。

C#でMidi機器をコントロールしたい人の参考になれば幸いです。

スポンサーリンク

最後までご覧いただき、ありがとうございます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です