You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdelibs/libtdemid/player.h

397 lines
11 KiB

/* 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 <larrosa@kde.org>
***************************************************************************/
#ifndef _PLAYER_H
#define _PLAYER_H
#include <libtdemid/dattypes.h>
#include <libtdemid/midfile.h>
#include <libtdemid/deviceman.h>
#include <libtdemid/track.h>
#include <libtdemid/notearray.h>
#include <tdemacros.h>
/**
* 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 <larrosa@kde.org>
*/
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 <larrosa@kde.org>
*/
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 TDE_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 <larrosa@kde.org>
*/
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