 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
fridemar
Joined: 16 Aug 2006 Posts: 16
|
Posted: Tue Dec 12, 2006 11:38 am Post subject: DLL is wonderful, but consider KeyKit too. |
|
|
| 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  |
|
| Back to top |
|
 |
automaticman
Joined: 27 Oct 2006 Posts: 648
|
Posted: Sat Dec 23, 2006 5:00 pm Post subject: |
|
|
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 ) |
|
| Back to top |
|
 |
Dookie Guest
|
Posted: Fri Mar 30, 2007 5:53 am Post subject: |
|
|
| i'd like to have midi in support too! pls integrate it into the great ahk tool!! |
|
| Back to top |
|
 |
Guest
|
Posted: Fri Apr 13, 2007 12:54 pm Post subject: |
|
|
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
|
|
| Back to top |
|
 |
Anatoly Larkin
Joined: 28 Nov 2004 Posts: 32 Location: USA
|
Posted: Thu Jul 26, 2007 4:22 am Post subject: |
|
|
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 |
|
 |
Anatoly Larkin
Joined: 28 Nov 2004 Posts: 32 Location: USA
|
Posted: Thu Jul 26, 2007 5:47 am Post subject: |
|
|
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 |
|
 |
Anatoly Larkin
Joined: 28 Nov 2004 Posts: 32 Location: USA
|
Posted: Sun Jul 29, 2007 3:07 am Post subject: RegisterCallback |
|
|
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 |
|
 |
Anatoly Larkin
Joined: 28 Nov 2004 Posts: 32 Location: USA
|
Posted: Sun Jul 29, 2007 5:10 am Post subject: Midi In Programming in AHK - initial attempt |
|
|
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 |
|
 |
Anatoly Larkin
Joined: 28 Nov 2004 Posts: 32 Location: USA
|
Posted: Sun Jul 29, 2007 6:33 am Post subject: |
|
|
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 |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10716
|
Posted: Mon Jul 30, 2007 3:08 pm Post subject: |
|
|
| Thanks for posting your progress. |
|
| Back to top |
|
 |
Anatoly Larkin
Joined: 28 Nov 2004 Posts: 32 Location: USA
|
Posted: Mon Jul 30, 2007 5:34 pm Post subject: |
|
|
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)  _________________ ||||
------
!! |
|
| Back to top |
|
 |
Galoobus
Joined: 13 Jul 2007 Posts: 8 Location: Sacramento, CA
|
Posted: Mon Jul 30, 2007 9:28 pm Post subject: |
|
|
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 |
|
 |
Bryan Guest
|
Posted: Thu Aug 30, 2007 8:22 pm Post subject: |
|
|
| Another vote for MIDI input. I would use it for controlling a music notation program. |
|
| Back to top |
|
 |
Marco2 Guest
|
Posted: Tue Sep 25, 2007 6:47 pm Post subject: |
|
|
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 |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|