home *** CD-ROM | disk | FTP | other *** search
- MIDI LIBRARY
- ==== =======
-
- WHAT IS THE MIDI LIBRARY?
- ---- -- --- ---- --------
-
- The MIDI library is a standard Amiga disk-based library that provides
- multitasking access to MIDI resources such as the serial port. The
- library is based around a "copying" message system so that a single
- message sent in can cause several messages to be sent back out. Included
- as part of the library are tasks that convert serial I/O to MIDI messages
- which can be sent to any task that cares to listen. This provides for
- unlimited sharing of the serial port by MIDI applications.
-
- The need for such a service seems obvious in a multitasking environment.
- Without this sort of interface, two tasks trying to receive MIDI data
- from the serial port at the same time will exclude each other from
- working correctly. Neither of them will get all the data they seek. By
- using the MIDI library this problem is eliminated because there is only
- one task actually receiving data from the serial port. Data is then
- distributed to all who are waiting for it.
-
- A similar problem occurs with transmitting. MIDI is based around a
- message system. Each message contains a certain number of bytes and must
- be received intact to make sense to the receiver. If two tasks try to
- transmit data to the serial port at the same time it is likely that the
- partial messages from each stream will merge producing disastrous
- results. The MIDI library handles this by keeping messages intact, and
- again only one task is actually sending data to the serial port.
-
- The MIDI library is intended for developers writing MIDI applications to
- use with their products. The library takes care of all the grunginess of
- transferring MIDI data between your applications and the serial port.
- Instead of getting an unformatted stream of bytes your programs receive
- complete messages as asynchronous events.
-
-
- Features
- --------
-
- * Unlimited MIDI message merging.
-
- * Provides an interface for multiple MIDI applications to access
- the serial port without conflict.
-
- * Versatile MIDI filtering including message, channel, controller,
- and SysEx ID number filtering.
-
- * Exists as a standard disk-based Amiga library less than 10K in
- size.
-
- * Supports the full MIDI message specification including system
- exclusive, 3 byte SysEx ID's, and MTC.
-
- * Transfers MIDI packets using the Amiga Executive message system.
-
- * Entirely written in Assembly.
-
-
- OVERVIEW
- --------
-
- Tasks wishing to perform MIDI I/O create "source" and "destination"
- nodes. These nodes are where messages are sent to and received from.
- Sources and destinations are then "routed" together. Once connected in
- this manner, MIDI messages that are placed at the source node are
- distributed to destination nodes connected to that source. Any number of
- source and destination nodes may exist at one time and any number of
- routes can be connected to a source or destination.
-
- In addition to piping information along, a route processes MIDI data.
- The following operations can be performed by a route in any combination:
-
- Message filtering
- Channel filtering
- Channel offset
- Note offset
- Controller number filtering
- Sys/Ex id number filtering
-
- In addition to nodes that the applications create there are "resident"
- nodes that launch built-in tasks. Currently the only built-in tasks are
- for transmitting and receiving MIDI messages to and from the Amiga's
- serial port.
-
- Covered in this remainder of this document are in depth descriptions of
- each of the major sections and concepts within the MIDI Library. In
- general, there are a few rules you should keep in mind when using the
- MIDI Library (and all other Amiga resources):
-
- 1. You must free any resource that you allocate (such as an MSource,
- MDest, MRoute, MidiPacket, etc) when you are done with it.
-
- 2. Only those fields within a structure that are explicitly
- documented as writable should be treated as such.
-
- 3. Any shared lists must be locked prior to examination (there are
- various list locking functions described in the Inner Workings
- section).
-
- More detailed information about each MIDI Library function can be found
- in midi.doc. Examine midi/midi.h (or midi/midi.i) for more information
- on the structures used within the MIDI Library and some handy constants
- not described in this document.
-
- This document assumes that you have access to and are familiar with MIDI
- 1.0 Spec v4.0 from the IMA. Also, familiarity with C and the Amiga Rom
- Kernel are assumed.
-
-
- LIBRARY
- -------
-
- Before using the MIDI library it must be opened like any other Amiga
- library. The global symbol for the library base is "MidiBase".
-
- MidiBase = OpenLibrary (MIDINAME,MIDIVERSION);
-
- The constants MIDINAME and MIDIVERSION are defined in the include file
- midi/midi.h. MIDINAME is "midi.library" and as of this writing
- MIDIVERSION is 7.
-
- When done using the library you should close it:
-
- CloseLibrary (MidiBase);
-
-
- SOURCE AND DESTINATION NODES
- ------ --- ----------- -----
-
- The MIDI source and destination nodes are the terminals for MIDI
- communication. Messages are placed at a source to be distributed to
- destinations through whatever routes are connected to the source.
-
- Nodes can be either public or private. Private nodes can only be
- accessed by the task that created them. Public nodes are available to
- everyone. This way an application can perform it's own private
- communications or can be made available for routing in a patch bay.
-
- The MIDI source is defined in "midi/midi.h" is follows:
-
- struct MSource {
- struct Node Node;
- struct Image *Image;
- struct MinList RPList;
- APTR UserData;
- UWORD RouteMsgFlags;
- UWORD RouteChanFlags;
- };
-
- Node
- An instance of an Exec Node used for linking public nodes into
- the library's source list. The ln_Name field is set for public
- nodes to the name supplied by the caller. ln_Type is set to
- NT_MSOURCE for user MSource's or NT_RESMSOURCE for resident
- MSource's.
-
- Image
- Points to an Intuition Image structure. The image may be used
- by graphics-based patch bay applications. It is only used for
- public nodes. A NULL here indicates that the creator of this
- node does not have an Image for it; patch bay programs may deal
- with that as they see fit.
-
- RPList
- A linked list of MRoutePtr structures. Each member of the list
- is attached to an MRoute structure. Scanning this list allows
- you to determine what other nodes are connected to this one.
-
- UserData
- A generic pointer to any user extension data. For resident
- nodes this points to an instance of an MTaskInfo structure.
-
- RouteMsgFlags
- RouteChanFlags
- The sum of MsgFlags and ChanFlags, respectively, in all routes
- attached to the MSource. This is used internally by the
- message distributor as a pre-check for which message classes
- actually need to be transmitted.
-
- In general you will only be concerned with a pointer to an MSource, not
- its contents. It is not safe to touch anything in the MSource structure
- except UserData and then only if you created the MSource. You are free
- to examine anything in the MSource structure such as RPList to determine
- the sort of route connections to the MSource. If you plan to do this, be
- sure to read the section on the Inner Workings so that you will
- understand all the necessary precautions.
-
- There are three functions dealing with MSource's:
-
- CreateMSource (name,image)
- Allocates, initializes, and returns a pointer to a new MSource
- structure. If name is non-NULL the MSource will be considered
- public and will be linked into the library's source list.
- Otherwise it will be considered private and won't be linked
- into the library's source list.
-
- DeleteMSource (source)
- Removes and frees a source created by CreateMSource().
-
- FindMSource (name)
- Looks for a public MSource with the specified name. If it is
- found a pointer to it is returned.
-
- See "midi.doc" for more thorough information on these and other MIDI
- Library functions.
-
- The MIDI destination is defined in "midi/midi.h" is follows:
-
- struct MDest {
- struct Node Node;
- struct Image *Image;
- struct MinList RPList;
- struct MsgPort *DestPort;
- APTR UserData;
- struct MRouteInfo DefaultRouteInfo;
- };
-
- These fields differ from an MSource
-
- Node
- The same as in an MSource except ln_Type is set to NT_MDEST for
- user MDest's or NT_RESMDEST for resident MDest's.
-
- DestPort
- Points to an Exec MsgPort that is automatically created. This
- is where MIDI messages will arrive. The port flags are set to
- PA_SIGNAL so you can Wait() for something to arrive. You don't
- GetMsg() from this port, however. See the messages section for
- the proper way to read messages.
-
- DefaultRouteInfo
- Used as storage for the default connection options for this
- MDest. There is more on this subject in the Routing section.
-
- The only field in this structure that you are likely to ever need to
- access is the DestPort since you will need to Wait() for messages to
- arrive there. Otherwise, the same guidelines that apply to MSource's
- apply to MDest's: don't tamper with anything other than UserData and
- only if you created the MDest.
-
- As with MSource there are three functions dealing with MDest's that have
- essentially the same functions as those for MSource's:
-
- CreateMDest (name,image)
- Allocates, initializes, and returns a pointer to a new MDest
- structure. If name is non-NULL the MDest will be considered
- public and will be linked into the library's destination list.
- Otherwise it will be considered private.
-
- DeleteMDest (source)
- Removes and frees a source created by CreateMDest(). Also any
- unread messages will be freed.
-
- FindMDest (name)
- Looks for a public MDest with the specified name. If it is
- found a pointer to it is returned.
-
- FlushMDest (dest)
- Disposes of any MidiPackets pending at the specified MDest.
-
- At this point it is worth discussing the Resident Nodes currently
- available. Resident nodes are public nodes that are always present in
- the public node lists and are physically part of the MIDI Library. They
- can be routed to just like any other public node as will be described in
- the next section. There are currently two resident nodes.
-
- name type description
- ---- ---- -----------
- MidiIn source Converts incoming data from the Amiga's serial port
- to MIDI Messages. Any MDest's that you route to
- MidiIn will be able to receive messages from any
- MIDI devices connected to the serial port.
-
- MidiOut dest Converts MidiPackets to data sent out the Amiga's
- serial port. Any MSource's that you route to
- MidiOut will then be able to transmit MIDI messages
- to devices connected to the serial port. Any
- number of MSource's can be routed to it without
- fear of mangled data; messages are merged
- properly. Each message sent to it will be
- transmitted to the serial port in the order
- received.
-
-
- ROUTES
- ------
-
- Routes are the "cables" that connect sources to destinations. Nodes can
- have any number of routes connected to them and routes may be connected
- in parallel. Additionally routes process MIDI messages as they are
- transferred along them.
-
- The route structure and related structures are defined in "midi/midi.h"
- is follows:
-
- The MRoute structure is the actual route structure managed by the
- library. You probably need not be concerned with it's contents.
-
- struct MRoute {
- struct MSource *Source;
- struct MDest *Dest;
- struct MRoutePtr SRoutePtr, DRoutePtr;
- struct MRouteInfo RouteInfo;
- };
-
- Source
- Points to the source end or input to this route. If is
- NULL, then the source no longer exists.
-
- Dest
- Points to the destination end or output of this route. If
- is NULL, then the destination no longer exists.
-
- SRoutePtr
- DRoutePtr
- Instances of the MRoutePtr structure. These are linked
- into the source and destination RPLists respectively. See
- midi/midi.h for the actual MRoutePtr structure definition.
-
- RouteInfo
- An instance of an MRouteInfo structure. This is a copy of
- data supplied by the user.
-
- When creating a route you have the option of using the default MRouteInfo
- structure within the target MDest or supplying your own. This structure
- is what determines the behavior of a route: filtering, event processing,
- etc. There is a great deal of flexibility offered by this system.
-
- struct MRouteInfo {
- UWORD MsgFlags;
- UWORD ChanFlags;
- BYTE ChanOffset;
- BYTE NoteOffset;
- struct RIMatch SysExMatch;
- struct RIMatch CtrlMatch;
- };
-
- MsgFlags
- Flag bits indicating which messages are to be supported by this
- route. "midi/midi.h" contains MMF_ constants which may be ORed
- together. A value of MMF_ALL indicates all message types.
-
- ChanFlags
- Flag bits indicating which channels for channel messages are to
- be supported by this route. The least significant bit
- corresponds to MIDI channel 1, the most significant bit
- corresponds to MIDI channel 16. A value of 0xffff indicates
- all channels.
-
- ChanOffset
- A signed offset to be applied to all channel messages passed
- through this route. If the resulting channel is out of range
- the message is not sent.
-
- NoteOffset
- A signed transposition offset to be applied to note on and off
- messages in half steps. If the resulting note number is out of
- range the message is not sent.
-
- SysExMatch
- An instance of an RIMatch structure. It allows you to specify
- up to three one-byte System Exclusive ID numbers or one
- three-byte ID to pass or block through this route. If left
- unset, all will be passed. To use this the MMF_SYSEX bit must
- be set in MsgFlags. See below for more on this.
-
- CtrlMatch
- An instance of an RIMatch structure. It allows you to specify
- up to three controller numbers to pass or block through this
- route. If left unset, all will be passed. To use this the
- MMF_CTRL bit must be set in MsgFlags.
-
- The RIMatch structure is used to specify up to three values to match.
-
- struct RIMatch {
- UBYTE Flags;
- UBYTE Match[RIM_MAXCOUNT];
- };
-
- Flags
- Indicates how the value(s) in Match should be treated. A value
- of 0 causes Match to be ignored. A value of 1 to 3 is used to
- specify how many one-byte values are contained in Match.
- Without any other flags set, this indicates that only the
- value(s) in Match will pass through this route.
-
- If the RIMF_EXCLUDE bit is set (OR with value of 1-3), the
- logic is reversed such that all except those values in Match
- are passed.
-
- SysExMatch only: If the RIMF_EXTID bit is set, Match is
- assumed to contain exactly one three-byte System Exclusive ID.
- This may be combined with RIMF_EXCLUDE.
-
- Match
- Value(s) to match packed left to right.
-
- In order to create a route you need to have a source pointer, a
- destination pointer, and optionally a properly filled out MRouteInfo
- structure. The contents of your MRouteInfo is copied to the created
- route so you do not need to preserve it after creation.
-
- There are several functions dealing with route management. First a note
- about public nodes. Since public nodes are available to other tasks
- besides the creator there needs to be a way to insure the validity of a
- given node between the time that someone finds it and the time that
- someone attempts to route to it. There is a pair of functions to lock
- the node lists to prevent a node from being removed while you are dealing
- with it. Additionally there are some special routing functions for
- dealing with public nodes that lock the lists for you. Thus, there is
- route creation function for every permutation of public and private nodes.
-
- source dest function
- ------ ---- --------
- private private CreateMRoute
- private public MRouteSource
- public private MRouteDest
- public public MRoutePublic
-
- CreateMRoute (source,dest,routeinfo)
- Allocates and links a route into the specified source and
- destination nodes. The data pointed to by routeinfo, if
- supplied, is copied to the new route structure. This is
- primarily used when both source and destination are private.
-
- MRouteSource (source,destname,routeinfo)
- Routes a source to a named public destination.
-
- MRouteDest (sourcename,dest,routeinfo)
- Routes a named public source to a destination.
-
- MRoutePublic (sourcename,destname,routeinfo)
- Routes a named public source to a named public destination.
-
- In all cases above, you may supply your own MRouteInfo by passing a
- pointer to it or use the DefaultMRouteInfo within the target MDest by
- passing NULL instead.
-
- The remaining functions deal with modifying and deleting routes:
-
- ModifyMRoute (route,newrouteinfo)
- Copies the contents of the new MRouteInfo structure to the
- specified route.
-
- DeleteMRoute (route)
- Unlinks and frees a route.
-
- SetDefaultMRouteInfo (dest,newrouteinfo)
- Copies the contents of the supplied to MRouteInfo to
- DefaultMRouteInfo in the supplied MDest. This does not affect
- any routes already connected to the MDest, only the template
- for creating new routes. You should only call this routine on
- MDest's that you created.
-
- You are responsible for deleting any routes you create even if the nodes
- it connected have been deleted. You should not delete or modify anyone
- else's routes.
-
-
- MESSAGES AND PACKETS
- -------- --- -------
-
- From the point of view of the MIDI Library, a MIDI Message is simply an
- array of UBYTEs containing a status byte as its first byte and any data
- bytes associated with that message. With the exception of system
- exclusive, all messages are from 1 to 3 bytes in length. A given status
- byte always has the same number of data bytes. Messages never contain
- embedded Real Time status bytes as these are sent as separate messages.
- Messages never rely on running status so there will always be a status
- byte at the beginning of every message and there will never be more than
- one message worth of data bytes within that message.
-
- System exclusive messages can be any length. Also, the last byte in a
- system exclusive message is the EOX status byte used as a terminator
- (like '\0' in a C string).
-
- The MidiPacket structure is built around the above MIDI Message concept.
- This structure is what arrives at the DestPort within an MDest.
-
- struct MidiPacket {
- struct Message ExecMsg;
- UWORD Type;
- UWORD Length;
- ULONG reserved;
- UBYTE MidiMsg[4];
- };
-
- ExecMsg
- The standard Exec Message node used to send to MsgPorts.
-
- Type
- An MMF_ message type value for the message contained in this
- packet as returned by MidiMsgType().
-
- Length
- The length of this message in bytes as returned by
- MidiMsgLength().
-
- MidiMsg
- The actual message as described above. There always at least 4
- bytes here, but the actual length that you should use is found
- in Length. Specifically, system exclusive packets more often
- than not have more than 4 bytes here.
-
- MIDI Messages (just the UBYTE array) are used for transmitting messages
- to an MSource. MidiPackets are used for receiving messages at an MDest.
- MidiPackets are always created by the MIDI Library, never by you.
- Consider them entirely read-only.
-
- These functions deal with receiving MidiPackets:
-
- GetMidiPacket (dest)
- Gets the first MidiPacket available at a destination and
- returns a pointer to it. If none are available NULL is
- returned. Any MidiPacket that you receive from GetMidiPacket()
- should be freed with FreeMidiPacket(). See below for an
- example packet reader.
-
- FreeMidiPacket (packet)
- Frees a MidiPacket received from GetMidiPacket().
-
- These functions deal with sending MIDI Messages:
-
- PutMidiMsg (source,msg)
- Places a single MIDI Message at a source for distribution.
- Upon return you may recycle your msg buffer since its contents
- has been copied to any MidiPackets that have been sent. This
- function assumes that you have constructed a valid MIDI message
- as described above. Invalid or undefined messages are ignored,
- however an unterminated system exclusive message cannot be
- detected and runs the risk of crashing the machine.
-
- PutMidiStream (source,fillbuffer,buf,bufsize,cursize)
- Converts an unformatted data stream into MIDI messages which
- are then sent by calling PutMidiMsg(). See midi.doc for proper
- usage.
-
- These functions give you information about specific MIDI Messages:
-
- MidiMsgType (msg)
- Returns an MMF_ flag indicating the type message. It returns 0
- for invalid or undefined messages.
-
- MidiMsgLength (msg)
- Returns the number of bytes in a message. For non-exclusive
- messages this is the status byte + data bytes. For system
- exclusive messages it is status byte + data bytes + EOX. 0 is
- returned for invalid or undefined messages.
-
- These functions deal with receiving MIDI Messages w/o the packets and are
- primarily here for backwards compatibility. They do little more than
- apply an offset from the beginning of the MidiPacket to the MidiMsg field
- and call the corresponding MidiPacket function. It is not recommended
- that these be used in new code since they are less efficient from the
- point of the Library and the caller:
-
- GetMidiMsg (dest)
- Gets the first MIDI message available at a destination and
- returns a pointer to it. If none are available NULL is
- returned. Any message that you receive from GetMidiMsg()
- should be freed with FreeMidiMsg(). See below for an example
- message reader.
-
- FreeMidiMsg (msg)
- Frees a message received from GetMidiMsg().
-
- Some additional notes about messages:
-
- 1. Invalid or undefined status bytes are ignored.
-
- 2. EOX is not considered a valid status byte on its own. It is only
- used to terminate system exclusive messages and will be ignored
- if sent by itself using PutMidiMsg().
-
- 3. Incomplete messages (such as system exclusive messages without a
- manufacturer ID) are ignored.
-
- 4. Note On messages with velocity == 0 are considered Note Off
- messages. MidiMsgType() will return MMF_NOTEOFF rather than
- MMF_NOTEON for these.
-
- 5. Controller numbers 121-127 are reserved for MIDI Mode Messages
- and are treated as such. MidiMsgType() will return MMF_MODE
- rather than MMF_CTRL for these.
-
-
- Here is a code fragment showing the recommended MidiPacket receive
- technique:
-
- domidi(dest)
- struct Dest *dest;
- {
- struct MidiPacket *packet;
-
- while (!done) {
- Wait (1L << dest->DestPort->mp_SigBit);
- while (packet = GetMidiPacket (dest)) {
- /* process the packet: */
- /* perhaps examine packet->Type */
- /* or packet->Length */
- /* or the actual Message in packet->MidiMsg */
- .
- .
- /* then free it */
- FreeMidiPacket (packet);
- }
- }
- }
-
-
- It's important to understand a little about how MidiPackets are
- allocated. For all message types other than System Exclusive,
- MidiPackets are allocated from a pre-allocated pool of MidiPackets. This
- is considerably quicker than having to call AllocMem() each time a
- MidiPacket needs to be allocated. The pool gets initialized the first
- time you create a route. If the pool becomes full, it gets extended but
- will not be pruned until someone calls FlushMDest() or DeleteMDest(). It
- gets totally expunged when the last user of the library calls
- CloseLibrary().
-
- If you cache MidiPackets for any length of time, your memory may vanish
- to increase the size of the packet pool. In order to get it back you
- will have to call FlushMDest().
-
- System Exclusive packets are allocated using AllocMem() which explains
- why they are marginally slower to route than non-exclusive messages.
-
-
- INNER WORKINGS
- ----- --------
-
- This section is for the more adventurous MIDI programmer. The
- information here is necessary for authors of patch bay or other route
- managing applications.
-
- MidiBase
- --------
-
- The structure of the library base is defined in "midi/midibase.h". This
- structure is strictly READ-ONLY. You may examine fields with care as
- noted below.
-
- struct MidiBase {
- struct Library libnode;
- struct List SourceList, DestList;
- struct SignalSemaphore ListSemaphore;
- struct SignalSemaphore RouteSemaphore;
- BPTR SegList;
- APTR SysBase, DosBase;
- struct MinList SignalList;
- };
-
- libnode
- Standard Amiga library node.
-
- SourceList
- An Exec linked list containing all public MSource nodes.
-
- DestList
- An Exec linked list containing all public MDest nodes.
-
- ListSemaphore
- A SignalSemaphore for locking the source and destination
- lists. This is the semaphore used when you call LockMidiBase()
- or UnlockMidiBase(). Exclusive access to lists is required
- when managing or scanning either the source or destination
- list. It is not required for message propagation. It is
- required for route management only when a public node is
- involved.
-
- RouteSemaphore
- A SignalSemaphore for locking the route system. The routines
- LockMRoutes() and UnlockMRoutes() use this semaphore.
- Exclusive access to the routing system is required for message
- propagation and route management. It is not needed for
- managing or scanning the node lists. Use this with care since
- it blocks message propagation.
-
- SegList
- A BPTR to the segment list for the library.
-
- SysBase & DosBase
- The library's pointers to Exec and Dos.
-
- SignalList
- The list of MListSignal nodes.
-
- Only SourceList and DestList are likely to be of any interest to patch
- bay programmers. The rest can be ignored.
-
- These routines are useful for examining the base:
-
- LockMidiBase()
- Gains exclusive access to the source and destination lists.
- Use of this will block anyone else from managing nodes or
- scanning the lists. Messages propagation is not blocked,
- however. Calls may be nested but each call must be matched
- with a call to UnlockMidiBase().
-
- UnlockMidiBase()
- Relinquishes exclusive access to the source and destination
- lists.
-
- These routines are useful for examining the routes attached to a specific
- source or destination:
-
- LockMRoutes()
- Gains exclusive access to the route system. Use of this will
- block message propagation and route management. Calls may be
- nested but each call must be matched with a call to
- UnlockMRoutes().
-
- UnlockMidiBase()
- Relinquishes exclusive access to the route system.
-
- You shouldn't be very likely to need to lock the route system, however,
- and if you do it should only be to read the route lists not to modify
- anything. A patch bay application should not use this approach to keep
- track of its routes. Instead it must maintain its own list of routes.
- As long as everyone observes the rule of modifying only their own
- structures there shouldn't be any trouble.
-
- Signals
- -------
-
- There is a system by which your task can be signaled when either of the
- public node lists changes. This permits a patch bay system to be
- notified when it needs to redraw its display of available nodes.
-
- struct MListSignal {
- struct MinNode Node;
- struct Task *SigTask;
- UBYTE SigBit;
- UBYTE Flags;
- };
-
- Node
- Standard Exec MinNode used to link this MListSignal into
- SignalList.
-
- SigTask
- Pointer to the task owning this MListSignal.
-
- SigBit
- Signal bit for this MListSignal. Used to Signal() SigTask on
- public node list change.
-
- Flags
- Flag bits describing which lists to watch for this signal.
-
- This entire structure should be considered READ-ONLY. The only field you
- should be concerned with examining is SigBit since you'll need to Wait()
- for that in order to find out when a list changes. The signals do not
- accumulate and you don't know what changed when you receive one, just
- that something you were looking for has changed since you last received a
- signal.
-
- These functions manage MListSignals:
-
- CreateMListSignal (flags)
- Adds your task to the list of those to be signaled when the
- public node lists change. Flags contains either MLSF_SOURCE,
- MLSF_DEST or both depending on which list(s) you want to
- monitor. The function returns a pointer to an MListSignal
- which you must keep and pass to DeleteMListSignal() when you
- are done with it. A signal bit is allocated for you when you
- call this and is placed in SigBit.
-
- DeleteMListSignal (signal)
- Removes and frees an MListSignal allocated by CreateMListSignal.
-
-
- Resident Nodes
- -------- -----
-
- As noted before there are some nodes that are always present. They are
- created by the library when it is first loaded. These nodes are attached
- to built-in tasks (actually AmigaDOS Processes) that are launched when
- the nodes are routed to. There are currently only two resident nodes:
- one for receiving from the serial port and one for transmitting to the
- serial port.
-
- MidiIn source Launches a task called MidiIn running at +30
- priority when it is first routed to. It receives
- data from the serial port and converts it to MIDI
- messages which are posted to its MSource node.
- Anyone with destinations routed to this node will
- receive MIDI messages from it.
-
- MidiOut dest Launches a task called MidiOut which also runs at
- +30 priority. It is responsible for receiving
- messages from it's MDest node and sending them to
- the serial port.
-
- Resident nodes can be identified by a node type value (in ln_Type) of
- NT_RESMSOURCE or NT_RESMDEST. Resident nodes have an additional
- MTaskInfo structure attached to them that is pointed to by the UserData
- field in the MSource or MDest structure.
-
- This rest of the information about resident nodes is provided merely for
- the curious and is not terribly useful. Consider ALL of this stuff to be
- READ ONLY. And be forewarned that it may change if necessary. The
- MTaskInfo structure is defined in "midi/midibase.h".
-
- struct MTaskInfo {
- char *Name;
- WORD Pri;
- void (*Entry)();
- UWORD Stack;
- UWORD Sources;
- struct MNodeInfo *SourceList;
- struct Dests;
- struct MNodeInfo *DestList;
- struct SignalSemaphore Semaphore;
- UWORD UsageCount;
- struct MsgPort *TaskPort;
- BPTR Segment;
- };
-
- These fields are defined within each task's module:
-
- Name
- Points to the name of the task.
-
- Pri
- The task's priority.
-
- Entry
- The start of the task's code.
-
- Stack
- The size of stack to allocate for the task.
-
- Sources
- The the number of MSource nodes defined for this task.
-
- SourceList
- Points to an array of MNodeInfo structures containing the
- definition of this task's MSource nodes.
-
- Dests
- Is the the number of MDest nodes defined for this task.
-
- DestList
- Points to an array of MNodeInfo structures containing the
- definition of this task's MDest nodes.
-
- These fields are managed by the library:
-
- Semaphore
- A signal semaphore for locking this MTaskInfo structure. This
- is only used when launching or shutting down this task.
-
- UsageCount
- The number of accessors to this task. If it is non-zero the
- task is running otherwise it is dormant.
-
- TaskPort
- Points to the message port used to communicate with the task.
-
- Segment
- A BPTR to a fake segment list necessary for CreateProc(). The
- segment contains a jump instruction to the startup code for the
- task. The task's code is actually part of the library's
- segment list. This might be considered making use of
- undocumented features, but as long as no one tries to
- UnloadSeg() this segment (and no one should) there shouldn't be
- any trouble.
-
- The MNodeInfo structure referred to above is used to define the resident
- source or destination nodes attached to this task. Tasks are not
- restricted to just one resident node, but that is the current usage.
- This structure is also defined in "midi/midibase.h".
-
- struct MNodeInfo {
- char *Name;
- struct Image *Image;
- APTR Node;
- };
-
- Name
- Points to the name of the node. This shouldn't ever be NULL.
-
- Image
- Points to an Intuition Image structure for this node. This may
- be NULL (and currently is in all cases).
-
- Node
- Points to the node allocated for this MNodeInfo structure so
- that the task can find it easily.
-
-
- SERIAL I/O CONSIDERATIONS
- ------ --- --------------
-
- The resident nodes that access the serial port do so by using
- serial.device - the standard device driver for the serial port.
- serial.device does however have a hard time receiving MIDI data at full
- speed, even with the SERF_RAD_BOOGIE flag set. It occasionally loses a
- byte or two on larger transfers such as long system exclusive messages.
- I have heard that there are also similar problems when running at 19200
- baud, so it seems likely that some attention will be given to improving
- serial.device in future releases of the operating system (like v1.4).
-
- In the meantime, it is strongly recommended that you make sure that you
- get what you expect when reading system exclusive messages from MidiIn.
- Use whatever error detection methods are appropriate for the data being
- transferred (like dump sizes or checksums).
-
- Some sequencers use interrupt driven serial I/O for speed reasons.
- These, from what I've seen, do not suffer from the lost data problems
- that serial.device does. I have given the matter of using my own serial
- interrupt handler some thought and these are my reasons for not doing so
- at this time.
-
- 1. serial.device is the polite way of accessing the serial hardware
- and it should be used whenever possible as it does provide a nice
- interface to the hardware and is presumably compatible with any
- future serial hardware that comes along.
-
- 2. Serial interrupt handlers are exclusive: only one task can own
- the serial interrupts at a time. Right now there are a few MIDI
- applications that use serial.device directly for MIDI. These do
- not directly conflict with the MIDI Library so long as both are
- not attempting to read or write data to the serial port at
- exactly the same time. If MIDI Library were to use its own
- interrupt system, these types of applications will not be able to
- access MIDI at all while someone is using MIDI Library.
-
- 3. The problem does not appear bad enough (at least in my own
- applications) to warrant it.
-
- 4. Commodore will presumably fix the problem eventually.
-
- 5. MIDI Library uses memory allocations occasionally during message
- routing. Interrupt code cannot call the memory allocator. (This
- can be worked around by implement the interrupt handler as simply
- a queue that is read by a task which in turn calls MIDI Library)
-
-
- CONCLUSION
- ----------
-
- Hopefully this document has provided you with an understanding of the
- MIDI library and will enable you to make use of its features in your own
- MIDI applications.
-
- Good luck.
-
-
- COPYRIGHT AND DISTRIBUTIONS
- --------- --- -------------
-
- The MIDI Library is Copyright (c) 1987, 1988, Pregnant Badger Music. All
- rights reserved. The MIDI Library may be used in and included with
- commercial products with the following provisos:
-
- 1. Pregnant Badger Music should be kept informed of your intent to
- release products that make use of the MIDI Library so that we may
- keep you informed of changes, updates, etc.
-
- 2. The above copyright notice should be included somewhere in the
- documentation accompanying any such commercial products.
-
- Bill Barton
- Pregnant Badger Music
- 1111 El Sur Way
- Sacramento, CA 95864
- (916) 487-9472
-
- Bix: peabody
- PLink: peabody
-
-