AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

MIDI IN support in AutoHotkey
Goto page Previous  1, 2, 3, 4, 5  Next
 
Reply to topic    AutoHotkey Community Forum Index -> Wish List
View previous topic :: View next topic  
Author Message
fridemar



Joined: 16 Aug 2006
Posts: 16

PostPosted: Tue Dec 12, 2006 11:38 am    Post subject: DLL is wonderful, but consider KeyKit too. Reply with quote

Zed Gecko wrote:
regarding this topic, i found a webpage:
http://www.logosfoundation.org/gmt/gmt_midi.html

I donīt understand a lot of it, but it seems to me,
that it contains the sourcecode for a dll, which handles
MIDI In/Output. It says that i can be compiled in C or in C++.
I have no experience with any of this, but maybe someone
else could look at this and make us a usable dll


I have added another approach, that can inspire the DLL people or even develop into another standalone option.

As peer developers for open software are a rare resource, I bridge the scattered fragments of Midi programming activities that combine Midi with Macros by means of links and social bookmarking/ annotations:

See http://www.autohotkey.com/forum/viewtopic.php?p=94203#94203
_________________
http://aboutUs.org/fridemar
Let's amplify each other's light Smile
Back to top
View user's profile Send private message Visit poster's website
automaticman



Joined: 27 Oct 2006
Posts: 648

PostPosted: Sat Dec 23, 2006 5:00 pm    Post subject: Reply with quote

I want also midi support in AutoHotkey without having to use KeyKit. (But in my case it doesn't matter much as I'm already a KeyKit user Laughing )
Back to top
View user's profile Send private message
Dookie
Guest





PostPosted: Fri Mar 30, 2007 5:53 am    Post subject: Reply with quote

i'd like to have midi in support too! pls integrate it into the great ahk tool!!
Back to top
Guest






PostPosted: Fri Apr 13, 2007 12:54 pm    Post subject: Reply with quote

just a quick thought, and one that I don't really have either the time or the knowledge to follow up on properly.

Couldn't DllCall be used to allow midi functions. I was under the impression that midi is part of the Windows API?

Matt
Back to top
TomB



Joined: 14 Jan 2005
Posts: 17

PostPosted: Fri Apr 27, 2007 8:26 pm    Post subject: Reply with quote

For those interested - I have Midi output working from AHK, but not Midi input. See this thread:

http://www.autohotkey.com/forum/viewtopic.php?p=118404#118404

TomB
Back to top
View user's profile Send private message
Anatoly Larkin



Joined: 28 Nov 2004
Posts: 32
Location: USA

PostPosted: Thu Jul 26, 2007 4:22 am    Post subject: Reply with quote

We should try to continue with developing this Midi In feature.

Surely the way C programs can be made to listen to the incoming Midi messages and respond to them is translatable into the way AHK does things.

This is going back to the original idea described in the beginning of this thread whereby a midi message can be used as a hotkey.

The way that AHK "listens" for key presses, can't it also "listen" for Midi In?
(using the required DLL)
_________________
||||
------
!!
Back to top
View user's profile Send private message
Anatoly Larkin



Joined: 28 Nov 2004
Posts: 32
Location: USA

PostPosted: Thu Jul 26, 2007 5:47 am    Post subject: Reply with quote

Here is another try at using DllCall and my problem - please help me, if you see how.


I want to do something simple first: open then close midiIn device.

So, to begin with:
Code:

h_midiin := "0000" ; Important!

result := DllCall("winmm.dll\midiInOpen"
               , UInt, &h_midiin
         , UInt, 0 ;; uDeviceID
         , UInt, 0
            , UInt, 0
           , UInt, 0 ;; dwFlags - set to CALLBACK_NULL (0)
          , "UInt")


So far so good.
h_midiin is set with a "handle" to my midiIn device, since midiInOpen expects a pointer to the variable (to which we allocated space through h_midiin = "0000".

By using *(&h_midiin + offset) I can see that the 4 bytes of this handle are set as following 32, 65, 5, 0.

To me this signifies that this "handle" = 0x20410500 = 541132032 in decimal.


Well, so then to close this open device I need to supply midiInClose function with this handle (not the pointer to the handle, but the actual handle). So I first calculate that handle value above by this convoluted manner:


Code:

midi_in_handle_uint0 := *(&h_midiin + 0)
midi_in_handle_uint1 := *(&h_midiin + 1)
midi_in_handle_uint2 := *(&h_midiin + 2)
midi_in_handle_uint3 := *(&h_midiin + 3)

midi_in_handle_uint := midi_in_handle_uint0 * 16777216 + midi_in_handle_uint1 * 65536 + midi_in_handle_uint2 * 256 + midi_in_handle_uint3




That gets me that 541132032 value.

So then I pass it to the midiInClose function:

Code:

   result := DllCall("winmm.dll\midiInClose"
               , UInt, midi_in_handle_uint)



But my result = 5, rather than 0.

"5" means MMSYSERR_INVALHANDLE. It thinks that I passed it a bad value.

Can you point out where I am failing, please?

...
And I solved my own problem, it seems.

I figured, what if the handle value is big, rather than little endian?

So, I just reversed my byte order above, and it worked!

correct way to translate my h_midiin handle into uint should be:


Code:

midi_in_handle_uint3 := *(&h_midiin + 0)
midi_in_handle_uint2 := *(&h_midiin + 1)
midi_in_handle_uint1 := *(&h_midiin + 2)
midi_in_handle_uint0 := *(&h_midiin + 3)

midi_in_handle_uint := midi_in_handle_uint0 * 16777216 + midi_in_handle_uint1 * 65536 + midi_in_handle_uint2 * 256 + midi_in_handle_uint3



This is great news, because it means I can now proceed with looping inside my midi in AHK function and "listen" for input, and respond accordingly. (Of course, it means that I can't use anyother AHK function in my script....)

We'll see what happens.
_________________
||||
------
!!
Back to top
View user's profile Send private message
Anatoly Larkin



Joined: 28 Nov 2004
Posts: 32
Location: USA

PostPosted: Sun Jul 29, 2007 3:07 am    Post subject: RegisterCallback Reply with quote

I just noticed that "RegisterCallback" function was created in the 19th of July release.
For Midi In to work, one has to register a so called "Callback" midi "listening" procedure, so that it can pass midi messages to the program.
I am still trying to understand how to implement it myself (even though I have written c code in the past that used Paul Messick's(1998) dll to capture incoming midi messages, and it worked fine).
Here is the relevant link on msdn2:

http://msdn2.microsoft.com/en-us/library/ms711612.aspx

I have a feeling that we can create some kind of AHK function that would be able to get us the midi values from the midi in driver.

Not sure how to do it yet, but maybe someone will beat me to it.
_________________
||||
------
!!
Back to top
View user's profile Send private message
Anatoly Larkin



Joined: 28 Nov 2004
Posts: 32
Location: USA

PostPosted: Sun Jul 29, 2007 5:10 am    Post subject: Midi In Programming in AHK - initial attempt Reply with quote

Here is the first try for what it's worth.

I am still missing something crucial to make it work, but something is happening already.

I included comentary in my code.

Basically, I used RegisterCallback() to create a reference to my ProcessMidiIn() function (a separate piece of code, at the bottom)

Code:

;12:32 AM 7/26/2007


;I am going to work on developing a midi in support in this function


MidiIn()
{

   skip_if = 0

   ; first we need to open the MidiIn driver
/*
MMRESULT midiOutOpen(
  LPHMIDIOUT lphmo,             
  UINT_PTR   uDeviceID,         
  DWORD_PTR  dwCallback,         
  DWORD_PTR  dwCallbackInstance,
  DWORD      dwFlags             
);
*/


/*
MMRESULT midiInOpen(
  LPHMIDIIN lphMidiIn,         
  UINT_PTR  uDeviceID,         
  DWORD_PTR dwCallback,         
  DWORD_PTR dwCallbackInstance,
  DWORD     dwFlags             
);
*/
   ;; initializing variables

   h_midiin := "0000" ; Important!
   dw_call_back_uint := "0000" ; probably unnecessary

   ;; registering the "MidiInProc" callback function
   ;; see http://msdn2.microsoft.com/en-us/library/ms711612.aspx

   dw_call_back_uint := RegisterCallback("ProcessMidiIn")
   msgbox after using RegisterCallback dw_call_back_uint = %dw_call_back_uint%


   ;; trying to open midi in device below
   
   msgbox we begin by opening midi in device
   result := DllCall("winmm.dll\midiInOpen"
               , UInt, &h_midiin
         , UInt, 0 ;; uDeviceID
         , UInt, dw_call_back_uint
            , UInt, 0
           , UInt, 196608 ;; dwFlags - set to CALLBACK_NULL (0)
              ;; 196608 = CALLBACK_FUNCTION flag
         
          , "UInt")
   ;; at this point my Callback Function gets called
   msgbox midiInOpen returned `n`n%result% `n`nif 0, everything is fine - it opened

   ;; midiInOpen can return the following:
   ;;  MMSYSERR_ALLOCATED The specified resource is already allocated. ---->MMSYSERR_BASE + 4
   ;;  MMSYSERR_BADDEVICEID The specified device identifier is out of range. --->(MMSYSERR_BASE + 2)
   ;;  MMSYSERR_INVALFLAG The flags specified by dwFlags are invalid. --->(MMSYSERR_BASE + 10)
   ;;  MMSYSERR_INVALPARAM The specified pointer or structure is invalid. -->(MMSYSERR_BASE + 11)
   ;;  MMSYSERR_NOMEM The system is unable to allocate or lock memory.    --->(MMSYSERR_BASE + 7) 

   if (result != 0)
   {
      ;; we don't want to continue with this
      skip_if = 1
      msgbox returning from midi_in() since there was a problem
   }

   if (skip_if == 0)
   {
      ;; msgbox h_midiin handle now points to something `n%h_midiin%
      ;; we should translate this to an actual number.
      ;; so, the convoluted translation code follows
      ;; it needs to be cleaned up someday

      midi_in_handle_uint3 := *(&h_midiin + 0)
      midi_in_handle_uint2 := *(&h_midiin + 1)
      midi_in_handle_uint1 := *(&h_midiin + 2)
      midi_in_handle_uint0 := *(&h_midiin + 3)
   
      midi_in_handle_uint := midi_in_handle_uint0 * 16777216 + midi_in_handle_uint1 * 65536 + midi_in_handle_uint2 * 256 + midi_in_handle_uint3
      msgbox h_midiout as uint = %midi_in_handle_uint%   

      ;; now we need to "listen" for incoming midi in messages
      ;; but how?
      ;; what is this MidiInProc "callback" function?
      ;; How does this all work?
   
      ;; also we need to "start" that midi in device, after
       ;; we open it, I think.

      ; now we try to "start midi in device"
      
      msgbox We're going to start midi in device now
      result := DllCall("winmm.dll\midiInStart"
                  , UInt, midi_in_handle_uint)

      ;; at this point the Callback Function   
      ;; is called. 
      msgbox midiInStart returned %result%

      msgbox We're now going to Reset midi in device
      result := DllCall("winmm.dll\midiInReset"
                  , UInt, midi_in_handle_uint)   
   
      ;; at this point something goes wrong, because
      ;; we don't get to the "MsgBox" line below
      ;; .... why?
      ;; Where is it stuck?
      ;; ...
      ;; Oh, I see.
      ;; as long as I don't display a msgbox
      ;; in response to the Yamaha Sync message (0xFE)
      ;; that gets transmitted every 300ms from my keyboard.
      ;;
      ;; So, now that I have added a little "if != 254" in my
      ;; ProcessMidiIn callback function, everything is fine.
      ;; The function runs as it should.
      ;; However, if, while the msgbox for
      ;; "midiInStart returned ..." is up on screen, and I press
      ;; some note on the keyboard, then ProcessMidiIn
      ;; is called anyway, and the MsgBox there comes up
      ;; and the same "infinite loop" stuck behavior is observed.
      ;;
      ;; Ok, lets try to change it to a tooltip
      ;; and see if this changes anything.
      ;; Obviously, MsgBox is not a problem when we open
      ;; the device at the top.
      ;; No, Changing to Tooltip didn't make a difference.
      ;;
      ;; Obviously, as events arrive to Midi In port, they   
      ;; get stored in some buffer, I guess and, perhaps,
      ;; I need to somehow get at that buffer?
      ;;
      ;; I am still not sure where exactly my program is    
      ;; getting stuck.
      ;; So far, as long as I don't press any keys
      ;; it opens and closes just fine.
      ;; But if I do press some keys (adding them to this buffer
      ;; somewhere) I don't get past midiInReset call


      msgbox midiInReset returned %result%

      loop
      {
         ;; I am probably going to have to use this loop at some point, but for now I have break here to skip out of it
         
         break   
      }

      ; msgbox we are now going to close Midi In device through midiInClose call



      msgbox now stopping midi in device      
      result := DllCall("winmm.dll\midiInStop"
                  , UInt, midi_in_handle_uint)
      msgbox midiInStop returned %result%

      msgbox now closing midi in device
      result := DllCall("winmm.dll\midiInClose"
                  , UInt, midi_in_handle_uint)
      ;; Possible returns
      ;; MMSYSERR_NOERROR (0)
      ;; MIDIERR_STILLPLAYING -> MIDIERR_BASE + 1
      ;; MMSYSERR_INVALHANDLE -> MMSYSERR_BASE + 5
      ;; MMSYSERR_NOMEM -> MMSYSERR_BASE + 7   

      sleep, 100
      msgbox midiInClose returned`n`n%result% `n `n(if 0 - it means everything is fine.  It closed.)
   


   }

   msgbox returning from midi_in()
   return
}



Code:


ProcessMidiIn(h_midi_in, wMsg, dwInstance, dwParam1, dwParam2)
{
   ; I have no idea yet how to use this function

   ;; if dwParam1 = 254, i.e. 0xFE
   ;; it is this YAMAHA sync signal,
   ;; which we need to ignore.
   
   if (dwParam1 != 254)
   {
      Tooltip,
      (Ltrim Join
      ProcessMidiIn function is being called`n
      h_midi_in = %h_midi_in%`n
      wMsg = %wMsg%`n
      dwInstance = %dwInstance%`n
      dwParam1 = %dwParam1%`n
      dwParam2 = %dwParam2%`n
   
      )
   }
   
   return
}

_________________
||||
------
!!
Back to top
View user's profile Send private message
Anatoly Larkin



Joined: 28 Nov 2004
Posts: 32
Location: USA

PostPosted: Sun Jul 29, 2007 6:33 am    Post subject: Reply with quote

Well, more progress, which is getting me somewhere.

In my previous post I made one important mistake.
I must not call GUI functions like Tooltip or MsgBox from within a CALLBACK function (like my ProcessMidiIn()).

It kills it.

So, what I did instead was create a global variable called dwParam1 holder and what I would do is simply add to it any incoming dwParam1 values.

Code:

ProcessMidiIn(h_midi_in, wMsg, dwInstance, dwParam1, dwParam2)
{
   global dwParam1_holder
   ; I have no idea yet how to use this function

   ;; if dwParam1 = 254, i.e. 0xFE
   ;; it is this YAMAHA sync signal,
   ;; which we need to ignore.
   
   if (dwParam1 != 254)
   {
   
      dwParam1_holder = %dwParam1_holder% %dwParam1%
   }
      
   return
}




In the mean time, I also added some code to my Loop:

Code:

      loop
      {
         
         Input, single_key, L1
         if (single_key == "a")
         {
            msgbox %dwParam1_holder%
         }
         if (single_key == "s")
         {
             break   
         }
      }




So, if I wanted to see what my dwParam1 values were, I just press "a".


Also, I removed that midiInReset call before the loop!


I think, it won't be long until I am using my midi keyboard to control things.
_________________
||||
------
!!
Back to top
View user's profile Send private message
Chris
Site Admin


Joined: 02 Mar 2004
Posts: 10716

PostPosted: Mon Jul 30, 2007 3:08 pm    Post subject: Reply with quote

Thanks for posting your progress.
Back to top
View user's profile Send private message Send e-mail
Anatoly Larkin



Joined: 28 Nov 2004
Posts: 32
Location: USA

PostPosted: Mon Jul 30, 2007 5:34 pm    Post subject: Reply with quote

Sure, Chris.

I do hope this helps somewhat, even though I am not a "programming expert" by any means.

I am now able to use my midi keyboard to "type" keys (Send, <key press>) every time I parse the received dwParam1 and find status = 144 (0x90, i.e. midi message Note On) in it, and it works mostly fine.
Since AHK stores numbers as strings, it took some figuring out on my part how to "extract" the right byte.
e.g.
Code:

l_word := dwParam1 & 0xffff


Of course, sometimes things "stop working" and I have to reset the script.

The problem is that, after all, I am having the midi device driver call my ProcessMidiIn CALLBACK function at any moment it receives a midi message.
I then immediately copy the contents to my own global variable (called dwParam1_holder). Then, in my main loop, I parse the contents of this holder and do what I need to do.

In the mean time, if more events have been generated by the keyboard and arrive at the midi driver, it interrupts everything and sends new values to my ProcessMidiIn().

That's where the conflict probably occurs.

If one part of the AHK script is working with a variable when this CALLBACK routine suddenly goes and tries to update this variable, I am sure there is nothing that can be done to prevent the crash.

There is probably a way to "buffer midi messages", and process them in my loop one after another, without ever conflicting with the CALLBACK function.

Let me know if you have any suggestions.

But, if I am careful, and only play one note at a time, I get a pretty reliable response from the script.

I can literally type: "I am typing this from my midi keyboard!"

(I use F#3 as my "LShift" key).
Also, every word gets its own unique melodic signature and since I mapped A-G to the respective keys (A3-G4) on the keyboard, a word like "face" would sound like a fragment of the theme from X-Files (or 2nd mvt from Berlioz's Symphony fantastique) Smile
_________________
||||
------
!!
Back to top
View user's profile Send private message
Galoobus



Joined: 13 Jul 2007
Posts: 8
Location: Sacramento, CA

PostPosted: Mon Jul 30, 2007 9:28 pm    Post subject: Reply with quote

The MIDI hardware available today is just amazing and the costs are totally reasonable. All the knobs, sliders, and keys are valuable input controls that could be used to control anything if AHK could repond to MIDI events. I have always wanted to use this midi hardware for controlling design software such as Photoshop or even to emulate high-end devices used in video production environments. I have always been surprised that someone hasn't already thought of these capabilities.

Another exciting purpose for this would be for use in home or theater automation. Midi sliders could be used to dim lights, automate stage lighting or control remote cameras. Software controls just don't cut it and currently dedicated hardware is astronomically expensive and out of reach for many. It is exciting to see that AHK is coming one step closer to making this a reality. The hardware is there, we just need a way to communicate to and automate it.

I SUPPORT THE AHK MIDI MOVEMENT!!
(and i'm sure many others do to, they just don't know it yet!)
Back to top
View user's profile Send private message
Bryan
Guest





PostPosted: Thu Aug 30, 2007 8:22 pm    Post subject: Reply with quote

Another vote for MIDI input. I would use it for controlling a music notation program.
Back to top
Marco2
Guest





PostPosted: Tue Sep 25, 2007 6:47 pm    Post subject: Reply with quote

Me too!
The natural interaction between an external midi controller/keyboard and a music software doesn't allow pc keypresses, or mouse movements.
They just kill the workflow of a musician.
Hope one day there will be something easy and usable.
BTW bome's midi traslator is a good app, but the midi --> pc key aspect is really far from usable.
Back to top
Display posts from previous:   
Reply to topic    AutoHotkey Community Forum Index -> Wish List All times are GMT
Goto page Previous  1, 2, 3, 4, 5  Next
Page 4 of 5

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group