mAirlist and Velleman USB kit?

Hi there!

I have just purchased this DIY usb kit: http://www.vellemanusa.com/us/enu/product/view/?id=500349

I was wondering if it works with mAirlist for controlling start/stop functionality? If not, will it be implemented in the future?

Cheers, Rutger

I haven’t heard of that particular interfaces, and to be honest, there are far too many of these cards to add support for all of them. Unfortunately, there is no standard API for this kind of card (*), they all have their own API and DLLs. In fact, several people have asked to add support for a particular USB board in the past, but it was all different boards (!).

(*) In fact, there is a standard - USB HID. The IOWarrior chips have support for it, which made it very easy to implement the interface without any external DLLs needed.

There’s two workarounds for using unsupported interfaces in mAirList:

  • Write a notification script that uses the proprietary DLL to access the card (it is possible to use DLLs from mAirList scripts!), use the OnTimer procedure to check the status of the input channels, and use ExecuteCommand() to execute a command when something has happened.

  • Write your own application, in any language, that manages the card, and use HTTP REST calls to send commands to the running mAirList instance.

Actually, there’s a third possibility: Pay me to add support for the board.

Generally, I’m happy to add new features to mAirList for free when they make sense in terms of sales arguments; things that will make the software more attractive to new customers. In this particular case, I’m suspect that there is a very little chance that anyone but you will ever want to use this board, and it doesn’t make sense to me to spend a whole day adding support for it, because it will not make me sell more licenses. So I’d better spend my time with more popular feature requests and improvements.

The exception to this rule is when someone pays me to add a particular feature (given that it will not break the remaining code and functionality of mAirList, which is not a problem here, because everyone else can just ignore the particular remote control interface I would be adding). And I would also need a sample of that interface, at least for a week or two. Remote testing slows everything down.

I hope this all makes sense.

These boards are actually quite popular - available in most major towns/cities in the Maplin stores. I suppose from a sales point-of-view, it’s wise to have support for a device that is popular and readily available. The Advantech series of IO cards also have a fair amount of use here in the UK.

Rutger - if you just need a simple System Tray app to process and handle the fader-starts to mAirList from your USB board, I think I could produce something.

Hi Torben, I understand that it is impossible for you to support every USB kit like these in the world. The kit I mentioned in the OP is well-known in the radio-scene in Holland, it already works with some (freeware) live-assist software made by some dutch programmers. That’s why I bought it.

To Charlie: thanks for your offer! Really cool.

Regarding the workarounds and Charlie’s offer: would any of those give a noticeable delay between the actual button-push and starting the player? And would running helper scripts or helper applications like in the System Tray cause instability in the software? Or more likely, windows xp?

As I mentioned, I personally haven’t heard of these boards. If they are as popular as you say, it might be worth adding support for them.

I took a quick look at the API. It’s very simple. In particular, there are no callback mechanisms, but you need to poll the input status synchronously (as mentioned above) using a timer or thread. That means that you can easily adjust the poll interval (and the reaction time), but you always end up with a relatively high CPU load when using short intervals.

Perhaps we can start with a script (I can show you how to write one), and if I find the time later, I can add support for these boards directly into mAirList. Someone would need to sponsor or lend me one of these, however.

Quick hack script, not tested of course (I don’t own a board like that). The DLL needs to be somewhere mAirList will find it (mAirList program folder, system32 folder etc.).

var
  CurrentStatus: array[1..5] of boolean;  

function OpenDevice(CardAddress: Longint): Longint; external 'OpenDevice@k8055d.dll stdcall';
procedure CloseDevice; external 'CloseDevice@k8055d.dll stdcall';
function ReadDigitalChannel(Channel: Longint): boolean; external 'ReadDigitalChannel@k8055d.dll stdcall';

procedure OnLoad;
var
  i: integer;
begin
  for i := 1 to 5 do 
    CurrentStatus[i] := false;

  if OpenDevice(0) < 0 then
    SystemLog('Unable to open K8055 device.')
  else
    EnableTimer(50); // poll interval 50ms
end;

procedure OnUnload;
begin
  CloseDevice;
end;

procedure OnTimer;
var
  i: integer;
  newval: boolean;
begin
  for i := 1 to 5 do begin
    newval := ReadDigitalChannel(i);
    if newval <> CurrentStatus[i] then begin
      CurrentStatus[i] := newval;

      if (i = 1) and (newval = true) then
        ExecuteCommand('PLAYER 1-1 START')
      else if (i = 1) and (newval = false) then
        ExecuteCommand('PLAYER 1-1 STOP');

    end;
  end;
end;

begin
end.

It’s also possible to request all inputs at the same time using the ReadAllDigital function, but this is not the time of the day to fiddle around with bit masks :wink:

Hi Torben, thanks for your reply and your time writing this. I’ll try it out the coming week!

Today I purchased one of these boards so that I could add it into one of my projects - after trying Torben’s script I can confirm that it works (copy the K8055D.dll into the mAirList folder!) but you will need to comment-out the STOP command:

if (i = 1) and (newval = true) then ExecuteCommand('PLAYER 1-1 START'); //else if (i = 1) and (newval = false) then //ExecuteCommand('PLAYER 1-1 STOP');

This is because the Player will Start/Stop/Start/Stop etc during the polling interval - a bit like if you held down a key on your keyboarddddddddd. What is needed is some kind of bounce control where the input is ignored for a short duration before sampling again.

For the UK readers - this USB device is available from Maplin as a kit for £30 or ready-built for £40. It offers 5 inputs and 8 outputs. You get a mini-CD with an EXE test app along with C++, Delphi, VB6 and VB.net sources.

Hm. I can’t see why this should happen.

Take a look at the code. newval is the status returned by ReadDigitalChannel(i). It is cached in CurrentStatus[i], and the rest of the code block is only executed when newval is different from CurrenStatus[i].

When you see START and STOP commands executing, that would mean that newval - and thus the return value of ReadDigitalChannel(i) - changes in between, from true to false and vice versa. That should not happen when the contact is closed all the time, should it?

Looking at this code more closely, I would say that Torben’s script is assuming a system where true/on is sent all the time while the channel is on/fader is open, and flase when the channel is off/fader is down.

But for many desks, you only need to cater for the newval = true condition and not need any CurrentStatus array. I’m thinking of the common case where you get a one-shot pulse of tally signal when you press ON or lift the fader. This would only ever execute a START command, and multiple executions during the duration of the pulse wouldn’t matter, because applying a START command to a Player which is already STARTed has no effect. >shrug< It’s a kind of ugly hack, but it would prevent the ‘toggle’ effect. :wink:

Or … maybe the desk in question is sending separate tallies for On/Off fader lifted/lowered? In that case, you would I assume attach those two signals to two of the inputs; in which case you would add ‘if i = 2’ code where a newval of true would execute the mAirList STOP command. Same thing applies here as to the START command: running it several times while the pulse is active won’t matter either.

Unless I’m completely missing the point here? :smiley:

And Charlie’s correct BTW: Velleman kits are popular with hobbyists in many countries; I’ve personally seen them in Maplins in the UK and in electrical/electronic stores in the Netherlands, and they have a base in Forth Worth, Texas plus their European operation is based in Belgium.

PS: the upcoming VM167 module looks like fun as well. Its app note shows how to connect up an array of 16 buttons (like a pinball machine’s switch array, actually!) to the 4 digital inputs. Sweeeeet! 8)

BFN
CAD

Yep, the Velleman kits are quite good - although Maplin seem to be cutting-down on the hobby electronics and going more computer and hi-fi :frowning:

Regarding the script and tests here - I was using Torben’s un-modified script and the actual K8055 board which has the input buttons mounted on it. A sustained press would cycle mAirList between Start and Stop - I think this is related to the polling period but I can see how you have written that code - it shouldn’t flip like that.

PS: The same happens in Visual Basic - the sample project features a 50mS timer to sample the inputs - so some form of bounce control is required to prevent the ping-pong effect :slight_smile:

Cad, I don’t think it’s a tally vs. pulse issue. If it was a single pulse, mAirList would start the player and stop it instantly, but only once, and it won’t keep toggling all the time.

I suspect that the DLL returns false after a while (for whatever reason) even though the button is still pressed.

It should be fairly easy to confirm this with a small script.

There isn’t an Event in the DLL - you call the DLL to retrieve (or set) the status of the I/O. If this is happening every 50mS, then the average press could lead to that start/stop/start/stop scenario so you would need to handle that in some way. My bounce timer is the most crude of them :wink: Ideally you want only 1 action to occur - a single “change of state” rather than a continuous repeat (like holding down a keyboard key).

Are we on the same lines or am I getting muddled ?!

When you press the button, and hold it down, ReadDigitalChannel() will return “true” all the time, until you release the button again.

When the return value of ReadDigitalChannel(i) - newval - becomes “true” for the first time, the script issues the START command, and also caches the “true” value in CurrentStatus.

At the next cycle, the script compares newval (still “true”) to CurrenStatus (also “true”, from the previous cycle). As both values are the same, the script won’t do anything.

The poll rate doesn’t really matter here.

The poll rate does only determine the overall latency (that is, the maximum time until a key press is detected). And also, you must press the button at least as long as the poll rate is, so that the status won’t go from “false” to “true” and back to “false” within a single cycle.

Yep, makes sense - from my tests I deduce that the script is incorrect for the USB board’s momentary buttons. In your example, you wish the Player to stop when the button is released - a condition that would occur if the mixing console was using a continuous remote-start rather than a 200-500mS pulse. Typically, the continuous pulse is reserved for turntables or when you want to “lock” the front panel controls of some CD players.

You need only the first Player command, but change it to PLAYER 1-1 START/STOP so that a press will either start or stop the player - Using your original example (I know you said it was untested) will cause a sustained press to ping-pong the Player between the Start and Stop states.

EDIT: I have attached a revised script with 2 Players and a Cartwall option - this should get most people up and running.


mAirList K8055 Remote Start.mls (1.47 KB)

Nice one, Charlie!

Do I have your permission to use that script in the Manual? It would make an excellent, working example script for OnTimer notification scripts.

Incidentally, the spec. for the board specifically states:

[ul][li]5 digital inputs (0= ground, 1= open)[/li][/ul]

… which would explain the ‘flip-flop’ problems above (think about it!) if I’m reading this correctly? :smiley:

Anyway, I think the OnTimer proc would look neater and (maybe?) work faster like this, because it minimises the amount of code executed per cycle if NO switches have changed state:

procedure OnTimer; var i: integer; newval: boolean; begin for i := 1 to 5 do begin newval := ReadDigitalChannel(i); if newval <> CurrentStatus[i] then begin CurrentStatus[i] := newval; if CurrentStatus[i] = true then // These are for Buttons 1, 2, and 3 case i of 1 : ExecuteCommand('PLAYER 1-1 START/STOP'); 2 : ExecuteCommand('PLAYER 1-2 START/STOP'); 3 : ExecuteCommand('CARTWALL 1 START/STOP'); end; end; end; end;
If the thing still ‘flip/flops’ on a button press with that script, change the true to false and let me know what happens. :wink:
EDIT: And also, at the same time, change the false in OnLoad to true. ::slight_smile:

BFN
CAD

'tis Torben’s scipt, I merely added a couple of lines - but fine with me :slight_smile:

Thanks, Charlie.

So, does closing a switch on an input actually deliver a TRUE or a FALSE to the driver?

My reading of the spec. (see above) implied that an input goes FALSE when ‘grounded’ and TRUE when ‘open.’ :-\

BFN
CAD

Input is 1 when grounded (ie: pressed). So “True”, in this case!

Just checking! ;D

BFN
CAD