amBX for VB.net

Filed under amBX

image A while back, I wrote up a short post about calling C function pointer style interfaces with VB.net. When I started into that, what I was really wanting was a pure VB.net solution for calling the amBX API interfaces. There was already a library out to do the job, but that would have required including a separate dll, and, well, it’s not VB! It was C++ and C#.

But what’s amBX? Well, the basic system looks like this:

image

That box in the middle is actually called a “wall washer.” It contains several banks of lights that shine up onto the wall behind the unit. The speaking looking things are exactly that: LED lights that look similar to speakers.

You can also get an extension pack:

image which consists of 2 fans, and a rumble bar (basically just a bar with two vibration motors in it).

In action, it looks like this:

Anyway, flash forward to now and my VB version of that library is ready for an initial release.

I call it amBXLibrary (catchy eh?)<g>.

amBXLibrary

The whole thing is in one ambx.vb source code file, and there’s no external references necessary, so, literally all you do is drop that source file into your project and you’ve got support for the amBX device set. Yes, it could  have been broken up into a separate file for each class, and, normally, that’s how I approach things. But in this case, knowing I was planning on making this code publicly available like this, I opted for the simplest distribution form possible. If you must have it split up, feel free!

One more important note: You will need to have the ambxrt.dll file somewhere accessible, either in the same folder as your application or on the path. This file is installed with the amBX system, but won’t normally be on the path.

General Usage

All the internal classes are part of the amBXLibrary namespace. You’ll need to add an imports for that or set it in the project properties (or remove the Namespace line from the source) before you can use it.

The root class is amBX. To start up amBX and connect to its drivers, you’ll need to call the Connect method:

amBX.Connect(1, 0, "My Application", "1.0.0")

The first 1 and 0 are the required major and minor version of the amBX library. Since there’s only a version 1.0, that’s the only possible value to those arguments at this point. The next args are the string name of your application and a string version of the version number of your application. As far as I can tell, these values can be anything you want.

When you’re finished with amBX, be sure to call the Disconnect method (although this is not strictly necessary).

amBX.Disconnect()

The amBX class is a static class, which means you can’t instantiate instances of it. All its methods are Shared. It exposes several collections, into which you can add new amBX objects. Those include:

  • amBX.Lights
  • amBX.Fans
  • amBX.Rumbles
  • amBX.Events
  • amBX.Movies

Create a new amBX light like this:

Dim LeftLight = amBX.Lights.Add("Left", amBXLibrary.Locations.East, amBXLibrary.Heights.AnyHeight)

Technically speaking, since the newly created light is automatically added to the Lights collection, you don’t absolutely need to keep a local reference to it. But doing so makes it easier to work with your objects. Further, generally speaking, in amBX applications, you create the objects you need up front, when your application loads, and you use them until the application quits, so it tends to be more convenient to keep local references.

The first argument, the name, is simply an arbitrary descriptor of the object you’re creating. That is not part of the underlying amBX library. I added it more for convenience than anything. That said, you don’t have  to give names to your objects. You can also create a light like this:

Dim RightLight = New amBX.Light(amBXLibrary.Locations.West, amBXLibrary.Heights.AnyHeight)

Notice, no name, and I just created the object directly with New. Note however that the new Light object is still added to the Lights collection and you can still reference it my index or via an enumeration.

Threading

amBX has several different options for multi-threading. This library only uses one. When you initially Connect, a background thread is started internally which calls the amBX.Update method 20 times per second. You can alter the timing however you want, and even turn it off by settings UpdatesPerSecond to 0. If you do turn it off, you’ll be responsible for calling the amBX.Update method periodically yourself.

Changing Objects

All the amBX objects are fairly simple. The lights have a Color; the fans, an Intensity; and the rumbles, an Intensity, Waveform, and speed. You simply set the properties however you want. The next time the amBX.Update method is called, the changes will be sent to the amBX drivers and the hardware updated.

Events and Movies

Event and Movie objects operate a little differently from the other amBX objects. Events are usually for short event sequences that can’t be stopped or paused. Movies are for longer sequences where you may want to stop or pause the sequence arbitrarily.

With Events, you generally create them during your application Load process and then simply call the Play method anytime you need the event sequence to play out.

Since Movies tend to be much longer sequences, you’ll generally create them right before you need to play them, Play the movie, and then dispose of the object.

Disposing of Objects

All of the effects objects in the library implement the IDisposable interface, so it’s usually best to explicitly Dispose the object once you’re done with it. Usually, this is easiest to do by using a Using Block:

Using Evt = New amBX.Event("c:\SomeEffectFile.ambx_bn")
        Evt.Play()
End Using

Enabling and Disabling

You’ll notice that several of the Enable/Enabled/Disable members are seemingly arbitraryly properties or methods. For instance, Light.Enabled is a boolean property, whereas Fan.Enable is a method, and fan.Enabled is a readonly property. This is because the different objects deal with enabling in different ways. This is the nature of the amBX drivers, not an arbitrary decision of mine!

In the case of a fan, the Enabled property will return which state the can is currently in, which can include Enabled, Disabled, Enabling or Disabling. However, in the case of a Light, the light can only be Enabled or Disabled.

Also note that although the amBX documentation indicates that disabling an object will “cause it to retract itself from the user experience”, I’ve found that doesn’t appear to be the case. When I Disable objects, it simply means that they no longer react to any property changes to the them.

For instance, if you set a fan intensity to .5, then disable the fan, it continues to spin. But, setting the intensity to 0 will no longer alter the fan speed. You must Enable the fan again in order to change its intensity again.

Rumble objects are particularly troublesome in this respect, since there doesn’t appear to be a way to turn one off once it’s turned on. I’ve found that releasing the object and then recreating it will turn the rumbler off, but that causes more problems. So, as currently implemented, you MAY have problems with rumble effects (at least, problems getting them to stop!).

From what I’ve seen online, this is described as a known bug in the amBX drivers, but I’m not completely sure.

The Tricky Parts

I’ve really already covered (in the post referenced at this top of this post) what was the most difficult aspect of getting this library operational. All of the amBX interfaces are C style function pointer structures. These are easy to deal with in C, but more difficult to work with in VB.net. However, pleasantly, they are, in fact completely interoperable with VB.net (or C# for that matter). You just have to use the right combination of IntPtr, and Marshalling to convert those C function pointers to .net Delegates that can be called from managed code with no problems at all.

If you want to know more, check out my previous post here, and pay special attention to the Generate methods in the source code. For instance, here’s the one for the Event object:

 Public Sub Generate(ByVal IamBXEventInterface As IamBXEventInterface)
   Me.Play = Marshal.GetDelegateForFunctionPointer(IamBXEventInterface.PlayPtr, GetType(PlayDelegate))
   Me.Stop = Marshal.GetDelegateForFunctionPointer(IamBXEventInterface.StopPtr, GetType(StopDelegate))
   Me.Release = Marshal.GetDelegateForFunctionPointer(IamBXEventInterface.ReleasePtr, GetType(ReleaseDelegate))
End Sub

It uses the GetDelegateForFunctionPointer method of the Marshal class to create the necessary delegate from the function pointers passed back by amBX. Then, it’s just a matter of retrieving those function pointers correctly, managing the whole mess efficiently and calling the delegates when you need them.

The Caveats

This is a very “in flux” library at this point. In reality, I don’t even have any amBX hardware to test on. Everything I’ve done so far has been using the Virtual amBX Test Device, a program that simulates all the various amBX hardware that’s out there at this point.

I’ve implemented all the various methods and properties of the C amBX interfaces, but I have not tested them all out at this point (specifically, the RunThread and StopThread methods of the amBX object).

I also have noticed the above mentioned problem with disabling rumble devices (it just doesn’t seem to work right), and the only workaround seems to completely kill the rumbler, such that you can’t turn it back on at all without disconnecting from amBX and reconnecting.

However, I’ve noticed similar issues when working with the “amBX Test Tool” that comes with the amBX SDK, so I’m not completely sure whether it’s something in my code, or with the drivers themselves.

That said, the lights, fans, events, and movies all seem to work spot on, and I’m not much concerned about the rumble effects myself anyway<g>.

My Intentions…

I’ve got some very specific things I intend to use amBX for, but mainly, once I find a set for a reasonable price, I’ll be disassembling it and mounting the various pieces in a purpose built cabinet. My hope is to use all the elements (lights, fans and rumblers) but I’m not completely sure that’ll make sense.

I’m also working on a general purpose “screen color tracker” that will drive the amBX lights based on whatever happens to be onscreen, not use amBX enabled DirectX windows. But that’s a whole other project in and of itself!

The Code

I’ve made this project Open Source via CodePlex. Check out the project page at ambx.codeplex.com.

Alternately, you can download the test project (with the ambx.vb library source) here.

And Finally…

Let me know what you think! Have suggestions? Ways to improve the library? Things you would have done differently? Fixes?

By all means let me know. I’ll do what I can to get improvements and suggestions implemented.

10 Comments

  1. MikeHD says:

    I realise this is a ridiculously long time after you developed this library, but please indulge me. Is there any way you know of to *access* rather than set the colour values of the AMBX lights?

  2. Darin says:

    Hi Mike
    Yeah, that was a while back, but I love to look back at old code. I believe what your looking for is IamBXLightDelegates.

    There’s a method there, GetCol, that is used to retrieve the color that a particular light unit is currently set to.

    Just went to the ambx site. Jeez, nothing there anymore, even the Wiki link is dead.

    In the interim years, I picked up an Ambx set, had it blown up in a lightning strike, picked up another, and then upgraded to Win7 and the drivers no longer seem to work. Sigh. It was very interesting stuff, though.

  3. MikeHD says:

    Nice work, thanks.
    They still work perfectly in Win7 btw, you just need to install drivers as “legacy hardware” and make sure the software updates itself. Unless you don’t want your kit anymore… in which case I’d happily take it off your hands! 😉
    I’m currently extending the system onto RGB LED strips around a cinema room and was thinking about using LED voltage levels, microcontrollers and all that crap. Your code sounds like it can do a much better job collecting the values in the background.
    Even now, in terms of performance, I think the AMBX system still can’t be beaten, even with all these open-source Atmo, Boblight, Momolight etc. clones. Unlike them it also works with every game I throw at it.
    Shame it’s become so low-key but I’m certain there will be a resurgence of this kind of tech very soon.
    Now, to learn some VB… so I don’t suppose you have any premade tools lying around to log the RGB values every 20ms…? 😉

    • Darin says:

      Really? I’ve never been able to get mine to connect to Win7 but that gives me hope. It may be time for a fresh paving of my machine.

      Sorry, I don’t have any code for that, but my little project up on codeplex should be a pretty good start. It’s been a while since I looked at it, but there’s a sample that shows how to set individual light colors (via the color property), that property is read write though, so you should be able to just poll it to retrieve the current color.

      However, Since I’ve never had a real system operational, I don’t know how that works in conjunction with the system running on its own (and I’m guessing that’s what you’re looking for, ie have the system running, and changing colors based on the screen, and you need something to reach in and grab the current colors and do something with those values)? I +think+ that would still work, because of the way the ambx system is architected, but I’m not sure.

      • MikeHD says:

        Well sir, thanks for the advice, my ‘programming skill’ extends to AutoIT only however (!), so it may take me a while to get to grips with it – but will start with your sample as you said.
        As for installing your system, download the latest installer and Philips dirvers from here http://www.ambx.com/download-drivers-software
        Then Device Manager > Action > Add legacy Hardware, do the “Have disk” routine, locate the .ini drivers et voila!

        • Darin says:

          Hi Mike

          I’ll give that a shot. Don’t think I tried it that way before. If I can get them running, I’ll try to have a look at polling the colors.

          • MikeHD says:

            Darin, that would be amazing if you can, thank you! I’m having no joy with the AmbxTest sample, unfortunately. The tool runs fine but there’s no light activity at all… most probably me not setting it up correctly, but there are no debug errors and nothing else is using the lights…?

  4. MikeHD says:

    Any luck getting it running? I’ve still not managed to get it functioning with my lights.

    • Darin says:

      I’m pretty swamped with work and life right now, unfortunately. I might get a chance to take a look sometime next week or next weekend, but I can’t say. This project got backburnered by some other things I’ve got going on right now.

      But I’ll definitely let you know if I get something going.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*