1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifndef AUDIO_MIDIPLAYER_H
24 #define AUDIO_MIDIPLAYER_H
25 
26 #include "common/scummsys.h"
27 #include "common/mutex.h"
28 #include "audio/mididrv.h"
29 
30 class MidiParser;
31 
32 namespace Audio {
33 
34 /**
35  * Simple MIDI playback class.
36  *
37  * @note Currently incomplete, as it lacks play() methods. This is just a
38  * start of the real thing, which tries to include code replicated between
39  * several of our engines.
40  *
41  * Eventually, this should offer ways to start playback of SMF and XMIDI
42  * data (and possibly make it easy to add further playback methods),
43  * should be able to automatically instantiate _driver as needed,
44  * should perform memory management on the MidiParser object(s) being
45  * used, and possibly more.
46  *
47  * Also, pause/resume handling should be unified (we provide an implementation,
48  * but several subclasses use different ones).
49  *
50  * Also, care should be taken to ensure that mutex locking is done right.
51  *
52  * @todo Document origin of this class. It is based on code shared by
53  * several engines (e.g. DRACI says it copied it from MADE, which took
54  * it from SAGE).
55  */
56 class MidiPlayer : public MidiDriver_BASE {
57 public:
58 	MidiPlayer();
59 	~MidiPlayer();
60 
61 	// TODO: Implement ways to actually play stuff
62 	//virtual void play(TODO);
63 
64 	// TODO: Document these
65 	virtual void stop();
66 	virtual void pause();
67 	virtual void resume();
68 
69 	/**
70 	 * Return whether there is currently any MIDI music playing.
71 	 *
72 	 * @todo There is a subtle difference between the semantics of this in
73 	 *       various subclasses, related to paused music: Namely, should this
74 	 *       function return true or false if a MIDI song is currently loaded,
75 	 *       but paused? In the base implementation of pause/resume, "false"
76 	 *       will be returned (that is, it is not possible to distinguish between
77 	 *       nothing being played, and an active but paused MIDI tune).
78 	 *       But in several subclasses (e.g. in HUGO), there is a separate _paused
79 	 *       variable, which is used to pause playback, and for these, "true"
80 	 *       will be returned.
81 	 *       And in SAGA, isPlaying is overwritten to return the value
82 	 *       of _parser->isPlaying() (which should amount to "true" in the
83 	 *       described situation).
84 	 *       We really should unify this and clearly define the desired
85 	 *       semantics of this method.
86 	 */
isPlaying()87 	bool isPlaying() const { return _isPlaying; }
88 
89 	/**
90 	 * Return the currently active master volume, in the range 0-255.
91 	 */
getVolume()92 	int getVolume() const { return _masterVolume; }
93 
94 	/**
95 	 * Set the master volume to the specified value in the range 0-255.
96 	 * (values outside this range are automatically clipped).
97 	 * This may cause suitable MIDI events to be sent to active channels.
98 	 *
99 	 * @todo This method currently does not do anything if the new volume
100 	 *       matches the old volume. But some engines always update the
101 	 *       volume (Parallaction, Tinsel, Touche, ...). This is why
102 	 *       this method is currently virtual. We really should figure
103 	 *       which way to do it, and then make this the default, and make
104 	 *       this method non-virtual again.
105 	 */
106 	virtual void setVolume(int volume);
107 
108 	/**
109 	 * Update the volume according to the ConfMan's 'music_volume'
110 	 * setting. also respects the 'mute' setting.
111 	 */
112 	void syncVolume();
113 
114 	// TODO: Document this
hasNativeMT32()115 	bool hasNativeMT32() const { return _nativeMT32; }
116 
117 	// MidiDriver_BASE implementation
118 	virtual void send(uint32 b);
119 	virtual void metaEvent(byte type, byte *data, uint16 length);
120 
121 protected:
122 	/**
123 	 * This method is invoked by the default send() implementation,
124 	 * after suitably filtering the message b.
125 	 */
126 	virtual void sendToChannel(byte ch, uint32 b);
127 
128 	/**
129 	 * This method is invoked by metaEvent when an end-of-track
130 	 * event arrives. By default, this tells the parser
131 	 * to jump to the start (if looping is enabled) resp.
132 	 * invokes stope():
133 	 * Overload this to customize behavior.
134 	 */
135 	virtual void endOfTrack();
136 
137 	// TODO: Document this
138 	virtual void onTimer();
139 
140 	static void timerCallback(void *data);
141 
142 	void createDriver(int flags = MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
143 
144 protected:
145 	enum {
146 		/**
147 		 * The number of MIDI channels supported.
148 		 */
149 		kNumChannels = 16
150 	};
151 
152 	Common::Mutex _mutex;
153 	MidiDriver *_driver;
154 
155 	/**
156 	 * A MidiParser instances, to be created by methods of a MidiPlayer
157 	 * subclass.
158 	 * @note The stop() method (and hence the destructor) invoke the
159 	 * unloadMusic() method of _parser and then delete it.
160 	 */
161 	MidiParser *_parser;
162 
163 	/**
164 	 * This is an (optional) pointer to a malloc'ed buffer containing
165 	 * MIDI data used by _parser. The stop() method (and hence the
166 	 * destructor) will free this if set.
167 	 * Subclasses of this class may use _midiData, but don't have to
168 	 */
169 	byte *_midiData;
170 
171 	MidiChannel *_channelsTable[kNumChannels];
172 	uint8 _channelsVolume[kNumChannels];
173 
174 	bool _isLooping;
175 	bool _isPlaying;
176 
177 	/**
178 	 * The master volume, in the range 0-255.
179 	 */
180 	int _masterVolume;	// FIXME: byte or int ?
181 
182 	bool _nativeMT32;
183 };
184 
185 
186 } // End of namespace Audio
187 
188 #endif
189