![]() |
|||
MIDI driver interfaceNota This document is currently only a draft and will most likely change before it is accepted as an official specification. It might also be deprecated if a better aproach has been found and might not correspond precisely with the current implementation. This document describes how to make a midi-driver for the camd.library. This is just a short explanation how things works right now. Everything might change in the future, I guess. CAMD is designed in such a way that writing device drivers should be very easy. Looking at the source for the debug-driver placed in AROS/workbench/devs/midi should explain the most, but some additional and more detailed information comes here. First, the new Camd.library will be described as AROS' Camd.library. However, this Camd.library also works for AmigaOS, and everything described here goes for the AmigaOS version of this Camd.library too. Beware that camd midi-device drivers made as described below will not work with the original Camd.library as the file-format is a bit changed. Luckily enough though, the new Camd.library is also able to use camd midi-device drivers designed for the old Camd.libraries driver-format (with the help of a dirty trick). (AROS' Camd.library does not handle the old format, only the AmigaOs/SASC - version). Camd.library does as its first thing in the init-routine, search thru all files in Devs:Midi/ and load all possible midi-device drivers. Therefore, the drivers must of course be placed in the Devs:Midi directory. The central point of a midi-device driver is the MidiDeviceData struct which you must put somewhere in your binary. Camd.library searches thru your file to find out where the structure is placed. So there are some rules you have to follow to let Camd.library recognize the driver as legal. The structure looks like this (taken from Include/devs/camddevices.h):
struct MidiDeviceData
{
ULONG Magic;
char *Name;
char *IDString;
UWORD Version;
UWORD Revision;
BOOL (ASM *Init)(
REG(a6) APTR SysBase
);
void (*Expunge)(void);
struct MidiPortData *(ASM *OpenPort)(
REG(a3) struct MidiDeviceData *data,
REG(d0) LONG portnum,
REG(a0) ULONG (* ASM transmitfunc)(APTR REG(a2) userdata),
REG(a1) void (* ASM recievefunc)(UWORD REG(d0) input,APTR REG(a2) userdata),
REG(a2) APTR userdata
);
void (ASM *ClosePort)(
REG(a3) struct MidiDeviceData *data,
REG(d0) LONG portnum
);
UBYTE NPorts;
UBYTE Flags;
};
'OpenPort' should return a pointer to a MidiPortData struct. If the port could not be opened, you return NULL. The MidiPortData struct looks like this:
struct MidiPortData
{
void (* ASM ActivateXmit)(ULONG REG(d0) portnum);
};
'ActivateXmit' contains a pointer to a function in your driver that is called from Camd.library whenever Camd.library has some midi-data it wants to be distributed. In other words, when Camd.library calls this function, it is time for you to as soon as possible call the 'transmit'-function to get mididata. Here is an example how you can do that:
while((data=(transmitfunc)(UserData[portnum-1])!=0x100)
SendDataToPort(portnum-1,data);
('UserData' is here an array of 'usedata's. 'userdata' is provided when 'OpenPort' is called) As you see, there might be more than one byte that is waiting to be picked up (that is actually the common case), and when there is no more data to be picked up, 'transmitfunc' returns 0x100. Unlike the original driver-format, its no harm calling 'transmitfunc' even though there are no more data waiting to be picked up. (Thats the most important change between the old and the new driver-format: How on earth are you able to know there aren't any more datas to be picked up for all possible situations?) Also beware that 'ActivateXmit' might be called even if there are no more datas to be picked up, and also while you are currently picking up data with another task or interrupt. But luckily, 'ActivateXmit' will not be called again until you return, so its single-threaded per port. Note that 'transmitfunc' returns data that is optimized with running status, so if you are not sending data that is going to be directly transmitted via a midi-cable, or the place you are sending the data is in some way not able to handle running-status, you have to manually keep track of running status. But if this is the case, its probably better if you write a normal Camd.library application that makes a new cluster and you receive datas via a hook, which you again distributes to wherever you want them. Then you'll get all status-bytes. (Applications using Camd.library don't see any difference between a normal driver and the driver-technique described here) |
Copyright © 1995-2009, The AROS Development Team. All rights reserved. Amiga® is a trademark of Amiga Inc. All other trademarks belong to their respective owners. |