/* player.h - class MidiPlayer. Plays a set of tracks 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 ***************************************************************************/ #ifndef _PLAYER_H #define _PLAYER_H #include #include #include #include #include #include /** * This struct stores text, lyrics and change tempo events among others. * * It includes the main information for an event. That is, the absolute * millisecond at which this event is played (from the beginning of the song), * the delta milliseconds from the previous SpecialEvent, an ID, etc. * * This struct is used as nodes for a linked list, which you can get using * MidiPlayer::specialEvents(). * * @short Struct used to store certain events * @version 0.9.5 17/01/2000 * @author Antonio Larrosa Jimenez */ struct SpecialEvent { /** * An integer ID, that is assigned in order to each SpecialEvent. */ int id; /** * Delta milliseconds from the previous SpecialEvent. * * @see absmilliseconds */ ulong diffmilliseconds; /** * The absolute millisecond (from the beginning of the song) at which this * SpecialEvent object is played. * * @see diffmilliseconds */ ulong absmilliseconds; /** * MIDI ticks (from the beginning of the song) at which this event is played. */ int ticks; /** * Type of event. This currently includes: * * @li 0 - Nothing, end of linked list. * @li 1 - Text Event . See text. * @li 3 - Change Tempo Event . See tempo. * @li 5 - Lyrics Event . See text. * @li 6 - Change number of beats per measure . See num and den. * @li 7 - Beat . See num and den. * * The "Change number of beats per measure" and "beat" events are not really * in the midi file, but they are added to the linked list in case you have * an use for it. */ int type; /** * Text field . It has a meaning only for Text and Lyrics events. */ char text[1024]; /** * Tempo field . It has a meaning only for Change Tempo events. */ ulong tempo; /** * Numerator . It has a meaning only for Change number of beats per measure and * beat events. */ int num; /** * Denominator . It has a meaning only for Change number of beats per measure * and beat events. */ int den; /** * This struct stores text, lyrics and change tempo events among others. * * It includes the main information for an event. That is, the absolute * millisecond at which this event is played (from the beginning of the song), * the delta milliseconds from the previous SpecialEvent, an ID, etc. * * This struct is used as nodes for a linked list, which you can get using * MidiPlayer::specialEvents(). */ struct SpecialEvent *next; /** * Next node in the linked list. */ }; /** * PlayerController is a struct that is used by the MidiPlayer object * to tell other parts of the application about the status of the MIDI playing. * * @short Struct used to have control over the player engine * @version 0.9.5 17/01/2000 * @author Antonio Larrosa Jimenez */ struct PlayerController { volatile ulong ticksTotal; volatile ulong ticksPlayed; volatile double millisecsPlayed; volatile ulong beginmillisec; volatile int tempo; volatile int num; volatile int den; volatile int SPEVprocessed; volatile int SPEVplayed; /** * When pause is released, if the caller must know when the player has * opened the devices and is playing again, then it just has to check * to see when OK changes the value to 1 */ volatile int OK; /** * When the player is playing (or paused), playing is set to 1. */ volatile int playing; /** * When the player is paused, paused is set to 1. */ volatile int paused; /** * When the player seeking the position of the song, moving is set to 1. */ volatile int moving; /** * When the player has finished playing a song, finished is set to 1. */ volatile int finished; /** * @internal * @deprecated * Not used */ volatile int message KDE_DEPRECATED; // set one of the following : #define PLAYER_DOPAUSE 1 #define PLAYER_DOSTOP 2 #define PLAYER_SETPOS 4 #define PLAYER_HALT 8 volatile ulong gotomsec; //milliseconds to go to,if player_setpos is set /** * When error is 1, an error has ocurred (i.e. it coultn't open the device) */ volatile int error; /** * If gm is 1, the song follows the General Midi standard, if gm is 0, the song * is in MT 32 format. */ volatile int gm; /** * 100 means no change, 50 halfs the volume, 200 doubles it (if possible), etc. * * @see DeviceManager::setVolumePercentage() */ volatile int volumepercentage ; /** * Activate or disactivate the force to use a patch for a given channel. * @see pgm */ volatile bool forcepgm[16]; /** * Force a given patch in each channel at "this" moment, as determined by * forcepgm. */ volatile int pgm[16]; /** * Ratio to multiply the tempo to. */ volatile double ratioTempo; /** * @internal Used to stop the main pid until the child has finished to * send the all notes off event */ volatile bool isSendingAllNotesOff; volatile MidiEvent *ev; }; /** * MIDI file player routines . This class reads a MIDI file and * play it using a DeviceManager object. * * To use it, just call loadSong() with the filename you want to play, * and then play(). * * Please have a look at the note in the play() documentation. * * MidiPlayer will write information about the playing process on a * PlayerController() structure that you must supply to the constructor * * Alternatively, if everything you want is to play a midi file in a game or * any other application that doesn't need to fine tune the midi playing, just * use the tdemidplay() function. * * @see KMidSimpleAPI * * @short The MIDI file player engine * @version 0.9.5 17/01/2000 * @author Antonio Larrosa Jimenez */ class KMID_EXPORT MidiPlayer { class MidiPlayerPrivate; MidiPlayerPrivate *d; DeviceManager *midi; MidiFileInfo *info; MidiTrack **tracks; SpecialEvent *spev; NoteArray *na; int songLoaded; PlayerController *ctl; bool parsesong; bool generatebeats; void removeSpecialEvents(void); void parseSpecialEvents(void); void insertBeat(SpecialEvent *ev,ulong ms,int num,int den); void generateBeats(void); //NoteArray *parseNotes(void); void debugSpecialEvents(void); public: /** * Constructor . You must construct and pass a DeviceManager object and a * PlayerController structure. None of them will be destroyed by this * object, so you should do it after destroying the MidiPlayer object. */ MidiPlayer(DeviceManager *midi_,PlayerController *pctl); /** * Destructor. */ ~MidiPlayer(); /** * Loads a Song, and parses it (it the parse wasn't disabled with * setParseSong() ) . It also generates the Beat events (see * SpecialEvent::type() ) if you enabled this by using * setGenerateBeats() . */ int loadSong(const char *filename); /** * Unloads the current song, so that every internal variable is empty and clean * for further usage. */ void removeSong(void); /** * Returns true if there's a song already loaded (with a previous call to * loadSong() ) and false if not. */ int isSongLoaded(void) { return songLoaded; } /** * Returns the linked list of SpecialEvents objects . For this to work, * the parse should be enabled (the default), by using setParseSong(). */ SpecialEvent *specialEvents() { return spev; } /** * Returns and array with the notes playen through the song . MidiPlayer must * parse the song to get the notes, so be sure not to disable the parsing of * the song. * * Returns an array of notes, (just note on and note off events), in the form * of a NoteArray object */ NoteArray *noteArray(void) { return na; } /** * Plays the song using the DeviceManager object supplied in the * constructor. It should be already configured, as play doesn't change the * volume, nor midi mapper, for example. * * Note: Calling this function will block the execution of your application * until the song finishes playing. The solution for this is simple, fork * before calling it, and create the PlayerController object on shared * memory. * * As alternative, if everything you want is playing a midi file in a game or * any other application that doesn't need to fine tune the midi playing, just * use the KMidSimpleAPI::kMidPlay() function. * * @see KMidSimpleAPI::kMidInit * @see KMidSimpleAPI::kMidPlay * @see KMidSimpleAPI::kMidStop * @see KMidSimpleAPI::kMidDestruct */ void play(bool calloutput=false,void output(void) = 0); /** * Enables or disables the parsing of the song when loading it. This affects * the SpecialEvents ( specialEvents() ) and the NoteArray * ( noteArray() ). */ void setParseSong(bool b = true); /** * Enables or disables the generation of beats event in a song when loading * it. */ void setGenerateBeats(bool b = false); /** * Returns information about the current MIDI file. * * @see loadSong */ MidiFileInfo *information(void) { return info; } /** * Sets the position in a song. * @param gotomsec the number of milliseconds to go to . A subsequent call to * play() will start playing the song from that moment, instead of the * beginning. * @param midistat a MidiStatus object that will contain the status in * which the MIDI device would be if it would have arrived to this situation by * a normal playing of the song. */ void setPos(ulong gotomsec, class MidiStatus *midistat); /** * Changes the speed at which a song is played. The song's tempo is multiplied * by the specified ratio. */ void setTempoRatio(double ratio); }; #endif