NAME

MIDI::ALSA - the ALSA library, plus some interface functions

SYNOPSIS

use MIDI::ALSA(SND_SEQ_EVENT_PORT_UNSUBSCRIBED);
MIDI::ALSA::client( 'Perl MIDI::ALSA client', 1, 1, 0 );
MIDI::ALSA::connectfrom( 0, 14, 0 );  # input port is lower (0)
MIDI::ALSA::connectto( 1, 20, 0 );   # output port is higher (1)
while (1) {
    my @alsaevent = MIDI::ALSA::input();
    if ($alsaevent[0] == SND_SEQ_EVENT_PORT_UNSUBSCRIBED) { last; }
    MIDI::ALSA::output( @alsaevent );
}

DESCRIPTION

This module offers a Perl interface to the ALSA library. It is a call-compatible translation into Perl of the Lua module midialsa http://www.pjb.com.au/comp/lua/midialsa.html which is in turn based on the Python modules alsaseq.py and alsamidi.py by Patricio Paez.

It also offers some functions to translate events from and to the event format used in Sean Burke's MIDI-Perl module.

Nothing is exported by default, but all the functions and constants can be exported, e.g.: use MIDI::ALSA(client, connectfrom, connectto, id, input, output);

The event-type constants, beginning with SND_SEQ_, are available not as scalars, but as module subroutines with empty prototypes. They must therefore be used without a dollar-sign e.g.: if ($event[0] == MIDI::ALSA::SND_SEQ_EVENT_PORT_UNSUBSCRIBED) { ...

FUNCTIONS

Functions based on those in alsaseq.py: client(), connectfrom(), connectto(), fd(), id(), input(), inputpending(), output(), start(), status(), stop(), syncoutput()

Functions based on those in alsamidi.py: noteevent(), noteonevent(), noteoffevent(), pgmchangeevent(), pitchbendevent(), chanpress()

Functions to interface with MIDI-Perl: alsa2opusevent(), alsa2scoreevent(), scoreevent2alsa(), rawevent2alsa()

client(name, ninputports, noutputports, createqueue)

Create an ALSA sequencer client with zero or more input or output ports, and optionally a timing queue. ninputports and noutputports are created if the quantity requested is between 1 and 4 for each. If createqueue = true, it creates a queue for stamping the arrival time of incoming events and scheduling future start times of outgoing events.

Unlike in the alsaseq.py Python module, it returns success or failure.

connectfrom( inputport, src_client, src_port )

Connect from src_client:src_port to inputport. Each input port can connect from more than one client. The input() function will receive events from any intput port and any of the clients connected to each of them. Events from each client can be distinguised by their source field.

Unlike in the alsaseq.py Python module, it returns success or failure.

connectto( outputport, dest_client, dest_port )

Connect outputport to dest_client:dest_port. Each outputport can be Connected to more than one client. Events sent to an output port using the output() funtion will be sent to all clients that are connected to it using this function.

Unlike in the alsaseq.py Python module, it returns success or failure.

fd()

Return fileno of sequencer.

id()

Return the client number, or 0 if the client is not yet created.

input()

Wait for an ALSA event in any of the input ports and return it. ALSA events are returned as an array with 8 elements:

{type, flags, tag, queue, time, source, destination, data}

Unlike in the alsaseq.py Python module, the time element is in floating-point seconds. The last three elements are also arrays:

source = { src_client,  src_port }
destination = { dest_client,  dest_port }
data = { varies depending on type }

The source and destination arrays may be useful within an application for handling events differently according to their source or destination. The event-type constants, beginning with SND_SEQ_, are available as module subroutines with empty prototypes, not as strings, and must therefore be used without any dollar-sign e.g.:

if ($event[0] == MIDI::ALSA::SND_SEQ_EVENT_PORT_UNSUBSCRIBED) { ...

Note that if the event is of type SND_SEQ_EVENT_PORT_UNSUBSCRIBED then the remote client and port do not seem to be correct...

The data array is documented in http://alsa-project.org/alsa-doc/alsa-lib/seq.html

inputpending()

Return the number of bytes available in input buffer. Use before input() to wait till an event is ready to be read. If a connection terminates, then inputpending() returns, and the next event will be of type SND_SEQ_EVENT_PORT_UNSUBSCRIBED

output( {type, flags, tag, queue, time, source, destination, data} )

Send an ALSA-event-array to an output port. The format of the event is dicussed in input() above. The event will be output immediately either if no queue was created in the client, or if the queue parameter is set to SND_SEQ_QUEUE_DIRECT and otherwise it will be queued and scheduled.

If only one port exists, all events are sent to that port. If two or more output ports exist, the dest_port of the event determines which to use. The smallest available port-number ( as created by client() ) will be used if dest_port is less than it, and the largest available port-number will be used if dest_port is greater than it.

An event sent to an output port will be sent to all clients that were subscribed using the connectto() function.

If the queue buffer is full, output() will wait until space is available to output the event. Use status() to know how many events are scheduled in the queue.

start(queue)

Start the queue. It is ignored if the client does not have a queue.

status(queue)

Return { status, time, events } of the queue.

Status: 0 if stopped, 1 if running.
Time: current time in seconds.
Events: number of output events scheduled in the queue.

If the client does not have a queue the value {0,0,0} is returned. Unlike in the alsaseq.py Python module, the time element is in floating-point seconds.

stop(queue)

Stop the queue. It is ignored if the client does not have a queue.

syncoutput(queue)

Wait until output events are processed.

noteevent( ch, key, vel, start, duration )

Returns an ALSA-event-array, to be scheduled by output(). Unlike in the alsaseq.py Python module, the start and duration elements are in floating-point seconds.

noteonevent( ch, key, vel )

Returns an ALSA-event-array to be sent directly with output().

noteoffevent( ch, key, vel )

Returns an ALSA-event-array to be sent directly with output().

pgmchangeevent( ch, value, start )

Returns an ALSA-event-array to be sent by output(). If start is not used, the event will be sent directly; if start is provided, the event will be scheduled in a queue. Unlike in the alsaseq.py Python module, the start element, when provided, is in floating-point seconds.

pitchbendevent( ch, value, start )

Returns an ALSA-event-array to be sent by output(). If start is not used, the event will be sent directly; if start is provided, the event will be scheduled in a queue. Unlike in the alsaseq.py Python module, the start element, when provided, is in floating-point seconds.

chanpress( ch, value, start )

Returns an ALSA-event-array to be sent by output(). If start is not used, the event will be sent directly; if start is provided, the event will be scheduled in a queue. Unlike in the alsaseq.py Python module, the start element, when provided, is in floating-point seconds.

alsa2opusevent(alsaevent)

Returns an event in the millisecond-tick score-format used by the MIDI.lua and MIDI.py modules, based on the opus-format in Sean Burke's MIDI-Perl CPAN module. See: http://www.pjb.com.au/comp/lua/MIDI.html#events

alsa2scoreevent(alsaevent)

Returns an event in the millisecond-tick score-format used by the MIDI.lua and MIDI.py modules, based on the score-format in Sean Burke's MIDI-Perl CPAN module. See: http://www.pjb.com.au/comp/lua/MIDI.html#events

Since it combines a note_on and a note_off event into one note event, it will return nil when called with the note_on event; the calling loop must therefore detect nil and not, for example, try to index it.

scoreevent2alsa(event)

Returns an ALSA-event-array to be scheduled in a queue by output(). The input is an event in the millisecond-tick score-format used by the MIDI.lua and MIDI.py modules, based on the score-format in Sean Burke's MIDI-Perl CPAN module. See: http://www.pjb.com.au/comp/lua/MIDI.html#events

For example: ALSA.output(ALSA.scoreevent2alsa{'note',4000,1000,0,62,110})

rawevent2alsa()

Unimplemented

DOWNLOAD

This Perl version is available from CPAN at http://search.cpan.org/perldoc?MIDI::ALSA

The Lua module is available as a LuaRock in http://luarocks.org/repositories/rocks/index.html#midi so you should be able to install it with the command: # luarocks install midialsa

TO DO

Certainly there should be a way of checking the current status of a connection, like is_still_connectedto() and is_still_connectedfrom() or something, so that if a connection has vanished the application can handle it gracefully.

Probably there should be disconnectto() and disconnectfrom()

Perhaps there should be a general connect_between() mechanism, allowing the interconnection of two other clients, a bit like aconnect 32 20

There should be a way of getting the textual information about the various clients, like "TiMidity" or "Roland XV-2020" or "Virtual Raw MIDI 2-0" and so on.

If an event is of type SND_SEQ_EVENT_PORT_UNSUBSCRIBED then the remote client and port seem to be zeroed-out, which makes it hard to know which client has disconnected.

output() and input() seem to filter out all non-sounding events, like text_events and sysex; this ought to be adjustable.

AUTHOR

Peter J Billam, http://www.pjb.com.au/comp/contact.html

SEE ALSO

aconnect -oil
http://pp.com.mx/python/alsaseq
http://search.cpan.org/perldoc?MIDI::ALSA
http://www.pjb.com.au/comp/lua/midialsa.html
http://luarocks.org/repositories/rocks/index.html#midialsa
http://www.pjb.com.au/comp/lua/MIDI.html
http://www.pjb.com.au/comp/lua/MIDI.html#events
http://alsa-project.org/alsa-doc/alsa-lib/seq.html
http://alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__ev__note.html
http://alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__ev__ctrl.html
http://alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__ev__queue__control.html
http://alsa-project.org/alsa-doc/alsa-lib/group___seq_client.html
snd_seq_client_info_event_filter_clear
snd_seq_get_any_client_info
snd_seq_get_client_info
snd_seq_client_info_t