MIDIコントローラのnanoKONTROL2を買ったので、
入力データを取得して表示するPowerShellスクリプトを作りました。
動作画面
ソースコード
#----------------------------------------------------------------------------------------------------------------------
# Get-MidiData.ps1
#----------------------------------------------------------------------------------------------------------------------
Write-Output "* Get-MidiData"
Set-Location $PSScriptRoot
#----------------------------------------------------------------------------------------------------------------------
# MIDI Win32API Functions
# https://docs.microsoft.com/en-us/windows/win32/api/mmeapi/
Add-Type @"
using System;
using System.Runtime.InteropServices;
namespace Win32API {
public enum ERR {
MMSYSERR_NOERROR = 0,
MMSYSERR_ERROR = 1,
MMSYSERR_BADDEVICEID = 2,
MMSYSERR_ALLOCATED = 4,
MMSYSERR_INVALHANDLE = 5,
MMSYSERR_NODRIVER = 6,
MMSYSERR_NOMEM = 7,
MMSYSERR_INVALFLAG = 10,
MMSYSERR_INVALPARAM = 11,
}
public enum MSG {
// MIDI Input
MM_MIM_OPEN = 0x3C1,
MM_MIM_CLOSE = 0x3C2,
MM_MIM_DATA = 0x3C3,
MM_MIM_LONGDATA = 0x3C4,
MM_MIM_ERROR = 0x3C5,
MM_MIM_LONGERROR = 0x3C6,
// MIDI Output
MM_MOM_OPEN = 0x3C7,
MM_MOM_CLOSE = 0x3C8,
MM_MOM_DONE = 0x3C9,
}
internal enum IE {
MAXPNAMELEN = 32,
CALLBACK_FUNCTION = 0x00030000,
}
[StructLayout(LayoutKind.Sequential)]
public struct MIDIINCAPS { // typedef struct {
public UInt16 wMid; // WORD wMid;
public UInt16 wPid; // WORD wPid;
public UInt32 vDriverVersion; // MMVERSION vDriverVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)IE.MAXPNAMELEN)]
public String szPname; // TCHAR szPname[MAXPNAMELEN];
public UInt32 dwSupport; // DWORD dwSupport;
} // } MIDIINCAPS;
[StructLayout(LayoutKind.Sequential)]
public struct MIDIOUTCAPS { // typedef struct {
public UInt16 wMid; // WORD wMid;
public UInt16 wPid; // WORD wPid;
public UInt32 vDriverVersion; // MMVERSION vDriverVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)IE.MAXPNAMELEN)]
public String szPname; // TCHAR szPname[MAXPNAMELEN];
public UInt16 wTechnology; // WORD wTechnology;
public UInt16 wVoices; // WORD wVoices;
public UInt16 wNotes; // WORD wNotes;
public UInt16 wChannelMask; // WORD wChannelMask;
public UInt32 dwSupport; // DWORD dwSupport;
} // } MIDIOUTCAPS;
public class C {
// MIDI Input Functions
[DllImport("Winmm.dll")]
public static extern UInt32 midiInGetNumDevs(); // UINT midiInGetNumDevs();
public static UInt32 getSizeOfMIDIINCAPS() {
return (UInt32)Marshal.SizeOf(typeof(MIDIINCAPS));
}
[DllImport("Winmm.dll")]
public static extern UInt32 midiInGetDevCaps( // MMRESULT midiInGetDevCaps(
UInt32 uDeviceID, // UINT uDeviceID,
out MIDIINCAPS pmic, // LPMIDIINCAPS pmic,
UInt32 cbmic // UINT cbmic
); // );
[DllImport("Winmm.dll")]
public static extern UInt32 midiInOpen( // MMRESULT midiInOpen(
out IntPtr phmi, // LPHMIDIIN phmi,
UInt32 uDeviceID, // UINT uDeviceID,
MidiInProcDelegate dwCallback, // DWORD_PTR dwCallback,
IntPtr dwInstance, // DWORD_PTR dwInstance,
UInt32 fdwOpen // DWORD fdwOpen
); // );
public static UInt32 midiInOpen_Callback(
out IntPtr phmi, // LPHMIDIIN phmi,
UInt32 uDeviceID, // UINT uDeviceID,
IntPtr dwInstance // DWORD_PTR dwInstance,
) {
return midiInOpen(out phmi, uDeviceID, MidiInProcRef, dwInstance, (UInt32)IE.CALLBACK_FUNCTION);
}
[DllImport("Winmm.dll")]
public static extern UInt32 midiInClose( // MMRESULT midiInClose(
IntPtr hmi // HMIDIIN hmi
); // );
[DllImport("Winmm.dll")]
public static extern UInt32 midiInReset( // MMRESULT midiInReset(
IntPtr hmi // HMIDIIN hmi
); // );
[DllImport("Winmm.dll")]
public static extern UInt32 midiInStart( // MMRESULT midiInStart(
IntPtr hmi // HMIDIIN hmi
); // );
[DllImport("Winmm.dll")]
public static extern UInt32 midiInStop( // MMRESULT midiInStop(
IntPtr hmi // HMIDIIN hmi
); // );
public delegate void MidiInProcDelegate( // void CALLBACK MidiInProc(
IntPtr hmi, // HMIDIIN hMidiIn,
UInt32 wMsg, // UINT wMsg,
IntPtr dwInstance, // DWORD_PTR dwInstance,
IntPtr dwParam1, // DWORD_PTR dwParam1,
IntPtr dwParam2 // DWORD_PTR dwParam2
); // );
public static event MidiInProcDelegate MidiInProcEvent;
private static readonly MidiInProcDelegate MidiInProcRef = MidiInProc;
private static void MidiInProc( // void CALLBACK MidiInProc(
IntPtr hmi, // HMIDIIN hMidiIn,
UInt32 wMsg, // UINT wMsg,
IntPtr dwInstance, // DWORD_PTR dwInstance,
IntPtr dwParam1, // DWORD_PTR dwParam1,
IntPtr dwParam2 // DWORD_PTR dwParam2
) { // );
if (MidiInProcEvent != null) {
MidiInProcEvent(hmi, wMsg, dwInstance, dwParam1, dwParam2);
}
}
// MIDI Output Functions
[DllImport("Winmm.dll")]
public static extern UInt32 midiOutGetNumDevs(); // UINT midiOutGetNumDevs();
public static UInt32 getSizeOfMIDIOUTCAPS() {
return (UInt32)Marshal.SizeOf(typeof(MIDIOUTCAPS));
}
[DllImport("Winmm.dll")]
public static extern UInt32 midiOutGetDevCaps( // MMRESULT midiOutGetDevCaps(
UInt32 uDeviceID, // UINT uDeviceID,
out MIDIOUTCAPS pmoc, // LPMIDIOUTCAPS pmoc,
UInt32 cbmoc // UINT cbmoc
); // );
}
}
"@
function Get-MidiInDevices() {
$devs = New-Object System.Collections.ArrayList
$num = [Win32API.C]::midiInGetNumDevs()
for ($id = 0; $id -lt $num; $id++) {
$caps = New-Object Win32API.MIDIINCAPS
$ret = [Win32API.C]::midiInGetDevCaps($id, [ref]$caps, [Win32API.C]::getSizeOfMIDIINCAPS())
if ($ret -eq [Win32API.ERR]::MMSYSERR_NOERROR) {
[void]$devs.Add($caps)
}
}
return $devs
}
function Get-MidiOutDevices() {
$devs = New-Object System.Collections.ArrayList
$num = [Win32API.C]::midiOutGetNumDevs()
for ($id = 0; $id -lt $num; $id++) {
$caps = New-Object Win32API.MIDIOUTCAPS
$ret = [Win32API.C]::midiOutGetDevCaps($id, [ref]$caps, [Win32API.C]::getSizeOfMIDIOUTCAPS())
if ($ret -eq [Win32API.ERR]::MMSYSERR_NOERROR) {
[void]$devs.Add($caps)
}
}
return $devs
}
#----------------------------------------------------------------------------------------------------------------------
# Main Routine
if ($null -eq $psISE) {
$timeout = 60
$ESC = @{
CSI_SCOSC = "$([Char]27)[s";
CSI_SCORC = "$([Char]27)[u";
CSI_SGR_0 = "$([Char]27)[0m";
CSI_SGR_7 = "$([Char]27)[7m"
}
$CSI_SCOSC_T = "$("`n" * 12)$([Char]27)[11A$([Char]27)[s"
} else {
$timeout = 5
}
$midiInDevs = Get-MidiInDevices
Write-Host "* MIDI IN Device List:`n$($midiInDevs.szPname -join "`n")"
$midiOutDevs = Get-MidiOutDevices
Write-Host "* MIDI OUT Device List:`n$($midiOutDevs.szPname -join "`n")"
$midiInProcAction = {
param ($hmi, $wMsg, $dwInstance, $dwParam1, $dwParam2)
try {
$ESC = $Event.MessageData.ESC
switch ($wMsg) {
([UInt32][Win32API.MSG]::MM_MIM_DATA) {
$name = ([Int32]$dwParam1 -band 0x0000ff00) -shr 8
$value = ([Int32]$dwParam1 -band 0x00ff0000) -shr 16
$Event.MessageData.status[$name] = $value
}
}
$Event.MessageData.watch.Restart()
Write-Host (("{0}{1}: dwInstance = {2}, dwParam1 = 0x{3:X8}, dwParam2 = 0x{4:X8}" -f
$ESC.CSI_SCORC, [Enum]::Parse([Win32API.MSG], $wMsg), $dwInstance, [Int]$dwParam1, [Int]$dwParam2))
$text = @"
KORG nanoKONTROL2
-- TRACK -- P 10:** 11:** 12:** 13:** 14:** 15:** 16:** 17:**
< >
3A:** 3B:** --- MARKER --- S 20:** 21:** 22:** 23:** 24:** 25:** 26:** 27:**
CYCLE SET < > M 30:** 31:** 32:** 33:** 34:** 35:** 36:** 37:**
2E:** 3C:** 3D:** 3E:** R 40:** 41:** 42:** 43:** 44:** 45:** 46:** 47:**
<< >> [] > O
2B:** 2C:** 2A:** 29:** 2D:** V 00:** 01:** 02:** 03:** 04:** 05:** 06:** 07:**
"@
$Event.MessageData.status.GetEnumerator() |
ForEach-Object {
$CSI_SGR = @($ESC.CSI_SGR_0, $ESC.CSI_SGR_7)[$_.Value -ne 0]
$text = $text -replace ("($($_.Name.ToString("X2")))\:\*\*"),
"`$1:$CSI_SGR$($_.Value.ToString("X2"))$($ESC.CSI_SGR_0)"
}
Write-Host $text
} catch [Exception] {
Write-Warning ($_ | Out-String)
}
}
$watch = New-Object System.Diagnostics.Stopwatch
$status = @{}
Write-Host "* Start Monitoring"
Write-Host "$CSI_SCOSC_T" -NoNewline
Get-Event | Remove-Event
$event = Register-ObjectEvent -InputObject ($obj = [Win32API.C]) -EventName MidiInProcEvent `
-Action $midiInProcAction `
-MessageData (New-Object PSObject -Property @{ status = $status; watch = $watch; ESC = $ESC })
$id = ([Collections.Generic.List[Object]]$midiInDevs).FindIndex({ $args.szPname -eq "nanoKONTROL2" })
if ($id -eq -1) {
$id = 0
}
$hmi = [IntPtr]::Zero
$ret = [Win32API.C]::midiInOpen_Callback([ref]$hmi, $id, [IntPtr]::Zero)
if ($ret -ne [Win32API.ERR]::MMSYSERR_NOERROR) {
Write-Host "! midiInOpen(uDeviceID = $id) failed: $([Enum]::Parse([Win32API.ERR], $ret))"
} else {
$watch.Restart()
$ret = [Win32API.C]::midiInStart($hmi)
while ($true) {
if ($Host.UI.RawUI.KeyAvailable) {
$key = $Host.ui.RawUI.ReadKey("NoEcho,IncludeKeyUp")
if ($key.VirtualKeyCode -eq 27) {
break
}
}
if ($watch.Elapsed.TotalSeconds -ge $timeout) {
break
}
}
$ret = [Win32API.C]::midiInStop($hmi)
$ret = [Win32API.C]::midiInReset($hmi)
$ret = [Win32API.C]::midiInClose($hmi)
}
Unregister-Event $event.Name
Get-Event | Remove-Event
Write-Host "* Stop Monitoring"
exit















