AutoHotkey Community

It is currently May 25th, 2012, 2:52 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 65 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next
Author Message
PostPosted: December 12th, 2006, 12:38 pm 
Offline

Joined: August 16th, 2006, 9:53 pm
Posts: 16
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/viewtop ... 4203#94203

_________________
http://aboutUs.org/fridemar
Let's amplify each other's light :-)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 23rd, 2006, 6:00 pm 
Offline

Joined: October 27th, 2006, 10:12 am
Posts: 649
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 :lol: )


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 30th, 2007, 6:53 am 
i'd like to have midi in support too! pls integrate it into the great ahk tool!!


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: April 13th, 2007, 1:54 pm 
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


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: April 27th, 2007, 9:26 pm 
Offline

Joined: January 14th, 2005, 5:30 pm
Posts: 17
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


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 26th, 2007, 5:22 am 
Offline

Joined: November 28th, 2004, 10:01 am
Posts: 32
Location: USA
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)

_________________
||||
------
!!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 26th, 2007, 6:47 am 
Offline

Joined: November 28th, 2004, 10:01 am
Posts: 32
Location: USA
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.

_________________
||||
------
!!


Report this post
Top
 Profile  
Reply with quote  
 Post subject: RegisterCallback
PostPosted: July 29th, 2007, 4:07 am 
Offline

Joined: November 28th, 2004, 10:01 am
Posts: 32
Location: USA
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.

_________________
||||
------
!!


Report this post
Top
 Profile  
Reply with quote  
PostPosted: July 29th, 2007, 6:10 am 
Offline

Joined: November 28th, 2004, 10:01 am
Posts: 32
Location: USA
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
}

_________________
||||
------
!!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 29th, 2007, 7:33 am 
Offline

Joined: November 28th, 2004, 10:01 am
Posts: 32
Location: USA
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.

_________________
||||
------
!!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 30th, 2007, 4:08 pm 
Offline

Joined: March 2nd, 2004, 3:36 pm
Posts: 10720
Thanks for posting your progress.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 30th, 2007, 6:34 pm 
Offline

Joined: November 28th, 2004, 10:01 am
Posts: 32
Location: USA
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) :)

_________________
||||
------
!!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 30th, 2007, 10:28 pm 
Offline

Joined: July 13th, 2007, 8:58 pm
Posts: 8
Location: Sacramento, CA
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!)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 30th, 2007, 9:22 pm 
Another vote for MIDI input. I would use it for controlling a music notation program.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: September 25th, 2007, 7:47 pm 
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.


Report this post
Top
  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 65 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 19 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group