Events einer Midi Datei abfragen

  • Hallo Leute^^,
    ich versuche grade von einzelnen "Kanälen" einer Midi Datei die Events abzufragen. Natürlich abgespielte Noten.
    Welche sind mir egal nur will ich praktisch bei jeder eine Funktion abspielen. In der Bass.dll habe ich zwar eine Funktion gefunden die mir die Events zurückgibt allerdings kann ich diese nicht mit Funktionen verbinden. Hat da vielleicht jemand eine Idee wie man das machen könnte?

    MfG Sumsum

  • Kommt drauf an, ob du die Noten in Echtzeit "abspielen" willst.
    Wenn nicht, dann bekommst du mit "_BASS_MIDI_StreamGetEvents" ein Array mit allen Events, welche du dann einzelen auswerten kannst.

    Wenn es in Echtzeit gehen soll, dann gibt es zwei Möglichkeiten:
    1) wie oben, nur die Event-Funktionen erst ausführen, wenn der Timecode der abgespielten Mididatei den Eventzeitstempel erreicht...

    2) Mit einer SyncProc:

    [autoit]

    _BASS_ChannelSetSync($hMidiStream, $BASS_SYNC_MIDI_EVENT, $MIDI_EVENT_NOTE, "_SyncProc", 0)

    [/autoit][autoit][/autoit][autoit]

    Func _SyncProc($handle, $channel, $data, $user)
    Local Static $iCnt = 0
    $iCnt += 1

    [/autoit][autoit][/autoit][autoit]

    Local $iKeyNumber = _BASS_LoByte($data)
    Local $iVelocity = _BASS_HiByte($data)

    [/autoit][autoit][/autoit][autoit]

    ConsoleWrite("! Midi event: " & $iCnt & @TAB & $iKeyNumber & "/" & $iVelocity & @CRLF)

    [/autoit][autoit][/autoit][autoit]

    Return True
    EndFunc ;==>_SyncProc

    [/autoit]


    ACHTUNG: für diese Variante ist AutoIt nicht geeignet! und wird bei zu vielen Events abstürzen!
    Du könntest aber eine DLL in einer höheren Programmiersprache erstellen...

    E

  • Ja es soll in Echtzeit sein^^
    Die erste Möglichkeit hab ich schon ausprobiert allerdings ist die Wahrscheinlichkeit arg unwahrscheinlich das Autoit genau in dem Moment in dem Die Note abgespielt wird den dazugehörigen Timecode abfragt.

    Funktioniert die 2. Methode denn nur bei einigen Events nicht oder stürzt sie bei allen häufig ab?

  • Probiers mal aus.
    Hier ein abgewandeltes Script aus der Hilfe:

    Spoiler anzeigen
    [autoit]

    #AutoIt3Wrapper_UseX64=n
    #include "bass.au3"
    #include "bassmidi.au3"
    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    HotKeySet("{ESC}", "_Exit")

    [/autoit] [autoit][/autoit] [autoit]

    $sFile = FileOpenDialog("Open Midi-file", "..\audiofiles", "(*.mid)")
    ___DeBug($sFile = "", $sFile)

    [/autoit] [autoit][/autoit] [autoit]

    _BASS_Startup()
    ___DeBug(@error, "load bass.dll")

    [/autoit] [autoit][/autoit] [autoit]

    _BASS_MIDI_Startup()
    ___DeBug(@error, "load bassmidi.dll")

    [/autoit] [autoit][/autoit] [autoit]

    _BASS_Init(0, -1, 44100, 0, "")
    ___DeBug(@error, "initialize bass")

    [/autoit] [autoit][/autoit] [autoit]

    $hMidiStream = _BASS_MIDI_StreamCreateFile(False, $sFile)
    ___DeBug(@error, "creating midifile stream")

    [/autoit] [autoit][/autoit] [autoit]

    _BASS_ChannelSetSync($hMidiStream, $BASS_SYNC_MIDI_EVENT, $MIDI_EVENT_NOTE, "_SyncProc", 0)
    ___DeBug(@error, "set sync" & @error)

    [/autoit] [autoit][/autoit] [autoit]

    _BASS_ChannelPlay($hMidiStream, False)
    ___DeBug(@error, "play stream")

    [/autoit] [autoit][/autoit] [autoit]

    $iLen = _BASS_ChannelGetLength($hMidiStream, $BASS_POS_BYTE)

    [/autoit] [autoit][/autoit] [autoit]

    While _BASS_ChannelIsActive($hMidiStream)
    Sleep(20)
    $iPos = _BASS_ChannelGetPosition($hMidiStream, $BASS_POS_BYTE)
    ToolTip(Round($iPos * 100 / $iLen, 1) & "% played")
    WEnd
    _Exit()

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _SyncProc($handle, $channel, $data, $user)
    Local Static $iCnt = 0
    $iCnt += 1

    [/autoit] [autoit][/autoit] [autoit]

    Local $iKeyNumber = _BASS_LoByte($data)
    Local $iVelocity = _BASS_HiByte($data)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite("! Midi event: " & $iCnt & @TAB & $iKeyNumber & "/" & $iVelocity & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Return True
    EndFunc ;==>_SyncProc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    _BASS_StreamFree($hMidiStream)
    ___DeBug(@error, "free stream")
    _BASS_Free()
    ___DeBug(@error, "free bass")
    Exit
    EndFunc ;==>_Exit

    [/autoit] [autoit][/autoit] [autoit]

    Func ___DeBug($iError, $sAction)
    Switch $iError
    Case -1
    ConsoleWrite(@CRLF & "-" & $sAction & @CRLF)
    Case 0
    ConsoleWrite(@CRLF & "+" & $sAction & " - OK" & @CRLF)
    Case Else
    ConsoleWrite(@CRLF & "!" & $sAction & " - FAILED" & @CRLF)
    Exit
    EndSwitch
    EndFunc ;==>___DeBug

    [/autoit]

    Ich glaube, dass AutoIt immer dann abstürtzt, wenn mehrere Callbackfunktionen zur selben Zeit aufgerufen werden...
    Sollte deine Midi-Datei immer nur einen Event auslösen (und der nächste erst, wenn die Funktion längst abgearbeitet wurde), dann könnte das durchaus stabil laufen.
    Ich würde aber trotzdem die Callback-Funktion in einer höheren Sprache schreiben...

    E

  • Naja das Problem ist das es theoretisch mit jeder midi gehen soll :(
    tatsächlich stürzt das Callback Script selbst dann ab wenn die Function nur hmm in die Console schreibt xD .
    Ich versuchs jetz wohl doch mit der Byte Anzahl und nem Array von allen events.