Aros/Developer/Docs/Libraries/CAMD
< Aros < Developer < Docs < LibrariesIntroduction
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 Specs
Nodes
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. </pre > ===Links === Links are created beween nodes Tags <pre > 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 </pre > 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. <pre > Link Links Application ----------> Cluster ----------> Application <------------ Application </pre > ===Messages === And midi messages are sent <pre > /* MidiMsg struct */ mm_Msg mm_Time mm_Status mm_Data1 mm_Data2 mm_Port mm_Data </pre > GetMidi PutMidi ====Filters ==== 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 <pre > 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
Examples
#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; }
Reference
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)