summaryrefslogtreecommitdiffstats
path: root/libtdemid/deviceman.h
diff options
context:
space:
mode:
Diffstat (limited to 'libtdemid/deviceman.h')
-rw-r--r--libtdemid/deviceman.h537
1 files changed, 537 insertions, 0 deletions
diff --git a/libtdemid/deviceman.h b/libtdemid/deviceman.h
new file mode 100644
index 000000000..40788ad34
--- /dev/null
+++ b/libtdemid/deviceman.h
@@ -0,0 +1,537 @@
+/* deviceman.h - The device manager, that hides the use of midiOut
+ This file is part of LibKMid 0.9.5
+ Copyright (C) 1997,98,99,2000 Antonio Larrosa Jimenez
+ LibKMid's homepage : http://www.arrakis.es/~rlarrosa/libtdemid.html
+ 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., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ Send comments and bug fixes to Antonio Larrosa <larrosa@kde.org>
+
+***************************************************************************/
+#ifndef DEVICEMAN_H
+#define DEVICEMAN_H
+
+#include <libtdemid/dattypes.h>
+#include <tdelibs_export.h>
+
+class MidiOut;
+class MidiMapper;
+
+/**
+ * MIDI Device Manager class . This class is the one you should use to
+ * send MIDI events to any device, as it creates and manages the *Out classes.
+ *
+ * This class is usually used by creating a DeviceManager object, then call
+ * openDev() and initDev() . Then, use numberOfMidiPorts(),
+ * numberOfSynthDevices(), name() and type() to choose which
+ * device to play MIDI events to and then use defaultDevice() to set the
+ * MIDI device to play.
+ *
+ * @short Manages all MIDI devices and redirects MIDI events to each one as
+ * configured.
+ * @version 0.9.5 17/01/2000
+ * @author Antonio Larrosa Jimenez <larrosa@kde.org>
+ */
+class KMID_EXPORT DeviceManager
+{
+ protected:
+
+ /**
+ * @internal
+ * The midi devices objects
+ */
+ MidiOut **device;
+
+ /**
+ * @internal
+ * Midi info
+ */
+ struct midi_info *midiinfo;
+
+ /**
+ * @internal
+ * Synth info
+ */
+ struct synth_info *synthinfo;
+
+ /**
+ * @internal
+ * Stores the device thru which a channel will be sent
+ */
+ int chn2dev[16];
+
+ /**
+ * @internal
+ * Number of synths devices
+ */
+ int n_synths;
+
+ /**
+ * @internal
+ * Number of midi ports
+ */
+ int n_midi;
+
+ /**
+ * @internal
+ * n_midi + n_synths
+ */
+ int n_total;
+
+ /**
+ * @internal
+ * rate
+ */
+ int m_rate;
+
+ /**
+ * @internal
+ * A "constant" used to convert from milliseconds to the computer rate.
+ */
+ double convertrate;
+
+ /**
+ * @internal
+ * Newest kernels don't want me to stop a timer that hasn't been started :-)
+ */
+ int timerstarted;
+
+ /**
+ * @internal
+ * Last time waited for in wait(double)
+ */
+ double lastwaittime;
+
+ /**
+ * @internal
+ * Keeps a pointer to the mapper so that if devices weren't initialized when
+ * first called setMidiMap then, when they get initialized, they use the
+ * proper mapper
+ */
+ MidiMapper *mapper_tmp;
+
+ int initialized;
+
+ /**
+ * @internal
+ * The real file handler for /dev/sequencer, that is opened and closed.
+ */
+ int seqfd;
+
+ /**
+ * @internal
+ * The device to which timer events will be sent
+ */
+ int default_dev;
+
+ /**
+ * @internal
+ */
+ int _ok;
+
+ /**
+ * @internal
+ * True if the user is running ALSA. False if (s)he's using OSS
+ */
+ bool alsa;
+
+ /**
+ * @internal
+ */
+ void seqbuf_dump (void);
+
+ /**
+ * @internal
+ */
+ void seqbuf_clean (void);
+
+ /**
+ * @internal
+ */
+ void checkAlsa (void);
+ public:
+ /**
+ * Constructor. It just initializes internal variables, before playing any
+ * music, you should call initManager(), setMidiMap()
+ * (optional), openDev(), initDev(), setPatchesToUse()
+ * (not required, unless you're playing to a GUS device, which must load
+ * the patches), tmrStart(), and finally, play the music.
+ */
+ DeviceManager(int def=-1);
+
+ /**
+ * Destructor. It closes the device (calling closeDev() ) if it wasn't
+ * closed before.
+ */
+ ~DeviceManager(void);
+
+ /**
+ * Initializes the MIDI Device Manager object.
+ *
+ * The /dev/sequencer and/or /dev/snd/seq files are opened, available
+ * devices are analyzed and *Out objects are created. Then, the
+ * device files are closed.
+ *
+ * @return 0 if everything was OK, or -1 if there was an error and it
+ * couldn't be initialized (for example, because it couldn't open the
+ * /dev/sequencer file)
+ */
+ int initManager(void);
+
+ /**
+ * Checks if the device manager has been initialized (with @p initManager),
+ * and in case it wasn't, initializes it.
+ *
+ * @return 0 if it was (or has just been) correctly initialized, and -1 if
+ * there was an error.
+ */
+ int checkInit(void);
+
+ /**
+ * \obsolete Please use deviceForChannel() instead.
+ *
+ */
+ MidiOut *chntodev(int chn)
+ { return deviceForChannel(chn); }
+
+ /**
+ * It's possible to send different MIDI channels to different MIDI devices,
+ * so that you can for example send channel 1 to an external synthesizer,
+ * channel 2 to a FM device and channel 10 to an AWE synth.
+ *
+ * @return the device to which MIDI events goind to channel @p chn should
+ * be sent.
+ */
+ MidiOut *deviceForChannel(int chn)
+ { return (device!=0L) ? device[chn2dev[chn]] : 0L ; }
+
+ /**
+ * Returns the device number associated with a given channel.
+ */
+ int deviceNumberForChannel(int chn) { return chn2dev[chn]; }
+
+ /**
+ * Sets the device number associated with a given channel.
+ */
+ void setDeviceNumberForChannel(int chn, int dev);
+
+ /**
+ * @return 0 if there was a problem and 1 if everything was OK. Note that the
+ * return value is changed after you check it, so you can only check it once.
+ */
+ int ok(void);
+
+ /**
+ * Returns true if it's running ALSA and false if OSS is being run
+ */
+ int usingAlsa(void) { return alsa; }
+
+ // The following function are here to emulate a midi, so that the
+ // DeviceManager sends the events to the appropriate devices.
+
+ /**
+ * Open the devices. It first initializes the manager it that wasn't done
+ * yet (you should do it yourself, to be able to choose the MIDI output
+ * device, as it will be set to an external synth by default, if available).
+ *
+ * Then /dev/sequencer is opened and the MIDI devices are opened
+ * (calling MidiOut::openDev() ).
+ * @see ok() to check if there was any problem
+ * @see closeDev()
+ * @see initDev()
+ */
+ void openDev (void);
+
+ /**
+ * Closes the devices, and /dev/sequencer.
+ *
+ * @see openDev()
+ */
+ void closeDev (void);
+
+ /**
+ * Calls MidiOut::initDev() in turn in each of the available devices.
+ *
+ * @see MidiOut::initDev()
+ */
+ void initDev (void);
+
+ /**
+ * Sends a Note On MIDI event.
+ *
+ * @param chn 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 noteOff()
+ */
+ void noteOn ( uchar chn, uchar note, uchar vel );
+
+ /**
+ * Sends a Note Off MIDI event. This is equivalent to send a Note On event
+ * with a vel value of 0.
+ *
+ * @param chn 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()
+ */
+ void noteOff ( uchar chn, uchar note, uchar vel );
+
+ /**
+ * Sends a Key Pressure (or Aftertouch) MIDI event.
+ * This event changes the pressure over a key after this key has been played.
+ *
+ * @param chn the MIDI channel (0 to 15) where the note is being played.
+ * @param note the key of the note (0 to 127).
+ * @param vel the new velocity (or pressure) of the note (0 to 127).
+ */
+ void keyPressure ( uchar chn, uchar note, uchar vel );
+
+ /**
+ * Changes the patch (instrument) on a MIDI channel.
+ *
+ * @see setPatchesToUse()
+ *
+ * @param chn the MIDI channel (0 to 15) .
+ * @param patch the General Midi patch (0 to 127) to use on the channel chn.
+ */
+ void chnPatchChange ( uchar chn, uchar 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 chn the MIDI channel (0 to 15) to change.
+ * @param vel the velocity (0 to 127) to use on the channel chn.
+ */
+ void chnPressure ( uchar chn, uchar vel );
+
+ /**
+ * Changes the Pitch Bender value on a MIDI channel. This bends the tone of
+ * each note played on this channel.
+ *
+ * @param chn the MIDI channel (0 to 15) to use.
+ * @param lsb and @p msb the less significant byte and the most significant
+ * byte (0 to 127 each) of the number by which notes will be bend. a 0x4000
+ * value means not to bend.
+ * @param msb the most significant byte
+ */
+ void chnPitchBender ( uchar chn, uchar lsb, uchar msb );
+
+ /**
+ * 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 chn, 1 to @p ctl and 127 to @p v.
+ *
+ * @param chn 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.
+ */
+ void chnController ( uchar chn, uchar ctl , uchar 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)
+ * @param size the size in bytes of the data to send
+ *
+ * @see setDefaultDevice()
+ */
+ void sysEx ( uchar *data,ulong size);
+
+ /**
+ * Sets the number of milliseconds at which the next event will be sent.
+ * This way, you can schedule notes and events to send to the MIDI device.
+ * @see tmrStart()
+ */
+ void wait (double ms);
+
+ /**
+ * Sets the tempo which will be used to convert between ticks and
+ * milliseconds.
+ */
+ void tmrSetTempo(int v);
+
+ /**
+ * Starts the timer. You must call tmrStart before using wait()
+ */
+ void tmrStart(long int tpcn);
+
+ /**
+ * Stops the timer. This will be called by closeDev() before closing
+ * the device
+ */
+ void tmrStop(void);
+
+ /**
+ * Continue the stopped timer . It is the same than starting a new timer, but
+ * without resetting it.
+ */
+ void tmrContinue(void);
+
+ /**
+ * Sends an all notes off event
+ */
+ void allNotesOff(void);
+
+ /**
+ * Synchronizes with the MIDI buffer. Midi events are put into a buffer,
+ * along with timer delays (see wait() ). sync returns when the buffer
+ * is empty.
+ *
+ * @param f if false, it syncronizes by waiting for the buffer to be sent.
+ * If true, it forces the synchronization by clearing the buffer
+ * inmediately. The "force" method is, of course, not recommended, except
+ * in rare situations.
+ */
+ void sync(bool f=0);
+
+ /**
+ * Changes the "master" volume of the played events by altering next volume
+ * controller events. The parameter @p i should be in the range of 0
+ * (nothing is heard) to 150 (music is played at a 150% of the original
+ * volume).
+ *
+ * Keep in mind that as most MIDI files already play music at near the
+ * maximum volume, an @p i value greater than 100 is very probably ignored
+ * most of the times.
+ */
+ void setVolumePercentage(int i);
+
+ /**
+ * Returns the device to which the MIDI events will be sent.
+ * Returns -1 if there's no available device.
+ *
+ * @see setDefaultDevice()
+ */
+ int defaultDevice(void);
+
+ /**
+ * Sets the device to send the MIDI events to.
+ *
+ * By using midiPorts(), synthDevices(), name() and
+ * type(), you should choose which device to use (note that they are
+ * numbered with midi ports being first and synth devices next)
+ *
+ * @see defaultDevice()
+ */
+ void setDefaultDevice(int i);
+
+ /**
+ * Loads the patches you're going to use . This has effect only for GUS
+ * cards, although, if you use this function when defaultDevice() is
+ * not a GUS device, it will be ignored.
+ *
+ * The parameter is an int [256] array, which contain the following:
+ *
+ * The first 0..127 integers, are the number of times each General MIDI patch
+ * will be used, and -1 when the corresponding patch won't be used.
+ *
+ * The 128..255 integers are the number of times each drum voice (each note
+ * on the drum channel) will be used, and -1 when the corresponding
+ * percussion won't be used.
+ *
+ * This is done this way so that if the user has very little memory on his
+ * GUS card, and not all patches will be loaded, they are at least
+ * reordered, so that it first loads the one you're going to use most.
+ *
+ * In case you don't worry about such users, or you don't know "a priori"
+ * the number of notes you're going to play, you can just use 1 for each
+ * patch you want to load and -1 in the rest.
+ *
+ * @see GUSOut::setPatchesToUse()
+ * @see GUSOut::loadPatch()
+ *
+ * @return 0 if ok, and -1 if there wasn't enough memory to load the patches
+ * in the card's memory.
+ */
+ int setPatchesToUse(int *patchesused);
+
+ /**
+ * Returns the filename where the Midi Mapper was loaded from, or "" if no
+ * MIDI Mapper is in use.
+ *
+ * @see setMidiMap()
+ */
+ const char *midiMapFilename(void);
+
+ /**
+ * Sets a MidiMapper object to use. This object should already have
+ * loaded the configuration. See the description of MidiMapper for
+ * more information.
+ *
+ * @see MidiMapper::MidiMapper()
+ * @see midiMapFilename()
+ */
+ void setMidiMap(MidiMapper *map);
+
+ /**
+ * Returns the SNDCTL_SEQ_CTRLRATE ioctl value
+ */
+ int rate(void) { return m_rate; }
+
+ /**
+ * Returns the number of MIDI ports available on the system. It's common that
+ * users have MIDI ports available, but there are no external synthesizers
+ * connected to these ports, so sending MIDI events to these ports will not
+ * produce any music in this case.
+ *
+ * @see synthDevices()
+ * @see setDefaultDevice()
+ */
+ int midiPorts(void) { return n_midi; }
+
+ /**
+ * Returns the number of internal synthesizers available on the system. Some
+ * of these devices will need special configuration, for example, to load
+ * sound patches.
+ *
+ * @see midiPorts()
+ * @see setDefaultDevice()
+ * @see setPatchesToUse()
+ */
+ int synthDevices(void) { return n_synths; }
+
+ /**
+ * Returns the name of the @p i-th device . In case the DeviceManager wasn't
+ * yet initialized ( see checkInit() ), the return value is NULL, and
+ * in case the parameter has a value out of the valid range ( 0 to
+ * midiPorts() + synthDevices() ) it returns an empty string.
+ */
+ const char *name(int i);
+
+ /**
+ * Returns the type of device the @p i-th device is , in a user-friendly
+ * string . For example, "External Midi Port" for midi ports, "FM" for FM
+ * synthesizers, "GUS" for Gravis Ultrasound devices, etc.
+ */
+ const char *type(int i);
+
+ private:
+ class DeviceManagerPrivate;
+ DeviceManagerPrivate *d;
+};
+
+#endif