Last modified on 7 February 2014, at 03:59

Aros/Developer/Docs/Libraries/CAMD

Navbar for the Aros wikibook
Aros User Docs
Aros User Docs
Aros User FAQs
Aros User Applications
Aros User DOS Shell
Aros/User/AmigaLegacy
Aros Dev Docs
Aros Developer Docs
Porting Software from AmigaOS/SDL
For Zune Beginners
Zune .MUI Classes
For SDL Beginners
Aros Developer BuildSystem
Specific platforms
68k Support
PPC Power Architecture Support
Arm Raspberry Pi Support
Android support
Linux and FreeBSD Support
Windows Mingw and MacOSX Support
Aros x86 Installing
Aros x86 Audio/Video Support
Aros x86 Network Support
Aros x86 Complete System HCL
Aros Storage Support IDE SATA etc
Aros Poseidon USB Support
x86-64 Support
misc
Aros Public License


IntroductionEdit

Commodore Amiga MIDI Driver (CAMD) is a shared library for AmigaOS which provides a general device driver for MIDI data, so that applications can share MIDI data with each other in real-time, and interface to MIDI hardware in a device-independent way.

AmigaOS itself did not support MIDI until release 3.1 when Roger Dannenberg's CAMD library was adapted as the standard MIDI API. Commodore's version of CAMD also included a built-in driver for the Amiga serial port.

Read more here


Only copy the driver(s) you use into devs:midi/. Dont have more than one type of driver for the same hardware in devs:midi/. Ie, don`t have both mmp and uaemidi (which both uses the serial-port), for example.

USB will poll and find all midi devices automatically

The new camd.library does not have a built-in driver for the serial-port. Just use mmp/port 0 instead. It should be more stable than the old internal driver too.

out.0, out.1, out.2, in.0, in.1, etc. does not exist anymore. The links will have the names <drivername>.out.0, <drivername>.out.1, <drivername>.in.0, etc. instead.


Camd library inside technical specs specifications src


Midi SpecsEdit

NodesEdit

Each node is hardware


Tags

MIDI_Name (STRPTR) name of the node, usually the program name
MIDI_SignalTask (struct Task *) Task to be signaled, defaults to current task
MIDI_RecvHook (struct Hook *) the hook to be called when new messages arrive
MIDI_PartHook (struct Hook *) the hook to call when linkages are added or removed
MIDI_RecvSignal (int8) the signal to send when messages arrive
MIDI_PartSignal (int8) the signal to send when linkages are added or removed
MIDI_MsgQueue (uint32) the desired size of incoming message queue
MIDI_SysExSize (uint32) the desired byte size of the System Exclusive buffer
MIDI_TimeStamp (uint32*) pointer to the desired MIDI time stamp source.
MIDI_ErrFilter (uint16) the desired error filter for this node. see camd.h
MIDI_ClientType (uint16) the desired client type for this node. see camd.h
MIDI_Image (struct Image *) Image (suggested 32X32) for this node.


LinksEdit

Links are created beween nodes


Tags

MLINK_Name (STRPTR) name for this link
MLINK_Location (STRPTR) Cluster to connect to, Case sensitive
MLINK_ChannelMask (uint16) Mask of which MIDI channels to listen to, defaults to ~0
MLINK_EventMask (uint16) Mask of which types of MIDI events to listen for, defaults to ~0
MLINK_UserData (CPTR) User defined
MLINK_Comment (STRPTR) highest priority link will comment the cluster
MLINK_PortID (uint8) Value to copy to any msgs arriving through this link
MLINK_Private (BOOL) if TRUE, link requests to be hidden
MLINK_Priority (int8) priority of this MidiLink
MLINK_SysExFilter (uint32) data is 3 1 byte SysEx ID's to filtter with
MLINK_SysExFilterX (uint32) data is one 3 Byte SysEx ID to filter with
MLINK_Parse (BOOL) If true, CAMD will parse incoming stream into MIDI Messages
MLINK_ErrorCode, (uint32*) points to an error code buffer


A meeting of links from different applications or interfaces (in, out or both) is called a cluster. It allows messages from one link to get to other links automatically.

                Link                     Links
Application ----------> Cluster ----------> Application 
                                 <------------ Application 



MessagesEdit

And midi messages are sent


/* MidiMsg struct */
mm_Msg 
mm_Time 
mm_Status 
mm_Data1 
mm_Data2 
mm_Port 
mm_Data 

GetMidi PutMidi


FiltersEdit

lower 4bits contains the channel number, if the MIDI messages is on a channel which does not match the bits set, then message is not used

what midi wants

note on/off
program change
pitch bend
controller change MSB
controller change LSB
controller change Boolean switch
controller change single byte
controller parameter change
undefined controllers
mode change messages
channel after touch
polyphonic after touch
system real-time messages (MIDI clock, MTC Quarter Frame)
system common messages (Start, Stop, etc)
system exclusive messages


Home to General Midi info



ExamplesEdit



#include <stdio.h>
#include <proto/exec.h>
#include <proto/camd.h>
#include <midi/camd.h>

#define TABSIZE 4

struct Library *CamdBase=NULL;

#ifndef GetMidiLinkAttrs
ULONG GetMidiLinkAttrs(struct MidiLink *ml, Tag tag, ...){
        return GetMidiLinkAttrsA(ml, (struct TagItem *)&tag );
}
#endif

#ifndef GetMidiAttrs
ULONG GetMidiAttrs(struct MidiNode *ml, Tag tag, ...){
        return GetMidiAttrsA(ml, (struct TagItem *)&tag );
}
#endif

struct MidiLink *GetMidiLinkFromOwnerNode(struct MinNode *node){
        struct MidiLink dummy;
        return (struct MidiLink *)((char *)((char *)(node)-((char *)&dummy.ml_OwnerNode-(char *)&dummy)));
}

void printSpaces(int level){
        int lokke;
        for(lokke=0;lokke<level*TABSIZE;lokke++){
                printf(" ");
        }
}

void printLink_brancheNodes(struct MidiLink *midilink,int level,int maxlevel);
void printLink_brancheClusters(struct MidiLink *midilink,int level,int maxlevel);
void printCluster(struct MidiCluster *cluster,int level,int maxlevel);


void printNode(struct MidiNode *midinode,int level,int maxlevel){
        char *nodename=NULL;
        struct MinNode *node;

        if(level==maxlevel) return;

        GetMidiAttrs(midinode,MIDI_Name,(IPTR)&nodename,TAG_END);

        printSpaces(level);
        printf(
                "%p, -%s-\n",
                midinode,
                nodename
        );

        if(level+1==maxlevel) return;

        if( ! (IsListEmpty((struct List *)&midinode->mi_OutLinks))){
                printSpaces(level);
                printf("  -OutLinks:\n");
                node=midinode->mi_OutLinks.mlh_Head;
                while(node->mln_Succ!=NULL){
                        printLink_brancheClusters(GetMidiLinkFromOwnerNode(node),level+1,maxlevel);
                        node=node->mln_Succ;
                }
        }

        if( ! (IsListEmpty((struct List *)&midinode->mi_InLinks))){
                printSpaces(level);
                printf("  -InLinks:\n");
                node=midinode->mi_InLinks.mlh_Head;
                while(node->mln_Succ!=NULL){
                        printLink_brancheClusters(GetMidiLinkFromOwnerNode(node),level+1,maxlevel);
                        node=node->mln_Succ;
                }
        }
}


BOOL printLink(struct MidiLink *midilink){
        char *linkname=NULL;

        if(midilink->ml_Node.ln_Type==NT_USER-MLTYPE_Receiver || midilink->ml_Node.ln_Type==NT_USER-MLTYPE_Sender){
                GetMidiLinkAttrs(midilink,MLINK_Name,(IPTR)&linkname,TAG_END);
                printf(
                        "%p, -%s-\n",
                        midilink,
                        linkname
                );
                return TRUE;
        }

        printf("%p, <driverdata> (private)\n",midilink);
        return FALSE;
}

void printLink_brancheNodes(struct MidiLink *midilink,int level,int maxlevel){
        struct MidiNode *midinode;

        if(level==maxlevel) return;

        printSpaces(level);
        if(printLink(midilink)==TRUE){
                midinode=midilink->ml_MidiNode;
                printSpaces(level);
                printf("  -Owner (MidiNode): \n");
                printNode(midinode,level+1,maxlevel);
        }
}

void printLink_brancheClusters(struct MidiLink *midilink,int level,int maxlevel){
        if(level==maxlevel) return;

        printSpaces(level);
        printLink(midilink);

        if(level+1==maxlevel) return;

        printSpaces(level);
        printf("  -Cluster: \n");
        printCluster(midilink->ml_Location,level+1,maxlevel);
}


void printCluster(struct MidiCluster *cluster,int level,int maxlevel){
        struct MidiLink *midilink;

        if(level==maxlevel) return;

        printSpaces(level);
        printf("clustername: -%s-\n",cluster->mcl_Node.ln_Name);

        if(level+1==maxlevel) return;

        if(!(IsListEmpty(&cluster->mcl_Receivers))){
                printSpaces(level);
                printf("  ");
                printf("-Receiver links:\n");

                midilink=(struct MidiLink *)cluster->mcl_Receivers.lh_Head;
                while(midilink->ml_Node.ln_Succ!=NULL){
                        printLink_brancheNodes(midilink,level+1,maxlevel);
                        midilink=(struct MidiLink *)midilink->ml_Node.ln_Succ;
                }
        }

        if(!(IsListEmpty(&cluster->mcl_Senders))){
                printSpaces(level);
                printf("  ");
                printf("-Sender links:\n");
                midilink=(struct MidiLink *)cluster->mcl_Senders.lh_Head;
                while(midilink->ml_Node.ln_Succ!=NULL){
                        printLink_brancheNodes(midilink,level+1,maxlevel);
                        midilink=(struct MidiLink *)midilink->ml_Node.ln_Succ;
                }
        }
}


int main(){

        APTR lock;
        struct MidiCluster *cluster;

        CamdBase=OpenLibrary("camd.library",40L);

        if(CamdBase!=NULL){

                lock=LockCAMD(CD_Linkages);

                cluster=NextCluster(NULL);
                if(cluster==NULL){

                        printf("No clusters available.\n");

                }else{

                        printf("-Clusters:\n\n");
                        do{
                                printCluster(cluster,1,6);
                                printf("\n");
                                cluster=NextCluster(cluster);
                        }while(cluster!=NULL);

                }

                UnlockCAMD(lock);
                CloseLibrary(CamdBase);

        }else{
                printf("Could not open at least V40 of camd.library.\n");
                return 1;
        }

        return 0;
}


#include proto/camd.h
#include proto/dos.h
#include proto/exec.h
#include midi/camd.h
#include stdlib.h
#include stdio.h

int main(int argc, char **argv)
{
struct MidiNode *ournode;
struct MidiLink *to;
MidiMsg mmsg;

if((ournode = Camd->CreateMidi(
MIDI_MsgQueue, 2048L, 
MIDI_SysExSize, 10000L, 
MIDI_Name, argv[0], 
TAG_END)))
{
if((to = Camd->AddMidiLink(ournode, MLTYPE_Sender, MLINK_Location, argv[1], TAG_END)))
{
mmsg.mm_Status = MS_Start;
mmsg.mm_Data1 = 0;
mmsg.mm_Data2 = 0;
Camd->PutMidi(to, mmsg.mm_Msg);

Camd->RemoveMidiLink(to); 
}
Camd->DeleteMidi(ournode); 
}

CloseLibrary(CamdBase);
return 0;
}



ReferenceEdit

APTR LockCAMD(ULONG locktype) 
void UnlockCAMD(APTR lock) 

struct MidiNode *CreateMidiA(struct TagItem *tags) 
void DeleteMidi(struct MidiNode *midinode) 
BOOL SetMidiAttrsA(struct MidiNode *midinode, struct TagItem *tags) 
ULONG GetMidiAttrsA(struct MidiNode *midinode, struct TagItem *tags) 
struct MidiNode *NextMidi(struct MidiNode *midinode) 
struct MidiNode *FindMidi(STRPTR name) 
void FlushMidi(struct MidiNode *midinode) 

struct MidiLink *AddMidiLinkA(struct MidiNode *midinode, LONG type, struct TagItem *tags) 
void RemoveMidiLink(struct MidiLink *midilink) 
BOOL SetMidiLinkAttrsA(struct MidiLink *midilink, struct TagItem *tags) 
ULONG GetMidiLinkAttrsA(struct MidiLink *midilink, struct TagItem *tags) 
struct MidiLink *NextClusterLink(struct MidiCluster *cluster, struct MidiLink *midilink, LONG type) 
struct MidiLink *NextMidiLink(struct MidiNode *midinode, struct MidiLink *midilink, LONG type) 
BOOL MidiLinkConnected(struct MidiLink *midilink) 

struct MidiCluster *NextCluster(struct MidiCluster *last)
struct MidiCluster *FindCluster(STRPTR name)

void PutMidi(struct MidiLink *link, ULONG msg) 
BOOL GetMidi(struct MidiNode *midinode, MidiMsg *msg) 
BOOL WaitMidi(struct MidiNode *midinode, MidiMsg *msg) 

void PutSysEx(struct MidiLink *midilink, UBYTE *buffer) 
ULONG GetSysEx(struct MidiNode *midinode, UBYTE *Buf, ULONG len) 
ULONG QuerySysEx(struct MidiNode *midinode) 
void SkipSysEx(struct MidiNode *midinode) 

UBYTE GetMidiErr(struct MidiNode *midinode)
WORD MidiMsgType(MidiMsg *msg) 
WORD MidiMsgLen(ULONG msg) 

void ParseMidi(struct MidiLink *midilink, UBYTE *buffer, ULONG length) 
struct MidiDeviceData *OpenMidiDevice(UBYTE *name) 
void CloseMidiDevice(struct MidiDeviceData *mididevicedata) 
LONG RethinkCAMD() 

void StartClusterNotify(struct ClusterNotifyNode *cn) 
void EndClusterNotify(struct ClusterNotifyNode *cn) 
APTR GoodPutMidi(struct MidiLink *midilink, ULONG msg, ULONG maxbuff) 
BOOL Midi2Driver(APTR driverdata, ULONG msg, ULONG maxbuff)