銀月の符号

Python 使い見習いの日記・雑記

おーぷんMIDIぷろじぇくと、なるもの発見

おーぷんMIDIぷろじぇくと を先日発見。これ Python から使えると便利な気がしてきた。気のせいかも? DLL の形式でも公開されているため、とりあえず ctypes つかえばベタなラッパーは何も考えずに書ける。たとえば MIDIIOライブラリならこんな感じ。

でもベタなままだと C と大差ない、なら C から使おうよってことにもなる。 Python らしくするためにも一工夫加える必要あり。整数 1, 0 返して正常異常を知らせる関数は失敗時に例外を送出にしたりとか(これは ctypes のみで可能)、ポインタ複数渡して値を複数受け取るための関数は普通にリストに値まとめて返すようにしたり(これも)。入出力マクロはそのままではなく Python 標準のファイルオブジェクト風にしてみたり。MIDIData ライブラリは OOP っぽくするのもありかも。今後の課題。

  • 使ってみる。 MIDIIO.dll と下記の自作 midiio パッケージを使用。起立、礼!
# coding: utf-8
import time
from ctypes import *
from midiio import midiout

def main():
    c_s = create_string_buffer(32)
    ret = midiout.GetDeviceName(0, c_s, 32)
    if not ret:
        u'MIDIデバイスが見つかりません'
        return

    s0 = c_s.value
    print s0

    mo = midiout.Open(s0)
    if mo:
        try:
            print u'MIDIデバイスオープンしました'
            grand_piano = '\xc0\x00'
            midiout.PutMIDIMessage(mo, grand_piano, len(grand_piano))
            time.sleep(0.1)

            code_c = ('\x24', '\x30', '\x3c', '\x40', '\x43', '\x48')
            code_g = ('\x2b', '\x37', '\x3b', '\x3e', '\x43', '\x47')
            for c in code_c:
                message = '\x90%s\x64' % c
                midiout.PutMIDIMessage(mo, message, len(message))
            time.sleep(2)

            for c in code_c:
                message = '\x90%s\x00' % c
                midiout.PutMIDIMessage(mo, message, len(message))
            for c in code_g:
                message = '\x90%s\x64' % c
                midiout.PutMIDIMessage(mo, message, len(message))
            time.sleep(2)

            for c in code_g:
                message = '\x90%s\x00' % c
                midiout.PutMIDIMessage(mo, message, len(message))
            for c in code_c:
                message = '\x90%s\x64' % c
                midiout.PutMIDIMessage(mo, message, len(message))
            time.sleep(4)
        finally:
            ret = midiout.Close(mo)
            if ret:
                print u'MIDIデバイスクローズしました'
            else:
                print u'MIDIデバイスクローズ失敗'
    else:
        print 'MIDIデバイスが開けません'

if __name__ == '__main__':
    main()
  • midiio/__init__.py
# coding: utf-8
u"""おーぷんMIDIぷろじぇくと
MIDIIOLib0.4 対応
"""

from ctypes import *

__all__ = ['midiin', 'midiout']

midiio_dll = windll.MIDIIO

class MIDI(Structure):
    _fields_ = [
            ('m_pDeviceHandle', c_void_p),
            ('m_szDeviceName', c_char * 32),
            ('m_lMode', c_long),
            ('m_pBuf', POINTER(c_ubyte)),
            ('m_lBufSize', c_long),
            ('m_lReadPosition', c_long),
            ('m_lWritePosition', c_long),
            ]
  • midiio/midiin.py
# coding: utf-8
u"""おーぷんMIDIぷろじぇくと
MIDIIn 系
"""

from ctypes import *
from midiio import MIDI, midiio_dll

__all__ = [
        'MIDIIn', 'GetDeviceNum', 'GetDeviceName', 'Open', 'Reopen',
        'Close', 'Reset', 'GetMIDIMessage', 'GetByte', 'GetBytes']

MIDIIn = MIDI

GetDeviceNum = WINFUNCTYPE(c_long)(
        ('MIDIIn_GetDeviceNum', midiio_dll),
        )

GetDeviceName = WINFUNCTYPE(c_long, c_long, c_char_p, c_long)(
        ('MIDIIn_GetDeviceName', midiio_dll),
        (
            (1, 'lIndex'),
            (1, 'pszDeviceName'),
            (1, 'lLen'),
            )
        )

Open = WINFUNCTYPE(POINTER(MIDIIn), c_char_p)(
        ('MIDIIn_Open', midiio_dll),
        (
            (1, 'pszDeviceName'),
            )
        )

Reopen = WINFUNCTYPE(POINTER(MIDIIn), POINTER(MIDIIn), c_char_p)(
        ('MIDIIn_Reopen', midiio_dll),
        (
            (1, 'pMIDIIn'),
            (1, 'pszDeviceName'),
            )
        )

Close = WINFUNCTYPE(c_long, POINTER(MIDIIn))(
        ('MIDIIn_Close', midiio_dll),
        (
            (1, 'pMIDIIn'),
            )
        )

Reset = WINFUNCTYPE(c_long, POINTER(MIDIIn))(
        ('MIDIIn_Reset', midiio_dll),
        (
            (1, 'pMIDIIn'),
            )
        )

GetMIDIMessage = WINFUNCTYPE(c_long, POINTER(MIDIIn), c_char_p, c_long)(
        ('MIDIIn_GetMIDIMessage', midiio_dll),
        (
            (1, 'pMIDIIn'),
            (1, 'pMessage'),
            (1, 'lLen'),
            )
        )

GetByte = WINFUNCTYPE(c_long, POINTER(MIDIIn), c_ubyte)(
        ('MIDIIn_GetByte', midiio_dll),
        (
            (1, 'pMIDIIn'),
            (1, 'ucByte'),
            )
        )

GetBytes = WINFUNCTYPE(c_long, POINTER(MIDIIn), c_char_p, c_long)(
        ('MIDIIn_GetBytes', midiio_dll),
        (
            (1, 'pMIDIIn'),
            (1, 'pBuf'),
            (1, 'lLen'),
            )
        )
  • midiio/midiout.py
# coding: utf-8
u"""おーぷんMIDIぷろじぇくと
MIDIOut 系
"""

from ctypes import *
from midiio import MIDI, midiio_dll

__all__ = [
        'MIDIOut', 'GetDeviceNum', 'GetDeviceName', 'Open', 'Reopen',
        'Close', 'Reset', 'PutMIDIMessage', 'PutByte', 'PutBytes']

MIDIOut = MIDI

GetDeviceNum = WINFUNCTYPE(c_long)(
        ('MIDIOut_GetDeviceNum', midiio_dll),
        )

GetDeviceName = WINFUNCTYPE(c_long, c_long, c_char_p, c_long)(
        ('MIDIOut_GetDeviceName', midiio_dll),
        (
            (1, 'lIndex'),
            (1, 'pszDeviceName'),
            (1, 'lLen'),
            )
        )

Open = WINFUNCTYPE(POINTER(MIDIOut), c_char_p)(
        ('MIDIOut_Open', midiio_dll),
        (
            (1, 'pszDeviceName'),
            )
        )

Reopen = WINFUNCTYPE(POINTER(MIDIOut), POINTER(MIDIOut), c_char_p)(
        ('MIDIOut_Reopen', midiio_dll),
        (
            (1, 'pMIDIOut'),
            (1, 'pszDeviceName'),
            )
        )

Close = WINFUNCTYPE(c_long, POINTER(MIDIOut))(
        ('MIDIOut_Close', midiio_dll),
        (
            (1, 'pMIDIOut'),
            )
        )

Reset = WINFUNCTYPE(c_long, POINTER(MIDIOut))(
        ('MIDIOut_Reset', midiio_dll),
        (
            (1, 'pMIDIOut'),
            )
        )

PutMIDIMessage = WINFUNCTYPE(c_long, POINTER(MIDIOut), c_char_p, c_long)(
        ('MIDIOut_PutMIDIMessage', midiio_dll),
        (
            (1, 'pMIDIOut'),
            (1, 'pMessage'),
            (1, 'lLen'),
            )
        )

PutByte = WINFUNCTYPE(c_long, POINTER(MIDIOut), c_ubyte)(
        ('MIDIOut_PutByte', midiio_dll),
        (
            (1, 'pMIDIOut'),
            (1, 'ucByte'),
            )
        )

PutBytes = WINFUNCTYPE(c_long, POINTER(MIDIOut), c_char_p, c_long)(
        ('MIDIOut_PutBytes', midiio_dll),
        (
            (1, 'pMIDIOut'),
            (1, 'pBuf'),
            (1, 'lLen'),
            )
        )