Jump to content

midi keyboard as user imput. how?


gigi1
 Share

Recommended Posts

hi, i would like to use a Midi keyboard just like any other user imput (mouse, keyboard). is it possible? i just need the imput midi data (in a variable, or whatever) to use it.

i've found and read the MidiUdf, and i want to thank for that, but it has midi managment functions and i cant figure out how to get the data.

thanks for help

P.S.: yes, im a little noobish ;)

Link to comment
Share on other sites

I'm sure someone who knows about this will respond eventually. I see you have waited nearly 24 hours already. Perhaps the members who have used this UDF have not been on line lately. Give it a bit more time and if nothing happens then try contacting the author of the UDF.

Link to comment
Share on other sites

There is a free "Midi Monitor" program that should be able to help determine what codes are being sent from your keyboard.

010101000110100001101001011100110010000001101001011100110010000

001101101011110010010000001110011011010010110011100100001

My Android cat and mouse game
https://play.google.com/store/apps/details?id=com.KaosVisions.WhiskersNSqueek

We're gonna need another Timmy!

Link to comment
Share on other sites

You might need to look into the windows API calls of "winmm.dll" to seek your answers mciGetDeviceID. After you place the multimedia control into your script, the first step is accessing the MCI device. To do this, you set a number of properties. On of these properties will no doubt be your DeviceType = "Sequencer".

At the moment I am getting ready for work, if I have any free time today, I will pop back in and add some code for you.

Link to comment
Share on other sites

I have an electronic drumset that can plug into the pc via USB so I will be very interested in helping figure this one out.

I just don't know about dll's yet ;)

010101000110100001101001011100110010000001101001011100110010000

001101101011110010010000001110011011010010110011100100001

My Android cat and mouse game
https://play.google.com/store/apps/details?id=com.KaosVisions.WhiskersNSqueek

We're gonna need another Timmy!

Link to comment
Share on other sites

Good I'm glad someone has some midi equipment to test on. I don't have a thing here or at home.

These are some of the midi functions inside the winmm.dll;

midiConnect
midiDisconnect
midiInAddBuffer
midiInClose
midiInGetDevCapsA
midiInGetDevCapsW
midiInGetErrorTextA
midiInGetErrorTextW
midiInGetID
midiInGetNumDevs
midiInOpen
midiInPrepareHeader
midiInReset
midiInStart
midiInStop
midiInUnprepareHeader
midiOutCacheDrumPatches
midiOutCachePatches
midiOutClose
midiOutGetDevCapsA
midiOutGetDevCapsW
midiOutGetErrorTextA
midiOutGetErrorTextW
midiOutGetID
midiOutGetNumDevs
midiOutGetVolume
midiOutLongMsg
midiOutOpen
midiOutPrepareHeader
midiOutReset
midiOutSetVolume
midiOutShortMsg
midiOutUnprepareHeader
midiStreamClose
midiStreamOpen
midiStreamOut
midiStreamPause
midiStreamPosition
midiStreamProperty
midiStreamRestart
midiStreamStop

I dug up some code on midi input, but most of it is written in VB, C++, or some other languages. But thankfully DLLCALL structure doesn't vary much. So the first code I am looking at is;

$x = DllCall ("winmm.dll", "int", "midiInGetNumDevs")
If $x > -1 Then
    ConsoleWrite ("Number of devices detected = " & $x & @crlf)
Else
    ConsoleWrite ("No devices are detected.")
Exit
EndIf

For $i = 1 to $x
    $port = DllCall("winmm.dll", "UInt", "midiInGetDevCapsA" ,"UInt","A_Index"-1, "UInt","MidiInCaps", "UInt",50)
    ConsoleWrite ( $port & @crlf)
Next

Hopefully this code will return the number of midi devices on your system, then list the ports. It shouldn't hurt to try since we are just reading information. If you can ID your port then the next step is to open it for reading using midiInOpen function. Once successfully opened you should be able to read from the device using midiInAddBuffer depending on the data.

I just don't know about dll's yet

Dynamic Linked Libraries or DLL is just a collection of Windows functions we can access to send and receive data. Winmm.dll contains all the Multimedia function calls. I don't know much about midi or how the winmm.dll access works. A lot is based on researching the other languages such as C++ and VB to see how they access it then apply it here to AutoIt.
Link to comment
Share on other sites

I did some digging around and found this script for both midi input and output posted on Autohotkey.com (another scripting tool) similar to, if not a branch of AutoIt.

REMINDER: This is not an AutoIt script but very close.

/*
 ; Last edited 9/5/2010 8:55 AM by genmce
 
 
 I fear that adding so many different examples may make this more difficult to use. ....
I may have to pull different parts, MidiRules into an include file the same goes for the hotkeys midi generation...
Ah well...
 
 
 ****************************************************************
 Please post your revisions back to this forum post.
 Please post your derivative projects back to this page, so that others can learn from what you do.
 Please share, as I am sharing, so that others may learn and grow!
 ****************************************************************
 
 
 
 Generic Midi Program
  Basic structural framework for a midi program in ahk.
  The description what this is for is contained in the first post on the topic Midi Input/Output Combined at the ahk forum.
  Please read it, if you want to know more.
  I have added a few more examples for different midi data types as well as more, meaningful (I hope), documentation to the script.
  You are strongly encouraged to visit http://www.midi.org/techspecs/midimessages.php (decimal values), to learn more
  about midi data.  It will help you create your own midi rules.
  I have combined much of the work of others here.
  It is a working script, most of the heavy lifing has been done for you.
  You will need to create your own midi rules.
  By creating or modifying if statements in the section of the MidiRules label.
  I don't claim to be an expert on this, just a guy who pulled disparate things together.
  I really need help from someone to add sysex functionality.
 
******  Sections with  !!!!!!!!!!!!!!!!!!!!!! - don't edit between these, unless you know what you are doing (uykwyad) !
 
******  Sections with ++++++++++++++++++++++ Edit between these marks. You won't break it, I don't think???

  v. 0.4
    + added an example of hotkey generating midi (volume controller)
    + added a second example for you create your own hotkey generated midi message.
   
   
  v. 0.3 changes
  + Adding text for how to add new rules.
  + Midi Rules, name used instead of filters, seems more appropriate.
  + Moved all rules outside the detector function, hoping to make it easier to understand and use.
  + abandoned the idea of dynamic code and a gui to create rules, omg, someone else do that, please!
  + Adding more examples for rules.
  + more to come, maybe...
  + removed that notemsg var - did not need it, not sure why i used it... nevermind
 
 
   TODO -
  + add a way to echo all midi input that is not filtered or modified to the output. Like a gui switch (sometimes you want it all sometimes you don't)
  + make the midi monitor easier to use and read, also a toggle for it to be on or off.
      - midi monitor columnar with data columns to show statusbyte, byte1 and byte2 as well as midi chan.
        So need a heading grid for each ....
  + bring back sendnote() funtion instead of a gosub, same for each type of midi data.
  + Figure out how to do SYSEX with it, PLEASE HELP ME ON THIS!
 
 Generic midi program v. - 0.2 changes

  - fixed bad note off detection...
  - select input and output port
  - open and close selected midi ports
  - write ports to ini file
  - send receive midi data
  - modify received midi data, send it to output port
  - uses contributions by so many different people. See midi input and midi output forum posts. Links in midi under the hood section below
  - "under the hood" midi functions and subroutines at the end of this file
  - post your creations back to this midi I/O thread - that way we can all build on it.
 
  Notes - All midi in/out lib stuff is included here, no external dlls, besides winmm.dll required.
  Use of this - you should only need to edit the input part - great way to practice you if else logic and midi manipulation.
  This does not do sysex. I really want to develop that, but not sure how to go about it.
  Perhaps one day.
 
*/
 
; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! no edit here
 
#Persistent
#SingleInstance
SendMode Input              ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.

if A_OSVersion in WIN_NT4,WIN_95,WIN_98,WIN_ME  ; if not xp or 2000 quit
{
    MsgBox This script requires Windows 2000/XP or later.
    ExitApp
}

; ===============
  version = Genmce_Generic_Midi_App_   ; Change this to suit you.
; ===============

readini()                       ; load values from the ini file, via the readini function - see below.
gosub, MidiPortRefresh          ; used to refresh the input and output port lists - see label below
port_test(numports,numports2)   ; test the ports - check for valid ports?
gosub, midiin_go                ; opens the midi input port listening routine
gosub, midiout                  ; opens the midi out port   
gosub, midiMon                  ; see below - a monitor gui - for learning mostly - you will probably comment this out eventually.
; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! end edit here

; =============== set variables you may use in MidiRules section

cc_msg = 73,74 ; ++++++++++++++++ you might want to add other vars that load in auto execute section  This example goes with

; varibles below are for keyboarcc
channel = 1     ; default channel =1
ccnum = 7       ; 7 is volume
volVal = 0     ; Default zero for volume
volDelta = 10  ; Amount to change volume
; end of vars for hotkey and keyboardcc

/*
  yourVar = 0
  yourVarDelta = 3
  yourVarCCnum = 1 ; modwheel
*/

settimer, KeyboardCCs, 70 ; timer to run the KeyboardCCs at the 70 interval

return ; !!!! no edit here, need this line to end the auto exec section.

; =============== end of auto execute section =====================

/*
  PARSE - LAST MIDI MESSAGE RECEIVED -
*/
; =============== MIDI input MESSAGE PARSE  ===============

; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! no edit below here ....
; don't edit this part!
MidiMsgDetect(hInput, midiMsg, wMsg) ; Midi input section in "under the hood" calls this function each time a midi message is received. Then the midi message is broken up into parts for manipulation.  See http://www.midi.org/techspecs/midimessages.php (decimal values).
  {
    global statusbyte, chan, note, cc, byte1, byte2
   
    statusbyte    :=  midiMsg & 0xFF         ; EXTRACT THE STATUS BYTE (WHAT KIND OF MIDI MESSAGE IS IT?)
    chan       := (statusbyte & 0x0f) + 1   ; WHAT MIDI CHANNEL IS THE MESSAGE ON?
    byte1       := (midiMsg >> 8) & 0xFF   ; THIS IS DATA1 VALUE = NOTE NUMBER OR CC NUMBER
    byte2       := (midiMsg >> 16) & 0xFF   ; DATA2 VALUE IS NOTE VELEOCITY OR CC VALUE
           
      ; GUI for midi monitor
      GuiControl,12:, MidiMs, MidiMon:%statusbyte% %chan% %byte1% %byte2% ; MidiMs (green text in gui) in midimon gui below - this is for display you will probably comment this out    evenually.
 
    gosub, MidiRules ; run the subroutine below
   
  } ; end of MidiMsgDetect funciton


; =============== filters/rules subroutine tests

/*
      The MidiRules section is for modifying midi input from some other source.
        *See hotkeys below if you wish to generate midi messages from hotkeys.
     
      Write your own MidiRules and put them in this section.
      Keep rules together under proper section, notes, cc, program change etc.
      Keep them after the statusbyte has been determined.
      Examples for each type of rule will be shown.
      The example below is for note type message.
     
      Remember byte1 for a noteon/off is the note number, byte2 is the velocity of that note.
      example
      ifequal, byte1, 20 ; if the note number coming in is note # 20
        {
          byte1 := (do something in here) ; could be do something to the velocity(byte2)
          gosub, SendNote ; send the note out.
        }
  */

MidiRules: ; write your own rules in here, look for : ++++++ for where you might want to add
           ; stay away from !!!!!!!!!!

  ; =============== Is midi input a Note On or Note off message?  ===============
  if statusbyte between 128 and 159 ; see range of values for notemsg var defined in autoexec section. "in" used because ranges of note on and note off
   { ; beginning of note block
     
      if statusbyte between 144 and 159 ; detect if note message is "note on"
        GuiControl,12:, MidiMsOut, noteOn:%statusbyte% %chan% %byte1% %byte2%  ; display noteOn message in gui
      if statusbyte between 128 and 143 ; detect if note message is "note off"
        GuiControl,12:, MidiMsOut, noteOff:%statusbyte% %chan% %byte1% %byte2%  ; display note off in gui
 
  ; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! above  end of no edit
     
  ; =============== add your note MidiRules here ==; ===============

  /*
      Write your own note filters and put them in this section.
      Remember byte1 for a noteon/off is the note number, byte2 is the velocity of that note.
      example
      ifequal, byte1, 20 ; if the note number coming in is note # 20
        {
          byte1 := (do something in here) ; could be do something to the velocity(byte2)
          gosub, SendNote ; send the note out.
        }
  */
  ; ++++++++++++++++++++++++++++++++ examples of note rules ++++++++++ feel free to add more.
     
     ifequal, byte1, 20 ; if the note number coming in is note # 20
        {
          byte1 := (byte1 +1) ; transpose that note up 1 note number 
          gosub, SendNote ; send the note out.
        }
     
      ifequal, byte1, 30 ; if the note number coming in is note # 30
        {
          send , {NumLock} ; send a keypress when note number 20 is received.
        }
     
      ; a little more complex filter two notes
      if ((byte1 != 60) and (byte1 != 62)) ; if note message is not(!) 60 and not(!) 62 send the note out - ie - do nothing except statements above (note 20 and 30 have things to do) to it.
        {
            gosub, SendNote ; send it out the selected output midi port
            ;msgbox, ,straight note, note %byte1% message, 1 ; this messagebox for testing only.
        }

      IfEqual, byte1, 60 ; if the note number is middle C (60) (you can change this) 
        {
            byte1 := (byte1 + 5) ;transpost up 5 steps
            gosub, SendNote ;(h_midiout, note) ;send a note transposed up 5 notes.
            ;msgbox, ,transpose up 5, note on %byte1% message, 1 ; for testing only - show msgbox for 1 sec
        }
     
      IfEqual, byte1, 62 ; if note on is note number 62 (just another example of note detection)
        {
            byte1 := (byte1 -5) ;transpose down 5 steps
            gosub, SendNote
            ;msgbox, ,transpose down 5, note on %byte1% message, 1 ; for testing only, uncomment if you need it.
        }   
    ; ++++++++++++++++++++++++++++++++ End of examples of note rules  ++++++++++
    } ; end of note block
 
; =============== all cc detection ----
  ; is input cc?
 
  if statusbyte between 176 and 191 ; check status byte for cc 176-191 is the range for CC messages ; !!!!!!!! no edit this line, uykwyad
    {
    ; ++++++++++++++++++++++++++++++++ examples of CC rules ++++++++++ feel free to add more. 
        if byte1 in %cc_msg%
          {
            cc := (byte1 + 3) ; Will change all cc#'s up 3 for a different controller number
            GuiControl,12:, MidiMsOut, CC %statusbyte% %chan% %cc% %byte2%
            ;midiOutShortMsg(h_midiout, statusbyte, cc, byte2)
            gosub, sendCC
          }
        else if byte1 not in %cc_msg% ; if the byte1 value is one of these...
          {
            cc := byte1 ; pass them as is, no change.
            GuiControl,12:, MidiMsOut, CC %statusbyte% %chan% %cc% %byte2%
            gosub, sendCC
          } 
    ; ++++++++++++++++++++++++++++++++ examples of cc rules ends ++++++++++++
    }
 
  ; Is midi input a Program Change?
  if statusbyte between 192 and 208  ; check if message is in range of program change messages for byte1 values. ; !!!!!!!!!!!! no edit
    {
    ; ++++++++++++++++++++++++++++++++ examples of program change rules ++++++++++ 
      ; Sorry I have not created anything for here nor for pitchbends....
     
      GuiControl,12:, MidiMsOut, ProgC:%statusbyte% %chan% %byte1% %byte2%
          gosub, sendPC
          ; need something for it to do here, could be converting to a cc or a note or changing the value of the pc
          ; however, at this point the only thing that happens is the gui change, not midi is output here.
          ; you may want to make a SendPc: label below
    ; ++++++++++++++++++++++++++++++++ examples of program change rules ++++++++++   
    }
  ;msgbox filter triggered
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  end of edit section

Return

; ++++++++++++++++++++++++ hotkeys here +++++++++++++++++++++++++=
/*
  Generate midi messages from computer keyboard (mouse) events.
  Examples below
 
  Each hotkey is defined to change the value of a varible.
  example f12::Vol=U ;  When f12 is pushed down, this will set the value of that varible to U.
  The keyboardcc loop is running every 70, so it detects the change for vol varible and triggers that process.
  See keyboardcc section (where all the work is done).
  f12 up::vol=  ; when f12 is let go, the vol var is set to blank and keyboardcc does nothing.
  Same for f11 except the vol var is either D or blank.
*/

; here are a few examples of adding controller hotkeys.

F12::Vol = U   ;   
f12 up::Vol =
F11::Vol = D   ; Mod wheel down
f11 up::Vol =

/*
; here are two more examples you can add

  F10::yourVar = U   ; set yourVar to U for changing value up
  F10 UP::yourVar =  ; set yourVar blank to stop message generation
  F9::yourVar = D    ; set yourVar to D for changing value down
  f9::yourVar =      ; set yourVar to blank to stop message generation
*/
; ++++++++++++++++++++++++++++++ end hotkey defs ++++++++++++++++++++

; +++++++++++++++++++++++++++++ begin keyboardccs section +++++++++++

  /*
    Process Definitions for hotkey generated midi controllers.
    Unless you are good at arrays (I am not)
    You will need to add three statements like these for each controller you wish to generate from a pair of hotkeys.
  */

KeyboardCCs:

; =============== this is a section for volume control
If Vol = U
  {
    VolVal := VolVal + VolDelta ;see top where vars defined.
    If VolVal > 127   ; check for max value reached
    VolVal:= 127, Vol:=""
    midiOutShortMsg(h_midiout, (channel+175), CCnum, VolVal)    ;  (channel+175 will make the correct statusbyte for cc message) CCnum var defined in autoexec section at top, as   
  }
If Vol = D
  {
    volVal := volVal- volDelta
    If volVal < 0      ; check min value reached.
    VolVal:=0, Vol=""
    midiOutShortMsg(h_midiout, (channel+175), CCnum, VolVal)
  }
if Vol = ; set the var to blank
  {
    ; do nothing.
  }
; =============== end of volume control

;++++++++++++++++++++++++++++++ edit below as needed
/*
; ********* remember you can't use yourVar unless you define it somewhere,
; ********* same goes for yourVarCCnum and yourVarDelta.... see beginning of script where they are commented out but set to be defined.

; examples to be triggered by f9 and f10 defined above but commented out.
; **********

If yourVar = U
  {
    yourVarVal := yourVarVal + yourVarDelta ;see top where vars defined.
    If yourVarVal > 127   ; check for max value reached
    yourVarVal:= 127, yourVar:=""
    midiOutShortMsg(h_midiout, (channel+175), yourVarCCnum, yourVarVal)    ;  yourVarCCnum is defined in autoexec section and yourVarVal is defined in the lines directly above.
  }
If yourVar = D
  {
    yourVarVal := yourVarVal- yourVarDelta
    If yourVarVal < 0      ; check min value reached.
    yourVarVal:=0, yourVar=""
    midiOutShortMsg(h_midiout, (channel+175), yourVarCCnum, yourVarVal)
  }
if yourVar = ; set the var to blank
  {
    ; do nothing.
  }

*/
Return

 ; ========================= end ============================

; =============== Send midi output data =============================

SendNote: ;(h_midiout,Note) ; send out note messages ; this should probably be a funciton but... eh.
  ;{
  GuiControl,12:, MidiMsOutSend, NoteOut:%statusbyte% %chan% %byte1% %byte2%
    ;global chan, EventType, NoteVel
    ;MidiStatus := 143 + chan
    note = %byte1%                                      ; this var is added to allow transpostion of a note
    midiOutShortMsg(h_midiout, statusbyte, note, byte2) ; call the midi funcitons with these params.
Return
 
SendCC: ; not sure i actually did anything changing cc's here but it is possible.

    GuiControl,12:, MidiMsOutSend, CCOut:%statusbyte% %chan% %cc% %byte2%
    midiOutShortMsg(h_midiout, statusbyte, cc, byte2)
    ;MsgBox, 0, ,sendcc triggered , 1
 Return
 
SendPC:
    GuiControl,12:, MidiMsOutSend, ProgChOut:%statusbyte% %chan% %byte1% %byte2%
    midiOutShortMsg(h_midiout, statusbyte, pc, byte2)
 /*
  COULD BE TRANSLATED TO SOME OTHER MIDI MESSAGE BESIDED PROGRAM CHANGE.
 */
Return






; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! no edit below here, unless you know what you are doing.

; =============== midi monitor gui ==========================

midiMon: ;just a simple gui window for a midi monitor of sorts.

  Gui, 12: +LastFound +AlwaysOnTop +Caption +ToolWindow  ; +ToolWindow avoids a taskbar button and an alt-tab menu item.
  Gui,12: Color, white ; %CustomColor% ;blue ;
  Gui,12: Font, s15 ; Set a large font size (32-point).
  Gui,12: Add, Text, w250 vMidiMs cgreen, XXXXX YYYYY  ; XX & YY serve to auto-size the window.
  gui, 12: add, text, w250 vMidiMsOut cblue, XXXXX YYYYY
  gui, 12: add, text, w250 vMidiMsOutSend cred, XXXXX YYYYY
  Gui,12: Show, xcenter y0 w500 NoActivate, %version% Midi Monitor - thingy  ; NoActivate avoids deactivating the currently active window.

; ===============  end monitor gui
;****************************************************************************************************************
;******************************************** midi "under the hood" *********************************************
/*
    This part is meant to take care of the "under the hood" midi input and output selection and save selection to an ini file.
    Hopefully it simplifies usage for others out here trying to do things with midi and ahk.
   
    * use it as an include.
   
    The code here was taken/modified from the work by TomB/Lazslo on Midi Output
        http://www.autohotkey.com/forum/viewtopic.php?t=18711&highlight=midi+output
   
    Orbik's Midi input thread
        http://www.autohotkey.com/forum/topic30715.html
        This method does NOT use the midi_in.dll, it makes direct calls to the winmm.dll
       
    Many different people took part in the creation of this file.
   
    ; Last edited 6/17/2010 11:30 AM by genmce

*/

MidiPortRefresh: ; get the list of ports

 MIlist := MidiInsList(NumPorts)
   Loop Parse, MIlist, |
      {
      }
   TheChoice := MidiInDevice + 1

MOlist := MidiOutsList(NumPorts2)
   Loop Parse, MOlist, |
      {
      }
   TheChoice2 := MidiOutDevice + 1

return

;-----------------------------------------------------------------

ReadIni() ; also set up the tray Menu
  {
    Menu, tray, add, MidiSet            ; set midi ports tray item
    Menu, tray, add, ResetAll           ; Delete the ini file for testing --------------------------------

    global MidiInDevice, MidiOutDevice, version ; version var is set at the beginning.
    IfExist, %version%io.ini
      {
        IniRead, MidiInDevice, %version%io.ini, Settings, MidiInDevice , %MidiInDevice%     ; read the midi In port from ini file
        IniRead, MidiOutDevice, %version%io.ini, Settings, MidiOutDevice , %MidiOutDevice%  ; read the midi out port from ini file
      }
    Else ; no ini exists and this is either the first run or reset settings.
      {
        MsgBox, 1, No ini file found, Select midi ports?
        IfMsgBox, Cancel
          ExitApp
        IfMsgBox, yes
          gosub, midiset
        ;WriteIni()
      }
  }

;CALLED TO UPDATE INI WHENEVER SAVED PARAMETERS CHANGE
WriteIni()
  {
    global MidiInDevice, MidiOutDevice, version
   
    IfNotExist, %version%io.ini ; if no ini
      FileAppend,, %version%io.ini ; make one with the following entries.
    IniWrite, %MidiInDevice%, %version%io.ini, Settings, MidiInDevice
    IniWrite, %MidiOutDevice%, %version%io.ini, Settings, MidiOutDevice
  }

;------------ port testing to make sure selected midi port is valid --------------------------------

port_test(numports,numports2) ; confirm selected ports exist ; CLEAN THIS UP STILL

  {
    global midiInDevice, midiOutDevice, midiok
   
    ; ----- In port selection test based on numports
    If MidiInDevice not Between 0 and %numports%
      {
        MidiIn := 0 ; this var is just to show if there is an error - set if the ports are valid = 1, invalid = 0
            ;MsgBox, 0, , midi in port Error ; (this is left only for testing)
        If (MidiInDevice = "")              ; if there is no midi in device
            MidiInerr = Midi In Port EMPTY. ; set this var = error message
            ;MsgBox, 0, , midi in port EMPTY
        If (midiInDevice > %numports%)          ; if greater than the number of ports on the system.
            MidiInnerr = Midi In Port Invalid.  ; set this error message
            ;MsgBox, 0, , midi in port out of range
      }
    Else
      {
        MidiIn := 1 ; setting var to non-error state or valid
      }
    ; ----- out port selection test based on numports2
    If  MidiOutDevice not Between 0 and %numports2%
      {
        MidiOut := 0 ; set var to 0 as Error state.
        If (MidiOutDevice = "")                 ; if blank
            MidiOuterr = Midi Out Port EMPTY.   ; set this error message
            ;MsgBox, 0, , midi o port EMPTY
        If (midiOutDevice > %numports2%)             ; if greater than number of availble ports 
            MidiOuterr = Midi Out Port Out Invalid.  ; set this error message   
            ;MsgBox, 0, , midi out port out of range
      }
    Else
      {
        MidiOut := 1 ;set var to 1 as valid state.
      }
      ; ---- test to see if ports valid, if either invalid load the gui to select.
      ;midicheck(MCUin,MCUout)
    If (%MidiIn% = 0) Or (%MidiOut% = 0)
      {
        MsgBox, 49, Midi Port Error!,%MidiInerr%`n%MidiOuterr%`n`nLaunch Midi Port Selection!
        IfMsgBox, Cancel
          ExitApp
        midiok = 0 ; Not sure if this is really needed now....
        Gosub, MidiSet ;Gui, show Midi Port Selection
      }
    Else
      {
        midiok = 1
        Return ; DO NOTHING - PERHAPS DO THE NOT TEST INSTEAD ABOVE.
      }
  }
Return

; ------------------ end of port testing ---------------------------


MidiSet: ; midi port selection gui
 
 ; ------------- MIDI INPUT SELECTION -----------------------
  ;Gui, Destroy
  ;Gosub, Suspendit
  Gui, 6: Destroy
  Gui, 2: Destroy
  Gui, 3: Destroy
  Gui, 4: Destroy
  ;Gui, 5: Destroy
  Gui, 4: +LastFound +AlwaysOnTop   +Caption +ToolWindow ;-SysMenu
  Gui, 4: Font, s12
  Gui, 4: add, text, x10 y10 w300 cmaroon, Select Midi Ports. ; Text title
  Gui, 4: Font, s8
  Gui, 4: Add, Text, x10 y+10 w175 Center , Midi In Port  ;Just text label
  Gui, 4: font, s8
  ; midi ins list box
  Gui, 4: Add, ListBox, x10 w200 h100  Choose%TheChoice% vMidiInPort gDoneInChange AltSubmit, %MiList% ; --- midi in listing of ports
    ;Gui,  Add, DropDownList, x10 w200 h120 Choose%TheChoice% vMidiInPort gDoneInChange altsubmit, %MiList%  ; ( you may prefer this style, may need tweak)

  ; --------------- MidiOutSet ---------------------
  Gui, 4: Add, TEXT,  x220 y40 w175 Center, Midi Out Port ; gDoneOutChange
  ; midi outlist box
  Gui, 4: Add, ListBox, x220 y62 w200 h100 Choose%TheChoice2% vMidiOutPort gDoneOutChange AltSubmit, %MoList% ; --- midi out listing
  ;Gui,  Add, DropDownList, x220 y97 w200 h120 Choose%TheChoice2% vMidiOutPort gDoneOutChange altsubmit , %MoList%
  Gui, 4: add, Button, x10 w205 gSet_Done, Done - Reload script.
  Gui, 4: add, Button, xp+205 w205 gCancel, Cancel
  ;gui, 4: add, checkbox, x10 y+10 vNotShown gDontShow, Do Not Show at startup.
  ;IfEqual, NotShown, 1
  ;guicontrol, 4:, NotShown, 1
  Gui, 4: show , , %version% Midi Port Selection ; main window title and command to show it.

Return

;-----------------gui done change stuff - see label in both gui listbox line

DoneInChange:
  Gui, 4: Submit, NoHide
  Gui, 4: Flash
  If %MidiInPort%
      UDPort:= MidiInPort - 1, MidiInDevice:= UDPort ; probably a much better way do this, I took this from JimF's qwmidi without out editing much.... it does work same with doneoutchange below.
  GuiControl, 4:, UDPort, %MidiIndevice%
  WriteIni()
  ;MsgBox, 32, , midi in device = %MidiInDevice%`nmidiinport = %MidiInPort%`nport = %port%`ndevice= %device% `n UDPort = %UDport% ; only for testing
Return

DoneOutChange:
  Gui, 4: Submit, NoHide
  Gui, 4: Flash
  If %MidiOutPort%
      UDPort2:= MidiOutPort - 1 , MidiOutDevice:= UDPort2
  GuiControl, 4: , UDPort2, %MidiOutdevice%
  WriteIni()
  ;Gui, Destroy
Return

;------------------------ end of the doneout change stuff.

Set_Done: ;  aka reload program, called from midi selection gui
  Gui, 3: Destroy
  Gui, 4: Destroy
   sleep, 100
  Reload
Return

Cancel:
  Gui, Destroy
  Gui, 2: Destroy
  Gui, 3: Destroy
  Gui, 4: Destroy
  Gui, 5: Destroy
Return

; ********************** Midi output detection

MidiOut: ; Function to load new settings from midi out menu item
  OpenCloseMidiAPI()
  h_midiout := midiOutOpen(MidiOutDevice) ; OUTPUT PORT 1 SEE BELOW FOR PORT 2
return

ResetAll: ; for development only, leaving this in for a program reset if needed by user
  MsgBox, 33, %version% - Reset All?, This will delete ALL settings`, and restart this program!
  IfMsgBox, OK
    {
      FileDelete, %version%io.ini   ; delete the ini file to reset ports, probably a better way to do this ...
      Reload                        ; restart the app.
    }
  IfMsgBox, Cancel
Return

GuiClose: ; on x exit app
  Suspend, Permit ; allow Exit to work Paused. I just added this yesterday 3.16.09 Can now quit when Paused.
 
  MsgBox, 4, Exit %version%, Exit %version% %ver%? ;
  IfMsgBox No
      Return
  Else IfMsgBox Yes
      midiOutClose(h_midiout)
   
  Gui, 6: Destroy
  Gui, 2: Destroy
  Gui, 3: Destroy
  Gui, 4: Destroy
  Gui, 5: Destroy
  gui, 7: destroy
 ;gui,
 Sleep 100
  ;winclose, Midi_in_2 ;close the midi in 2 ahk file
 ExitApp


;############################################## MIDI LIB from orbik and lazslo#############
;-------- orbiks midi input code --------------
; Set up midi input and callback_window based on the ini file above.
; This code copied from ahk forum Orbik's post on midi input

; nothing below here to edit.

; =============== midi in =====================

Midiin_go:
DeviceID := MidiInDevice      ; midiindevice from IniRead above assigned to deviceid
CALLBACK_WINDOW := 0x10000    ; from orbiks code for midi input

Gui, +LastFound    ; set up the window for midi data to arrive.
hWnd := WinExist()   ;MsgBox, 32, , line 176 - mcu-input  is := %MidiInDevice% , 3 ; this is just a test to show midi device selection

hMidiIn =
VarSetCapacity(hMidiIn, 4, 0)
  result := DllCall("winmm.dll\midiInOpen", UInt,&hMidiIn, UInt,DeviceID, UInt,hWnd, UInt,0, UInt,CALLBACK_WINDOW, "UInt")
    If result
      {
        MsgBox, Error, midiInOpen Returned %result%`n
        ;GoSub, sub_exit
      }

hMidiIn := NumGet(hMidiIn) ; because midiInOpen writes the value in 32 bit binary Number, AHK stores it as a string
  result := DllCall("winmm.dll\midiInStart", UInt,hMidiIn)
    If result
      {
        MsgBox, Error, midiInStart Returned %result%`nRight Click on the Tray Icon - Left click on MidiSet to select valid midi_in port.
        ;GoSub, sub_exit
      }

OpenCloseMidiAPI()
 
  ; ----- the OnMessage listeners ----

      ; #define MM_MIM_OPEN 0x3C1 /* MIDI input */
      ; #define MM_MIM_CLOSE 0x3C2
      ; #define MM_MIM_DATA 0x3C3
      ; #define MM_MIM_LONGDATA 0x3C4
      ; #define MM_MIM_ERROR 0x3C5
      ; #define MM_MIM_LONGERROR 0x3C6

    OnMessage(0x3C1, "MidiMsgDetect")  ; calling the function MidiMsgDetect in get_midi_in.ahk
    OnMessage(0x3C2, "MidiMsgDetect") 
    OnMessage(0x3C3, "MidiMsgDetect")
    OnMessage(0x3C4, "MidiMsgDetect")
    OnMessage(0x3C5, "MidiMsgDetect")
    OnMessage(0x3C6, "MidiMsgDetect")

Return

;--- MIDI INS LIST FUNCTIONS - port handling -----

MidiInsList(ByRef NumPorts)
  { ; Returns a "|"-separated list of midi output devices
    local List, MidiInCaps, PortName, result
    VarSetCapacity(MidiInCaps, 50, 0)
    VarSetCapacity(PortName, 32)                       ; PortNameSize 32

    NumPorts := DllCall("winmm.dll\midiInGetNumDevs") ; #midi output devices on system, First device ID = 0

    Loop %NumPorts%
      {
        result := DllCall("winmm.dll\midiInGetDevCapsA", UInt,A_Index-1, UInt,&MidiInCaps, UInt,50, UInt)
        If (result OR ErrorLevel) {
            List .= "|-Error-"
            Continue
          }
        DllCall("RtlMoveMemory", Str,PortName, UInt,&MidiInCaps+8, UInt,32) ; PortNameOffset 8, PortNameSize 32
        List .= "|" PortName
      }
    Return SubStr(List,2)
  }

MidiInGetNumDevs() { ; Get number of midi output devices on system, first device has an ID of 0
    Return DllCall("winmm.dll\midiInGetNumDevs")
  }
MidiInNameGet(uDeviceID = 0) { ; Get name of a midiOut device for a given ID

    ;MIDIOUTCAPS struct
    ;    WORD      wMid;
    ;    WORD      wPid;
    ;    MMVERSION vDriverVersion;
    ;    CHAR      szPname[MAXPNAMELEN];
    ;    WORD      wTechnology;
    ;    WORD      wVoices;
    ;    WORD      wNotes;
    ;    WORD      wChannelMask;
    ;    DWORD     dwSupport;

    VarSetCapacity(MidiInCaps, 50, 0)  ; allows for szPname to be 32 bytes
    OffsettoPortName := 8, PortNameSize := 32
    result := DllCall("winmm.dll\midiInGetDevCapsA", UInt,uDeviceID, UInt,&MidiInCaps, UInt,50, UInt)

    If (result OR ErrorLevel) {
        MsgBox Error %result% (ErrorLevel = %ErrorLevel%) in retrieving the name of midi Input %uDeviceID%
        Return -1
      }

    VarSetCapacity(PortName, PortNameSize)
    DllCall("RtlMoveMemory", Str,PortName, Uint,&MidiInCaps+OffsettoPortName, Uint,PortNameSize)
    Return PortName
  }

MidiInsEnumerate() { ; Returns number of midi output devices, creates global array MidiOutPortName with their names
    local NumPorts, PortID
    MidiInPortName =
    NumPorts := MidiInGetNumDevs()

    Loop %NumPorts% {
        PortID := A_Index -1
        MidiInPortName%PortID% := MidiInNameGet(PortID)
      }
    Return NumPorts
  }


; =============== end of midi selection stuff


MidiOutsList(ByRef NumPorts)
  { ; Returns a "|"-separated list of midi output devices
    local List, MidiOutCaps, PortName, result
    VarSetCapacity(MidiOutCaps, 50, 0)
    VarSetCapacity(PortName, 32)                       ; PortNameSize 32

    NumPorts := DllCall("winmm.dll\midiOutGetNumDevs") ; #midi output devices on system, First device ID = 0

    Loop %NumPorts%
      {
        result := DllCall("winmm.dll\midiOutGetDevCapsA", UInt,A_Index-1, UInt,&MidiOutCaps, UInt,50, UInt)
        If (result OR ErrorLevel)
          {
            List .= "|-Error-"
            Continue
          }
        DllCall("RtlMoveMemory", Str,PortName, UInt,&MidiOutCaps+8, UInt,32) ; PortNameOffset 8, PortNameSize 32
        List .= "|" PortName
      }
    Return SubStr(List,2)
  }
;---------------------midiOut from TomB and Lazslo and JimF --------------------------------

;THATS THE END OF MY STUFF (JimF) THE REST ID WHAT LASZLo AND PAXOPHONE WERE USING ALREADY
;AHK FUNCTIONS FOR MIDI OUTPUT - calling winmm.dll
;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_multimedia_functions.asp
;Derived from Midi.ahk dated 29 August 2008 - streaming support removed - (JimF)


OpenCloseMidiAPI() {  ; at the beginning to load, at the end to unload winmm.dll
    static hModule
    If hModule
        DllCall("FreeLibrary", UInt,hModule), hModule := ""
    If (0 = hModule := DllCall("LoadLibrary",Str,"winmm.dll")) {
        MsgBox Cannot load libray winmm.dll
        Exit
      }
  }

;FUNCTIONS FOR SENDING SHORT MESSAGES

midiOutOpen(uDeviceID = 0) { ; Open midi port for sending individual midi messages --> handle
    strh_midiout = 0000

    result := DllCall("winmm.dll\midiOutOpen", UInt,&strh_midiout, UInt,uDeviceID, UInt,0, UInt,0, UInt,0, UInt)
    If (result or ErrorLevel) {
        MsgBox There was an Error opening the midi port.`nError code %result%`nErrorLevel = %ErrorLevel%
        Return -1
      }
    Return UInt@(&strh_midiout)
  }

midiOutShortMsg(h_midiout, MidiStatus,  Param1, Param2) { ;Channel,
    ;h_midiout: handle to midi output device returned by midiOutOpen
    ;EventType, Channel combined -> MidiStatus byte: http://www.harmony-central.com/MIDI/Doc/table1.html
    ;Param3 should be 0 for PChange, ChanAT, or Wheel
    ;Wheel events: entire Wheel value in Param2 - the function splits it into two bytes
/*
    If (EventType = "NoteOn" OR EventType = "N1")
        MidiStatus := 143 + Channel
    Else If (EventType = "NoteOff" OR EventType = "N0")
        MidiStatus := 127 + Channel
    Else If (EventType = "CC")
        MidiStatus := 175 + Channel
    Else If (EventType = "PolyAT"  OR EventType = "PA")
        MidiStatus := 159 + Channel
    Else If (EventType = "ChanAT"  OR EventType = "AT")
        MidiStatus := 207 + Channel
    Else If (EventType = "PChange" OR EventType = "PC")
        MidiStatus := 191 + Channel
    Else If (EventType = "Wheel"   OR EventType = "W") {
        MidiStatus := 223 + Channel
        Param2 := Param1 >> 8      ; MSB of wheel value
        Param1 := Param1 & 0x00FF  ; strip MSB
      }
*/
    result := DllCall("winmm.dll\midiOutShortMsg", UInt,h_midiout, UInt, MidiStatus|(Param1<<8)|(Param2<<16), UInt)
    If (result or ErrorLevel)  {
        MsgBox There was an Error Sending the midi event: (%result%`, %ErrorLevel%)
        Return -1
      }
  }

midiOutClose(h_midiout) {  ; Close MidiOutput
    Loop 9 {
        result := DllCall("winmm.dll\midiOutClose", UInt,h_midiout)
        If !(result or ErrorLevel)
            Return
        Sleep 250
      }
    MsgBox Error in closing the midi output port. There may still be midi events being Processed.
    Return -1
  }

;UTILITY FUNCTIONS
MidiOutGetNumDevs() { ; Get number of midi output devices on system, first device has an ID of 0
    Return DllCall("winmm.dll\midiOutGetNumDevs")
  }

MidiOutNameGet(uDeviceID = 0) { ; Get name of a midiOut device for a given ID

    ;MIDIOUTCAPS struct
    ;    WORD      wMid;
    ;    WORD      wPid;
    ;    MMVERSION vDriverVersion;
    ;    CHAR      szPname[MAXPNAMELEN];
    ;    WORD      wTechnology;
    ;    WORD      wVoices;
    ;    WORD      wNotes;
    ;    WORD      wChannelMask;
    ;    DWORD     dwSupport;

    VarSetCapacity(MidiOutCaps, 50, 0)  ; allows for szPname to be 32 bytes
    OffsettoPortName := 8, PortNameSize := 32
    result := DllCall("winmm.dll\midiOutGetDevCapsA", UInt,uDeviceID, UInt,&MidiOutCaps, UInt,50, UInt)

    If (result OR ErrorLevel) {
        MsgBox Error %result% (ErrorLevel = %ErrorLevel%) in retrieving the name of midi output %uDeviceID%
        Return -1
      }

    VarSetCapacity(PortName, PortNameSize)
    DllCall("RtlMoveMemory", Str,PortName, Uint,&MidiOutCaps+OffsettoPortName, Uint,PortNameSize)
    Return PortName
  }

MidiOutsEnumerate() { ; Returns number of midi output devices, creates global array MidiOutPortName with their names
    local NumPorts, PortID
    MidiOutPortName =
    NumPorts := MidiOutGetNumDevs()

    Loop %NumPorts% {
        PortID := A_Index -1
        MidiOutPortName%PortID% := MidiOutNameGet(PortID)
      }
    Return NumPorts
  }

UInt@(ptr) {
Return *ptr | *(ptr+1) << 8 | *(ptr+2) << 16 | *(ptr+3) << 24
}

PokeInt(p_value, p_address) { ; Windows 2000 and later
    DllCall("ntdll\RtlFillMemoryUlong", UInt,p_address, UInt,4, UInt,p_value)
}

It is very lengthy and complexed, so your choices at this point would be; study the code and convert only what you need into AutoIt format, convert the complete code, or download the other program and use it.

Link to comment
Share on other sites

  • 2 months later...

Sorry to revive this topic but I was really wondering whether you actually succeeded to write some autoit code for midi interaction already that I could use as an example. If not, then I'll have to look into DLL stuff myself, that will also be my first time :graduated:

Roses are FF0000, violets are 0000FF... All my base are belong to you.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...