MIDI IN support in AutoHotkey
This is my first post and I want to say how impressed I am about this software. I've been using alternative shells for years, mainly because the ability to handle all kinds of key shortcuts, but Autohotkey goes far far beyond (and I've only seen 2% of what is possible).
The truth is I found Autohotkey looking for a program that could detect MIDI IN input and translate that to keypresses. This is not yet possible with this great software and I was writing Chris about this (instead of posting here, sorry!).
I don't know if any of the other users have some MIDI hardware. I have bought recently a Behringer BCR2000 controller. It connects through USB, costs 200 eur. It has 32 endless rotary knobs and 28 push buttons. I use it to make music, but I was wondering how awesome it would be to control a program like Photoshop or Flash to select RGB colors with real knobs, or to assign to each button a function like Levels, Curves, Create Layer... it would be like the hardware version of Photoshop.
So that this would be possible, someone should add MIDI input to Autohotkey. I believe it should be quite easy and not add many bytes to the executable file. I looked very quickly how to program MIDI in C with google and found:
(I'm a programmer myself and I've done MIDI apps long time ago, but now I only do interactive web services).
Is there anyone else who thinks this could be a really interesting addition? I guess you all know how powerful Autohotkey is, so imagine adding suddendly 61 new keys and lots of sliders and knobs :)
Here some thoughts I wrote to Chris in that email last week:
Add a new entry to the View menu:
View > List MIDI IN ports
That would dump a list of available MIDI IN ports like:
Then, in our script, we can specify not only keyboard keys but also MIDI events. Those can be of two types (there are a few more, but probably not interesting in this case):
3 bytes: channel (0-16), key number (0-127), velocity (0-127)
Control Changes (CC).
3 bytes: channel (0-16), CC number (0-127), value (0-127)
And the script could look like:
So when we play key 70 on the Edirol, opens somepage.com, and when we move the slider that transmits control change 100 in the BCR2000, opens someotherpage.com.
For this to work, Autokeys should start listening to the MIDI devices specified by &0, &1, etc. I'm not sure if MIDI support is included in your C compiler, but it's probable.
The behaviour I described is the most simple and only detects the event, but does not use the parameter. It can be improved if Autokey can detect the CC value and use it, because when I turn a knob, it transmits 'how much it is turned'. That could control the transparency of an object, or the volume, or... Also key velocity can be read (how hard the keyboard was hit, so it could detect your mood :)
The programming part shouldn't be so difficult. Basically it consists on opening the required MIDI in ports, listening to them, when events occur discards non useful events and take actions for the interesting ones. One thing to consider is the amount of events, which can be high. If you turn a knob from 0 to 127, maybe it transmits 127 x 3 bytes. No one could hit a key on the computer keyboard 127 x 3 times in half second, but with control changes this is possible. One solution is to filter and allow the same control change at a maximum rate, lets say one every 1/10 s., discarding the rest.
I don't know about file size increase. Depends on the required MIDI library or maybe direct access is possible...
By the way... there is a way to test it on your own computer without owning MIDI devices. You would need two programs. First, a virtual synthesisers with virtual keyboard, knobs and sliders which you can play with the mouse. Second, MidiYoke driver, which allows
"you to connect the MIDI output from one program to the MIDI input of a different program."
This way you could click keys and move sliders in the virtual synth, which would send MIDI events to a port that you are listening to in Autokeys. (a little twisted, but cheap).
I think a simple beta version can be done in a few hours...
This command line utility reads from any number of Windows MIDI input ports, merges the streams together, and copies the result to any number of Windows MIDI output ports. You can think of it as a combination of a hardware thru box and merge box.
This command line utility pretty-prints incoming MIDI messages from any number of Windows MIDI input ports. It can be useful for debugging complex MIDI setups, but there's nothing special about it.
This command line utility sends a single specified MIDI message. It can be used for scripting, or as a poor man's knob box.
@Chris (midimon has LGPL sourcecode included)
Now I would write the output to file, write an AutoHotkey-routine with a timer that checks for filechanges, reads changes, analyses and acts as wished...
Probably there is an easier or faster way of getting and processing the data, but this would work too :wink:
I've been using alternative shells for years,
I'm a big fan of alternative shells, too. What shells have you tried in the past? Also, which one are you running right now (and if it's not your preferred one, what is)?
As for myself, I've tried a lot, but there are still many (particularly *box and litestep variants) that I haven't yet. Right now I'm using Litestep, and I like any shell that is compatible with OTS2.
Hey someone else from Berlin! :)
You downloaded those really quick!
I think it's a great idea writing to a file and reading the changes. The only thing I wonder is.. how often would you read this file to get somekind of reasonable response? I don't want to put down your idea, and I will try it myself tomorrow. I want to see things happen when I press some keys on my MIDI controller!
But I just would suffer for my hard disk if I check two times per second 12 hours a day the same file... wouldn't it make a hole on the hard disk surface? ;) and it also would be a problem if you turn a knob and send suddendly 100 different CC (control changes). Imagine the knob is at position 0 and you turn it up to 100, this would send 100 commands, 3 bytes long each. The script you plan writing should do something with all those bytes... but we can try for normal keys first, later CC.
(by the way, I sent an email asking the author of those MIDI utilities if he would help us)
I don't want to turn this MIDI thread into Shells thread, but anyways...
Actually, since I found AutoHotKey I stopped using the alternative shells. It's kinda sad, because it looked better before. But some (few) things don't work 100.00 % right and I prefer to have one worry less. I used them for over two years. First I used Litestep. That's probably the best and with most plugins to do anything you can imagine. But it just took too much time to configure all those text files. Then I switched to xoblite, which worked great. Much less configurable, but worked enough to keep people saying... wow... cool... what OS is that? ;) I also tried some more, but don't even remember which. Now, back to explorer.exe, what I did first was to remove the Windows Logo and the 'start' word from the start menu, which I couldn't resist :) and then I have no icons on desktop, the start menu is as simple as possible. Everything happens with AutoHotKey and lots of key/mouse shortcuts, I also use rainlendar and rainmeter with my minimal skin to show sys info, weather and a calendar with ToDo and coming events. If interested we can start a new thread about shells or you can email me: abe at 314bits dot com :)
Well, getting the data by fileread is possible... I have been playing around with something similar. I wanted to be able to interact with a browser, to use a browser as a GUI for AutoHotkey, so to speak.
I posted a copy of the resulting script here... Check it out! It turned out to be quite cool 8)
Oh, and it could maybe solve the much asked for 'when do I know if a html-page is finished loading' issue. Add a write-cookie routine to the end of the file and then wait for this cookie-write, or something? Well, then you still would need to know about the other elements being fully loaded (maybe you could 'hook' them too). Might be worth looking into...
@hamoid: I think something similar to the above method could be used to capture the MIDI data 'semi-realtime'...
Hey... I was thinking of a different approach.
Is it possible to generate key presses in another software so AutoHotKey reacts to them?
What I'm thinking is how is it possible to link an external program (the one that reads MIDI input) and AHK without using just a text file, some kind of direct communication. I thought of the registry, but that's also a file and not so fast. I thought of creating a window with objects in "midiinput.exe", since AHK can access windows in other apps. But these two methods do not provide external events: AHK should ask if something happened. Then I thought that if "midiinput.exe" could also simulate key presses, AHK could catch those and react, creating this way a direct link. But I'm afraid AHK is at the lowest level and no program can generate events under it. Or is it possible? Can there be two programs simulating keypresses in the same system? who has priority? Is there any other way of sending events to AHK? If there was a way, it would be a good system for adding 'plugins' for AHK, so little .exe files could do things AHK can not, and then notify AHK.
Btw... are AHK and autoit somehow related? autoit has a very nice script syntax...
Of course, they have other differences too, since they've been developing separately for some time now. The most notable is the way they operate; AutoHotkey is optimized for code that's expected to run multiple times (i.e. loops, hotkeys, timers), and it is much better at user interaction. AutoIt3 is made more for static activies, and if you're making a gui or a non-persistent script, AutoIt3 would probably be better.
In the end, though, you have to decide for yourself. Get 'em both, and play around with them.
An AutoHotkey script can definitely detect the keystrokes sent by other programs. For example, if "^!p" is a hotkey in the script, you could have some other program hold down Ctrl, hold down Alt, then press P to trigger the hotkey in the script. These keystrokes could be generated by calling keybd_event() in the program.
Can there be two programs simulating keypresses in the same system? who has priority? Is there any other way of sending events to AHK?
Jonny also wrote a script that demonstrates how to send information into another script. This method should be adaptable to programs as well:
Edit: Fixed typo.
It would really be great if AutoHotkey had built-in MIDI in/out support. If you need any help on the subject, I studied music technology (am not working in the field anymore though), so if you have any questions about music hardware or MIDI, don't hesitate to ask (the MIDI-protocol isn't that easy to grasp). I'm not much of a programmer, but music happens to be my field...
Oh, I would love to use my keyboard/sampler or even my Atari or Macs to control my Windoze computer (yes, that could be done thru MIDI too)
... that would be muy kewl indeed 8) ... (don't know if I can sleep tonight )
Therefore, it will probably be at least 6 months until its priority level justifies a large amount of research on my part. However, I’d welcome any kind of proof-of-concept code (perhaps a standalone program) from anyone with the know-how or the tenacity to dive into this area. Having some kind of prototype code would greatly improve my confidence about whether and how AutoHotkey could be adapted to use midi.
I believe everything what is needed to add midi input is in the midimon.c program found at midiutilies.zip
It's under 150 lines, and it opens and listens to a MIDI IN port and dumps the MIDI messages to the screen (it's the little program daonlyfreez used in his midi demo script).
If someone ever decides to do this, here some thoughts:
AHK is able to read the state of a key (down or not). With MIDI you can not ask if a key on the keyboard is down. I propose to do the following.
The code needed is basically midimon.c, but instead of dumping text to a window, it stores the last parameter it has received for one keyboard press or control change in a dynamic array. This means that it stores the value of a knob/slider, or how hard a key was pressed. If you move the same control again, it replaces the value in this array. If you release a key, it sends velocity=0, and we replace this also in the array.
So it's really simple. Basically midimon.c, but storing new events in an array which is initially empty.
Why this array? So we can ask for the 'current' state of a key or control later on. We can read if a key is down (velocity>0) or read the value of a knob or slider.
I would also store a flag for each key/control in this array indicating 'changed' (true|false).
Each time we receive a MIDI event and MIDI_IN callback is executed, I would overwrite in this array the new value. This should be realtime (no added delay, callback_executed => array_updated & changed_flag=true).
When this callback is triggered, it's possible our script specifies we must do something, for example, show a msg_box with the value received. The tricky part here is that I would not execute scripts realtime, only the array should be updated realtime (which would be very fast because it's just writing one or two bytes each time). The script, which could take some time to execute, should be allowed to finish, maybe wait a little, and then check if the same value changed while it was running (if it did, run the script again).
The idea here is that if we use a knob to change the transparency of a layer in photoshop, and we turn the knob from 0 to 127, the array would be updated 127 times, but I doubt that the system would be fast enough to change the transparency level 127 times while remaining responsive. But there would be no problem if photoshop would only set those values at a slower pace, 0..33..72..83..100 (for example) ... semi real time.
I have to think if one flag would be enough, or maybe two, but I think you get the idea: the system updates internally in real time but executes scripts at a slower speed. All this is only important for sliders and knobs, for key presses there is no problem.
Maybe it sounds all very complicated here, but I believe what's complicated is this thinking before doing it. Once decided, the midi part is quite simple (as one can see in midimon.c). Maybe the other part (making AHK understand the new script commands) is not so obvious, that I don't know. If someone is interested I could try to define exactly the midi part, so the developer who makes it someday (chris?) doesn't have to think about it much.
One thing that can be tested in one minute is how much the exe size grows when adding this midi support, throwing in midimon.c inside and compiling the project. I would do it myself if I had visual studio, or is mingw enough?
And before going any further with all this I will try the script daonlyfreez was doing, to describe potential uses in normal work (designing, browsing, programming, doing office work) and see why would it be better or what problems there might be.