Category Archives: MP3s

Uniquely Identifying RawInput Devices in AutoHotKey

3
Filed under AutoHotKey, Hardware, MP3s

NOTE: My take on this has changed slightly, as a result of some feedback. See the end of this post and the "Better Alternate Solution” for details.

I recently completed restoration of an old 1930’s era console radio into a fully modern touch-screen mp3-playing networked jukebox, and have been putting the finishing touches on the loaded software configuration for a few weeks.

Jukebox Original CL Photo

WP_000576

Radio as we found it, stuffed at the back of a barn/storage area

After the conversion, that touchscreen you see automatically folds and the top lowers back down to it’s original position when not in use

There were 3 knobs on the original unit. The actual knobs were long gone, but the holes were still there and I wanted some old-school tactile controls for this thing, as well as the touchscreen.

A few ebay searches and junk drawers scavanges later, and I had 3 very serviceable knobs for the front. You can see them in the photo, the two large dial knobs and the one small brass knob on the center plate.

WP_000498

Now that that was taken care of, I had to determine

  1. What I wanted them to do
  2. How to make them actually do that

Believe it or not, the “what” has actually turned out to be harder than the “how”

All About the “How”

Realistically, the what doesn’t much matter from a technical standpoint. Controlling volume, track playback etc is pretty trivial stuff with most software these days. So I’ll focus on the “how”.

I’d used a macro application called AutoHotKey on several occasions, and, while it’s programming language is quirky to put it mildly, it does get the job done, particularly when the job consists of converting one type of computer input into another.

In my case, each of those knobs it connected, via a typical encoder wheel, to the inputs of a standard 3 button optical mouse with middle wheel. Yes, you heard that right, there are three mice lurking in that cabinet (a forth if you count the real mouse that I use when working on it).

The Three Blind Mice

If you’ve ever hooked up 2 or more mice to a Windows PC, you know that they all control the single cursor. There’s no clear way to tell one mouse’s input from the other. Windows does that intentionally because it generally makes sense.

However, underneath the covers, there’s an API that exposes all input devices uniquely, meaning you CAN actually tell whether one mouse or another is being moved, clicked, scrolled or what not. It’s called the “RawInput” API, and it’s been there ever since Windows XP (and possibly even earlier, though I’m not sure of that).

Unfortunately, the RawInput functions are not the easiest functions to deal with in the world. Lots of C-style structure parsing and pointer juggling.

AHKHID to the Rescue

Fortunately though, for AutoHotKey users, a user named “theGood” posted AHKHID.ahk, an AutoHotKey script of functions to make working with HID devices (Human Interface Devices) at the RawInput level relatively straightforward.

I’d been able to craft up a script to detect which of my mice were been wheeled and clicked and react accordingly, so things were good.

Until I unplugged the mouse I used for working on the jukebox, and the keyboard.

When I booted it back up, boom, nothing worked right.

An ID isn’t an ID

I had been using the function AHKHID_GetDevIndex, as in:

id := AHKHID_GetDevIndex(h)

in order to retrieve a device ID and I’d assumed that ID would consistently identify a device. And I’d assumed wrong. Unplugging my actual mouse and keyboard had caused the devices to get renumbered on reboot, a common issue with Windows applications.

A Nasty Solution

The AHKHID script includes a function called AHKHID_GetDevName() that retrieves a unique “device name”, but that “name” is huge, consisting of a number of segments of hex number, plus an additional entire GUID, something along these lines:

USB\VID_045E&PID_00DD&REV_0173&MI_00{745a17a0-74d3-11d0-b6fe-00a0c90f57da}

Obviously, this could be used for a key, but it’s a bit unwieldy.

So, to shorten the key name a bit and make it easier to work with, I came up with AHKHID_GetDevKey()

AHKHID_GetDevKey(i, IsHandle = false) {
    ;generate a unique name from the DevName (which is huge, and usually includes a useless GUID)
    devname := AHKHID_GetDevName(i, IsHandle)
    StringReplace, devname, devname, Hid#Vid_, , All
    StringReplace, devname, devname, USBVid_, , All
    StringReplace, devname, devname, KODAK, , All
    StringReplace, devname, devname, &Pid_, , All
    StringReplace, devname, devname, &MI_, , All
    StringReplace, devname, devname, #7&, , All
    StringReplace, devname, devname, #, , All
    StringReplace, devname, devname, &, , All
    StringReplace, devname, devname, \, , All
    StringReplace, devname, devname, ?, , All
    p := Instr(devname, "{")
    if p > 0
    {
        p := p - 1
        StringLeft, devname, devname, p
    }
    ;remove last 5 0's if that's what's there
    if SubStr(devname, -4) = "00000"
    {
        p := StrLen(devname) - 5
        StringLeft, devname, devname, p
    }
    StringUpper, devname, devname
    Return devname
}

The idea here is to essentially strip out all the characters that wouldn’t help to make the string any more unique anyway. It’s a tad brute-force, but it’s easy to understand and it works.

So that insane name could end up a relatively benign:

045E00DD017300

Which is a perfectly reasonable unique key in my book.

An Alternate Solution

After I’d put this together and gotten it in use, I realized a potentially even better solution: just calculate a CRC-32 for the full Device Name. It turns out another user has already built a CRC-32 algorithm in AHK script, so doing so would be trivial. Granted, you might still get collisions with a CRC, but it’s reasonably unlikely.

A Better Alternate Solution

Well, after posting this, I got a comment on the AutoHotKey forums that, essentially, was pointing out that the “VID_” and “PID_” strings that my routine removes, actually can have an impact on the uniqueness of the name. The poster also indicated that the GUID at the end of the name also aided in the uniqueness.

While neither of those two claims held true in my specific case (on the 3 machines I tested on), I don’t doubt them in the list.

Which got me to thinking if there’s a better solution.

And there is. Our old friend, the hash function.

In reality, the CRC-32 approach that I suggest above can certainly be considered a form of hash function, and a pretty good one at that.

But, if you’re really gunning for just about ironclad uniqueness, at 64 or 128 bit hash is what you need, and there’s a couple of implementations that already exist for AutoHotKey.

Grab one of those, run it against the GetDevName value, and convert to a string value and you have a relatively short and manageable, unique and consistent HID device ID.

Wrap Up

I love Visual Basic, and VB.net in particular, but AutoHotKey makes many tasks concerned with translating one type of input into another (converted joystick input to mouse input, or keyboard keystrokes, for instance) so easy, it just often doesn’t make sense to build a dedicated app for the purpose.

It’s definitely an application to key handy in your toolbox.

Arcade Ambience

0
Filed under Arcade, Media, MP3s

If you’re putting together an Arcade cabinet or if you just like the ambience of an old arcade parlor while hacking away at some code, you might get a kick from Andy Hofle’s Arcade Ambience project.

image

Basically, Andy took recordings of playing dozens of arcade machines, remixed them, adjusting volumes, pans, etc, and ended up with several, very large, mp3 tracks of background ambience that sounds very much like stepping into an old arcade. What’s even better, the tracks are so large (at 70+mb each), they effectively don’t loop, so you don’t get that been there, heard that feeling that’s typical of ambient tracks.

Couple that with an arcade front end that can play an arbitrary mp3 looped as background sounds, and couple that with a recent audio card that supports multiple simultaneous channels, and you get all the ambience of walking into an arcade while playing any emulator, Visual Pinball table, etc.

The Running instance of Windows Media Player

13
Filed under Media, MP3s, Office, Utilities

I’m finishing up my little Signature Enhancement Utility for Outlook and had finally gotten the Media Center 12 “Currently listening to” functions operational (This is just a minor feature I’ve seen popular on website blogs and forums, where the tag line contains not only the author’s name but what they are currently listening to, if anything, nifty and fun, but not in the least practical).

I figured I’d go ahead and try to support Windows Media Player 11 (and hopefully earlier versions) as well.

Basically, the idea is to grab a reference to the running instance, interrogate it as to the “playing” state and, if it’s playing or paused, retrieve the name, album, artist, etc info on the playing track and make it available as replaceable fields in the signature.

With Media Center, it was almost trivial:

Set omc = GetObject(, "MediaJukebox Application")
If not omc is nothing Then
   '---- it's running
   ' if it's not running, they can't be playing any music
   With omc
   Select Case .GetPlayback.State
      Case PLAYSTATE_PAUSED, PLAYSTATE_PLAYING
      '---- Media center info is available
      ps = .GetCurPlaylist.Position
      CurTrackTitle$ = .GetCurPlaylist.GetFile(ps).Name
      etc...

Obviously, if the GETOBJECT fails to return anything, Media Center isn’t currently running so the user can’t be listening to anything.

Three hours of Googling later, plus tons of experimentation and I’m not even an inch closer to getting this working for Media Player.

Using ROTView(the Running Object Table viewer, comes with various installations of Visual Studio), it does appear that WMP registers “something” with the ROT, which I’d think would be accessible by VB’s GetObject().

Alas, “Windows Media Player”, “WindowsMediaPlayer”, “MediaPlayer.MediaPlayer”, and on and on, all came up empty.

I scoured the registry for anything that even remotely looked like the moniker of a WMP registration with the ROT and everything I tried also came up empty. I’m sure it’s another case of knowing the magic password, but so far, it appears to be a tad more involved than Speak, friend, and enter.

So, for now, looks like I’ll have to rely on the FunPack for support of a limited set of attributes of the currently playing song in WMP. Apparently, for ITunes, you can use this plugin to accomplish the same thing, though I don’t use ITunes and probably won’t bother with testing that.

If anyone’s ever had any success with accessing the running instance of Media Player, I’d love to hear about it!

Media Center and the command line

0
Filed under Media, MP3s

I’ve used several different media players over time, but since stumbling across J River’s Media Center, I haven’t seen the need to use anything else.

It has an fast and flexible database, and it can tag multiple tracks very efficiently. Plus it looks great!

MediaCenter

I really only have two negatives about it.

  • I still can’t get it to work right with my Tivo. When it DID work, it was great. But it quit at one point about a year ago, and I’ve never been able to get it to work since. Galleon, on the other hand, works great with Tivo, and has since I first installed it.
  • The Next and Previous track keys on my MS Comfort Curve keyboard don’t actually go to the next and previous tracks like they should when MC is minimized. The volume and pause keys work perfect though.

Ok, scratch that last negative. I posted a question to the MC forums and got some very helpful responses, which led me to the Media Center Wiki with this post about the command line options. Just use:

MC12.EXE /COMMAND /NEXT

or

MC12.EXE /COMMAND /PREVIOUS

and Viola! Next and previous work just fine, no matter whether MC is minimized to the systray or not.

Now, maybe someone has an idea about getting it to work with Tivo again. Anyone?