aboutsummaryrefslogtreecommitdiff
path: root/audio/midiplayer.h
blob: 5c06baeff221ac0e6f9290a0da851bad0f27fcc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#ifndef AUDIO_MIDIPLAYER_H
#define AUDIO_MIDIPLAYER_H

#include "common/scummsys.h"
#include "common/mutex.h"
#include "audio/mididrv.h"

class MidiParser;

namespace Audio {

/**
 * Simple MIDI playback class.
 *
 * @note Currently incomplete, as it lacks play() methods. This is just a
 * start of the real thing, which tries to include code replicated between
 * several of our engines.
 *
 * Eventually, this should offer ways to start playback of SMF and XMIDI
 * data (and possibly make it easy to add further playback methods),
 * should be able to automatically instantiate _driver as needed,
 * should perform memory management on the MidiParser object(s) being
 * used, and possibly more.
 *
 * Also, pause/resume handling should be unified (we provide an implementation,
 * but several subclasses use different ones).
 *
 * Also, care should be taken to ensure that mutex locking is done right.
 *
 * @todo Document origin of this class. It is based on code shared by
 * several engines (e.g. DRACI says it copied it from MADE, which took
 * it from SAGE).
 */
class MidiPlayer : public MidiDriver_BASE {
public:
	MidiPlayer();
	~MidiPlayer();

	// TODO: Implement ways to actually play stuff
	//virtual void play(TODO);

	// TODO: Document these
	virtual void stop();
	virtual void pause();
	virtual void resume();

	/**
	 * Return whether there is currently any MIDI music playing.
	 *
	 * @todo There is a subtle difference between the semantics of this in
	 *       various subclasses, related to paused music: Namely, should this
	 *       function return true or false if a MIDI song is currently loaded,
	 *       but paused? In the base implementation of pause/resume, "false"
	 *       will be returned (that is, it is not possible to distinguish between
	 *       nothing being played, and an active but paused MIDI tune).
	 *       But in several subclasses (e.g. in HUGO), there is a separate _paused
	 *       variable, which is used to pause playback, and for these, "true"
	 *       will be returned.
	 *       And in SAGA, isPlaying is overwritten to return the value
	 *       of _parser->isPlaying() (which should amount to "true" in the
	 *       described situation).
	 *       We really should unify this and clearly define the desired
	 *       semantics of this method.
	 */
	bool isPlaying() const { return _isPlaying; }

	/**
	 * Return the currently active master volume, in the range 0-255.
	 */
	int getVolume() const { return _masterVolume; }

	/**
	 * Set the master volume to the specified value in the range 0-255.
	 * (values outside this range are automatically clipped).
	 * This may cause suitable MIDI events to be sent to active channels.
	 *
	 * @todo This method currently does not do anything if the new volume
	 *       matches the old volume. But some engines always update the
	 *       volume (Parallaction, Tinsel, Touche, ...). This is why
	 *       this method is currently virtual. We really should figure
	 *       which way to do it, and then make this the default, and make
	 *       this method non-virtual again.
	 */
	virtual void setVolume(int volume);

	/**
	 * Update the volume according to the ConfMan's 'music_volume'
	 * setting. also respects the 'mute' setting.
	 */
	void syncVolume();

	// TODO: Document this
	bool hasNativeMT32() const { return _nativeMT32; }

	// MidiDriver_BASE implementation
	virtual void send(uint32 b);
	virtual void metaEvent(byte type, byte *data, uint16 length);

protected:
	/**
	 * This method is invoked by the default send() implementation,
	 * after suitably filtering the message b.
	 */
	virtual void sendToChannel(byte ch, uint32 b);

	/**
	 * This method is invoked by metaEvent when an end-of-track
	 * event arrives. By default, this tells the parser
	 * to jump to the start (if looping is enabled) resp.
	 * invokes stope():
	 * Overload this to customize behavior.
	 */
	virtual void endOfTrack();

	// TODO: Document this
	virtual void onTimer();

	static void timerCallback(void *data);

	void createDriver(int flags = MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);

protected:
	enum {
		/**
		 * The number of MIDI channels supported.
		 */
		kNumChannels = 16
	};

	Common::Mutex _mutex;
	MidiDriver *_driver;

	/**
	 * A MidiParser instances, to be created by methods of a MidiPlayer
	 * subclass.
	 * @note The stop() method (and hence the destructor) invoke the
	 * unloadMusic() method of _parser and then delete it.
	 */
	MidiParser *_parser;

	/**
	 * This is an (optional) pointer to a malloc'ed buffer containing
	 * MIDI data used by _parser. The stop() method (and hence the
	 * destructor) will free this if set.
	 * Subclasses of this class may use _midiData, but don't have to
	 */
	byte *_midiData;

	MidiChannel *_channelsTable[kNumChannels];
	uint8 _channelsVolume[kNumChannels];

	bool _isLooping;
	bool _isPlaying;

	/**
	 * The master volume, in the range 0-255.
	 */
	int _masterVolume;	// FIXME: byte or int ?

	bool _nativeMT32;
};


} // End of namespace Audio

#endif