[prev in list] [next in list] [prev in thread] [next in thread] 

List:       arts
Subject:    New aRts midi interfaces
From:       Stefan Westerfeld <stefan () space ! twc ! de>
Date:       2000-11-30 16:40:12
[Download RAW message or body]

   Hi!

I wrote some new aRts idl files for midi interfaces. They include

 * a completed MidiPort interface, which should have all capabilities
   normal midi streams offer
 * a MidiManager, which assigns applications to midi destinations, much in
   the same way the aRts AudioManager does - it might also be comparable
   with the design of a window manager, which assigns clients (X11 apps) to
   destinations (screen space)

The reason why I think this is a good idea, is because the current interfaces
that aRts provides are simply not suitable to do serious music with (i.e.
missing pitch bend and controllers), and because I want to ship aRts based
midi stuff with KDE2.1.

To "why this, we have libkmid and ALSA" I can only say that I don't think
that the aRts midi interfaces are even designed to replace them. ALSA and
libkmid could both be made interoperable with the midi manager stuff by
acting as applications or destinations.

However, I also think that it is inappropriate to demand that aRts apps like
artstracker or an arts based sampler all reimplement necessary midi accesses
by either accessing libkmid or ALSA. A sound layer like aRts should provide
a reasonable abstraction for doing things like that.

Things that I am not happy with, are:
 * I would wished to have a streams based midi design (just like the audio
   design, with blocks and connections)
 * I am not sure if the timing stuff is reasonable, i.e. if you can use it
   with more than one application and one destination

However, I'd rather ship a suboptimal (marked "not binary compatible, don't
use") experimental midi stuff with 2.1, with apps on top of that, than never
start writing something at all.

Comments, questions, feedback?

   Cu... Stefan

/* Location: KDE CVS: kdemultimedia/arts/modules/artsmidi.idl */

    /*

    Copyright (C) 2000 Stefan Westerfeld
                       stefan@space.twc.de

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.
  
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.
   
    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.

    */

module Arts {

/* This is modelled somewhat after
    - the AudioManager concept
	- the aRts-0.3.4.1 MidiPort concept
	- libkmid

   It adds timing as new feature compared to older implementation, and also
   tries to do the full set of midi operations.

   It's current state is "experimental", and "binary compatibility not kept".
 */

/**
 * an absolute timestamp
 */
struct TimeStamp {
	long sec,usec;
};

interface MidiPort {
    /**
     * Sends a Note On MIDI event.
     *
     * @param channel the MIDI channel (0 to 15) to play the note on.
     * @param note the key of the note to play (0 to 127).
     * @param velocity the velocity of the note (0 to 127).
     *
     * @see #noteOff()
     */
    oneway void noteOn ( byte channel, byte note, byte velocity );

    /**
     * Sends a Note Off MIDI event. This is equivalent to send a Note On event
     * with a vel value of 0.
     *
     * @param channel the MIDI channel (0 to 15) to play the note on.
     * @param note the key of the note to play (0 to 127).
     * @param vel the velocity of the note (0 to 127).
     *
     * @see #noteOn()
     */
    oneway void noteOff ( byte channel, byte note, byte velocity );

    /**
     * Sends a Key Pressure (or Aftertouch) MIDI event.
     * This event changes the pressure over a key after this key has been
	 * played.
     *
     * @param channel the MIDI channel (0 to 15) where the note is being played.
     * @param note the key of the note (0 to 127).
     * @param velocity the new velocity (or pressure) of the note (0 to 127).
     */
    oneway void keyPressure ( byte channel, byte note, byte velocity );

    /**
     * Changes the patch (instrument) on a MIDI channel.
     *
     * @see setPatchesToUse()
     *
     * @param channel the MIDI channel (0 to 15) .
     * @param patch the General Midi patch (0 to 127) to use on
	 *        the channel channel.
     */
    oneway void channelPatchChange ( byte channel, byte patch );

    /**
     * Changes the Pressure (Aftertouch) on a MIDI channel. Keep in mind that
     * some synthesizers don't like this events, and it's better not to send it.
     *
     * @param channel the MIDI channel (0 to 15) to change.
     * @param velocity the velocity (0 to 127) to use on the channel channel.
     */
    oneway void channelPressure ( byte channel, byte velocity );

    /**
     * Changes the Pitch Bender value on a MIDI channel. This bends the tone of
     * each note played on this channel.
     *
     * @param channel the MIDI channel (0 to 15) to use.
     * @param value is the number by which notes will be bend, it is signed
	 *        between -8192 and 8064 (0 means no pitch bend)
     */
    oneway void channelPitchBender ( byte channel, long value );

    /**
     * Sends a Controller event to a MIDI channel. This can be used for example
     * to change the volume, set a XG patch, etc. Look for any General Midi
     * resource page on the net for more information about the available
     * controller events.
     *
     * For example, to set the tremolo value to a maximum on the MIDI channel
     * number one, you should pass 1 to @p channel, 1 to @p ctl and 127 to @p v.
     *
     * @param channel the MIDI channel (0 to 15) to send the event to.
     * @param ctl the controller (0 to 15) to send.
     * @param v the value (data) of the controller.
     */
    oneway void channelController ( byte channel, byte ctl , byte v );

    /**
     * Sends a SYStem EXclusive message to the default MIDI device (usually,
     * external MIDI synths, as most internal synths do not support sysex
     * messages)
     *
     * @param data the array of bytes that comform the system exclusive message.
     * Without the initial 0xF0 char, and including the final 0xF7 char (end of
     * exclusive message)
     *
     * @see setDefaultDevice()
     */
    oneway void sysEx (sequence<byte> data);

/**-------------------------- timing --------------------------**/

	/**
	 * true if the MidiPort supports timing at all
	 */
	readonly attribute boolean timingSupported;

	/**
	 * the current absolute time (since the existence of the midi device)
	 */
	readonly attribute TimeStamp time;

	/**
	 * how many events are queued but not yet played
	 */
	readonly attribute long futureEventCount;

	/**
	 * waits until a specified absolute time is reached
	 */
	oneway void waitUntil( TimeStamp time );

	/**
	 * Relative wait - relative waits are cumulative, that is, they always
	 * start waiting at the last position where something was waiting
	 */
	oneway void wait( float ms );

	/**
	 * flush removes all events that have been scheduled for the future
	 */
    oneway void flush();
};

enum MidiClientDirection { mcdPlay, mcdRecord }; 
enum MidiClientType { mctDestination, mctApplication }; 

/**
 * information about a midi client
 */
struct MidiClientInfo {
	long ID;
	sequence<long> connections;

	MidiClientDirection direction;
	MidiClientType type;
	string title, autoRestoreID;
};

/**
 * a midi manager client
 */
interface MidiClient {
    readonly attribute MidiClientInfo info;

	/**
	 * you can change the title of your client on the fly - everything else
	 * (besides the actual assignment) is static
	 */
    attribute string title;
 
	/**
	 * creates a new channel through which the client can receive data from
	 * the midi manager
	 */
	void addOutputPort(MidiPort channel);

	/**
	 * creates a new channel through which the client can send data to the
	 * midi manager
	 */
	MidiPort addInputPort();

	/**
	 * removes a channel
	 */
	void removePort(MidiPort channel);
};

/**
 * Some general notes to the understanding of the midi manager. The midi
 * manager has the task to intelligently assign applications to destinations.
 *
 * It is important to understand what it actually does to understand the
 * distinction first, which is expressed through the "MidiClientType" of
 * each client.
 *
 * APPLICATIONS: An application is a user visible application, that produces
 *    or records midi data. It is important for the understanding of an
 *    application, that an application actually *wants* to be supplied with
 *    data, or wants to get its data played. Thus, adding an application to
 *    the midi manager is an implicit request: "go and find a place where to
 *    put the events to (or get the events from)".
 *
 *    Examples for applications would be games or midi players.
 *
 * DESTINATIONS: A destination is a system service that plays or supplies
 *    midi data. The characteristic here is that a destination is something
 *    that is there if you need it.
 *
 *    Examples for destinations might be might be a hardware device or an
 *    emulation of a hardware device (such as a virtual sampler).
 *
 * So the process is as follows:
 *  - destinations register themselves at the midi manager, and provide
 *    system services in that way
 *
 *  - when the user starts an application (such as a midi player), the midi
 *    manager's task is to assign it to a suitable destination
 *
 *  - the user can interact with the process by changing the way applications
 *    are assigned to destinations - the midi manager will try to learn
 *    what the user wants, and next time do a better job while assigning
 *
 * To actually record or play some data, you need to register a client first,
 * and after that, you can add Input or Output "MidiPort"s to your client,
 * so that you can actually send or receive events with them.
 */
interface MidiManager { // SINGLETON: Arts_MidiManager
    /**
     * a list of clients
     */
    readonly attribute sequence<MidiClientInfo> clients;

	/**
	 * add a client
     *
	 * this creates a new MidiManagerClient
	 */ 
	MidiClient addClient(MidiClientDirection direction, MidiClientType type,
							string title, string autoRestoreID);

	/**
	 * connect two clients
	 */
	void connect(long clientID, long destinationID);

	/**
	 * disconnect two clients
	 */
	void disconnect(long clientID, long destinationID);
};                                                                              

};
-- 
  -* Stefan Westerfeld, stefan@space.twc.de (PGP!), Hamburg/Germany
     KDE Developer, project infos at http://space.twc.de/~stefan/kde *-         
_______________________________________________
Kde-multimedia mailing list
Kde-multimedia@master.kde.org
http://master.kde.org/mailman/listinfo/kde-multimedia

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic