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_MIDIDRV_MS_H
24 #define AUDIO_MIDIDRV_MS_H
25 
26 #include "common/mutex.h"
27 
28 #include "audio/mididrv.h"
29 
30 /**
31  * Abstract base class for MIDI drivers supporting multiple simultaneous
32  * sources of MIDI data.
33  *
34  * These drivers support the following features:
35  *
36  * - Multiple MIDI sources
37  *   If the game plays multiple streams of MIDI data at the same time, each
38  *   stream can be marked with a source number. When a source has finished
39  *   playing, it must be deinitialized to release any resources allocated to
40  *   it. This is done automatically when an End Of Track MIDI meta event is
41  *   received, or manually by calling deinitSource.
42  *   Using source numbers enables the following features:
43  *	 - Music/SFX volume
44  *	   Using setSourceType a MIDI source can be designated as music or sound
45  *	   effects. The driver will then apply the appropriate user volume setting
46  *	   to the MIDI channel volume. This setting sticks after deinitializing a
47  *	   source, so if you use the same source numbers for the same types of MIDI
48  *	   data, you don't need to set the source type repeatedly. The default setup
49  *	   is music for source 0 and SFX for sources 1 and higher.
50  *	 - Source volume
51  *	   If the game changes the volume of the MIDI playback, you can use
52  *	   setSourceVolume to set the volume level for a source. The driver will
53  *	   then adjust the current MIDI channel volume and any received MIDI volume
54  *	   controller messages. Use setSourceNeutralVolume to set the neutral volume
55  *	   for a source (MIDI volume is not changed when source volume is at this
56  *	   level; if it is lower or higher, MIDI volume is reduced or increased).
57  *	 - Volume fading
58  *	   If the game needs to gradually change the volume of the MIDI playback
59  *	   (typically for a fade-out), you can use the startFade function. You can
60  *	   check the status of the fade using isFading, and abort a fade using
61  *	   abortFade. An active fade is automatically aborted when the fading source
62  *	   is deinitialized.
63  *	   The fading functionality uses the source volume, so you should not set
64  *	   this while a fade is active. After the fade the source volume will remain
65  *	   at the target level, so if you perform f.e. a fade-out, the source volume
66  *	   will remain at 0. If you want to start playback again using this source,
67  *	   use setSourceVolume to set the correct playback volume.
68  *	   Note that when you stop MIDI playback, notes will not be immediately
69  *	   silent but will gradually die out ("release"). So if you fade out a
70  *	   source, stop playback, and immediately reset the source volume, the
71  *	   note release will be audible. It is recommended to wait about 0.5s
72  *	   before resetting the source volume.
73  *
74  * - User volume settings
75  *   The driver can scale the MIDI channel volume using the user specified
76  *   volume settings. Just call syncSoundSettings when the user has changed the
77  *   volume settings. Set the USER_VOLUME_SCALING property to true to enable
78  *   this functionality.
79  *
80  * A driver extending this class must implement the following functions:
81  * - send(source, data): process a MIDI event for a specific source.
82  * - stopAllNotes(source, channel): stop all active notes for a source and/or
83  *   MIDI channel (called when a source is deinitialized).
84  * - applySourceVolume(source): set the current source volume on active notes
85  *   and/or MIDI channels.
86  */
87 class MidiDriver_Multisource : public MidiDriver {
88 public:
89 	/**
90 	 * The maximum number of sources supported. This can be increased if
91 	 * necessary, but this will consume more memory and processing time.
92 	 */
93 	static const uint8 MAXIMUM_SOURCES = 10;
94 	/**
95 	 * The default neutral volume level for a source. If the source volume is
96 	 * set to this level, the volume levels in the MIDI data are used directly;
97 	 * if source volume is lower or higher, output volume is decreased or
98 	 * increased, respectively. Use @see setSourceNeutralVolume to change the
99 	 * default neutral volume.
100 	 */
101 	static const uint16 DEFAULT_SOURCE_NEUTRAL_VOLUME = 255;
102 
103 protected:
104 	// Timeout between updates of the channel volume for fades (25ms)
105 	static const uint16 FADING_DELAY = 25 * 1000;
106 
107 public:
108 	/**
109 	 * The type of audio produced by a MIDI source (music or sound effects).
110 	 */
111 	enum SourceType {
112 		/**
113 		 * Source type not specified (generally treated as music).
114 		 */
115 		SOURCE_TYPE_UNDEFINED,
116 		/**
117 		 * Source produces music.
118 		 */
119 		SOURCE_TYPE_MUSIC,
120 		/**
121 		 * Source produces sound effects.
122 		 */
123 		SOURCE_TYPE_SFX
124 	};
125 
126 	/**
127 	 * Specifies what happens to the volume when a fade is aborted.
128 	 */
129 	enum FadeAbortType {
130 		/**
131 		 * The volume is set to the fade's end volume level.
132 		 */
133 		FADE_ABORT_TYPE_END_VOLUME,
134 		/**
135 		 * The volume remains at the current level.
136 		 */
137 		FADE_ABORT_TYPE_CURRENT_VOLUME,
138 		/**
139 		 * The volume is reset to the fade's start volume level.
140 		 */
141 		FADE_ABORT_TYPE_START_VOLUME
142 	};
143 
144 protected:
145 	// This stores data about a specific source of MIDI data.
146 	struct MidiSource {
147 		// Whether this source sends music or SFX MIDI data.
148 		SourceType type;
149 		// The source volume (relative volume for this source as defined by the
150 		// game). Default is the default neutral value (255).
151 		uint16 volume;
152 		// The source volume level at which no scaling is performed (volume as
153 		// defined in the MIDI data is used directly). Volume values below this
154 		// decrease volume, values above increase volume (up to the maximum MIDI
155 		// channel volume). Set this to match the volume values used by the game
156 		// engine to avoid having to convert them. Default value is 255; minimum
157 		// value is 1.
158 		uint16 neutralVolume;
159 		// The volume level at which the fade started.
160 		uint16 fadeStartVolume;
161 		// The target volume level for the fade.
162 		uint16 fadeEndVolume;
163 		// How much time (microseconds) has passed since the start of the fade.
164 		int32 fadePassedTime;
165 		// The total duration of the fade (microseconds).
166 		int32 fadeDuration;
167 
168 		MidiSource();
169 	};
170 
171 public:
172 	MidiDriver_Multisource();
173 
174 	// MidiDriver functions
175 	using MidiDriver_BASE::send;
176 	void send(uint32 b) override;
177 	void send(int8 source, uint32 b) override = 0;
178 
179 	uint32 property(int prop, uint32 param) override;
180 
181 	/**
182 	 * Deinitializes a source. This will abort active fades and stop any active
183 	 * notes.
184 	 *
185 	 * @param source The source to deinitialize.
186 	 */
187 	virtual void deinitSource(uint8 source);
188 	/**
189 	 * Sets the type for all sources (music or SFX).
190 	 *
191 	 * @param type The new type for all sources.
192 	 */
193 	void setSourceType(SourceType type);
194 	/**
195 	 * Sets the type for a specific sources (music or SFX).
196 	 *
197 	 * @param source The source for which the type should be set.
198 	 * @param type The new type for the specified source.
199 	 */
200 	void setSourceType(uint8 source, SourceType type);
201 	/**
202 	 * Sets the source volume for all sources.
203 	 *
204 	 * @param volume The new source volume for all sources.
205 	 */
206 	void setSourceVolume(uint16 volume);
207 	/**
208 	 * Sets the volume for this source. The volume values in the MIDI data sent
209 	 * by this source will be scaled by the source volume.
210 	 *
211 	 * @param source The source for which the source volume should be set.
212 	 * @param volume The new source volume for the specified source.
213 	 */
214 	void setSourceVolume(uint8 source, uint16 volume);
215 	/**
216 	 * Resets the source volume for all sources to each source's neutral volume.
217 	 */
218 	void resetSourceVolume();
219 	/**
220 	 * Resets the volume for this source to its neutral volume.
221 	 */
222 	void resetSourceVolume(uint8 source);
223 	/**
224 	 * Sets the neutral volume for all sources. See the source-specific
225 	 * setSourceNeutralVolume function for details.
226 	 *
227 	 * @param volume The new neutral volume for all sources.
228 	 */
229 	void setSourceNeutralVolume(uint16 volume);
230 	/**
231 	 * Sets the neutral volume for this source. If the source volume is at this
232 	 * level, the volume values in the MIDI data sent by this source will not
233 	 * be changed. At source volumes below or above this value, the MIDI volume
234 	 * values will be decreased or increased accordingly.
235 	 *
236 	 * @param source The source for which the neutral volume should be set.
237 	 * @param volume The new neutral volume for the specified source.
238 	 */
239 	void setSourceNeutralVolume(uint8 source, uint16 volume);
240 
241 	/**
242 	 * Starts a fade for all sources.
243 	 * See the source-specific startFade function for more information.
244 	 *
245 	 * @param duration The fade duration in milliseconds
246 	 * @param targetVolume The volume at the end of the fade
247 	 */
248 	void startFade(uint16 duration, uint16 targetVolume);
249 	/**
250 	 * Starts a fade for a source. This will linearly increase or decrease the
251 	 * volume of the MIDI channels used by the source to the specified target
252 	 * value over the specified length of time.
253 	 *
254 	 * @param source The source to fade
255 	 * @param duration The fade duration in milliseconds
256 	 * @param targetVolume The volume at the end of the fade
257 	 */
258 	void startFade(uint8 source, uint16 duration, uint16 targetVolume);
259 	/**
260 	 * Aborts any active fades for all sources.
261 	 * See the source-specific abortFade function for more information.
262 	 *
263 	 * @param abortType How to set the volume when aborting the fade (default:
264 	 * set to the target fade volume).
265 	 */
266 	void abortFade(FadeAbortType abortType = FADE_ABORT_TYPE_END_VOLUME);
267 	/**
268 	 * Aborts an active fade for a source. Depending on the abort type, the
269 	 * volume will remain at the current value or be set to the start or end
270 	 * volume. If there is no active fade for the specified source, this
271 	 * function does nothing.
272 	 *
273 	 * @param source The source that should have its fade aborted
274 	 * @param abortType How to set the volume when aborting the fade (default:
275 	 * set to the target fade volume).
276 	 */
277 	void abortFade(uint8 source, FadeAbortType abortType = FADE_ABORT_TYPE_END_VOLUME);
278 	/**
279 	 * Check if any source has an active fade.
280 	 *
281 	 * @return True if any source has an active fade.
282 	 */
283 	bool isFading();
284 	/**
285 	 * Check if the specified source has an active fade.
286 	 *
287 	 * @return True if the specified source has an active fade.
288 	 */
289 	bool isFading(uint8 source);
290 
291 	/**
292 	 * Applies the user volume settings to the MIDI driver. MIDI channel
293 	 * volumes will be scaled using the user volume.
294 	 * This function must be called by the engine when the user has changed the
295 	 * volume settings.
296 	 */
297 	void syncSoundSettings();
298 
299 	using MidiDriver::stopAllNotes;
300 	/**
301 	 * Stops all active notes (including sustained notes) for the specified
302 	 * source and MIDI channel. For both source and channel the value 0xFF can
303 	 * be specified, in which case active notes will be stopped for all sources
304 	 * and/or MIDI channels.
305 	 *
306 	 * @param source The source for which all notes should be stopped, or all
307 	 * sources if 0xFF is specified.
308 	 * @param channel The MIDI channel on which all notes should be stopped, or
309 	 * all channels if 0xFF is specified.
310 	 */
311 	virtual void stopAllNotes(uint8 source, uint8 channel) = 0;
312 
313 	/**
314 	 * Sets a callback which will be called whenever the driver's timer
315 	 * callback is called by the underlying emulator or hardware driver. The
316 	 * callback will only be called when the driver is open. Use
317 	 * @see getBaseTempo to get the delay between each callback invocation.
318 	 *
319 	 * @param timer_param A parameter that will be passed to the callback
320 	 * function. Optional.
321 	 * @param timer_proc The function that should be called.
322 	 */
setTimerCallback(void * timer_param,Common::TimerManager::TimerProc timer_proc)323 	void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) override {
324 		_timer_param = timer_param;
325 		_timer_proc = timer_proc;
326 	}
327 
328 protected:
329 	/**
330 	 * Applies the current source volume to the active notes and/or MIDI
331 	 * channels of the specified source. 0xFF can be specified to apply the
332 	 * source volume for all sources.
333 	 *
334 	 * @param source The source for which the source volume should be applied,
335 	 * or all sources if 0xFF is specified.
336 	 */
337 	virtual void applySourceVolume(uint8 source) = 0;
338 	/**
339 	 * Processes active fades and sets new volume values if necessary.
340 	 */
341 	void updateFading();
342 	/**
343 	 * Runs the MIDI driver's timer related functionality. Will update volume
344 	 * fades and calls the timer callback if necessary.
345 	 */
346 	virtual void onTimer();
347 
348 	// MIDI source data
349 	MidiSource _sources[MAXIMUM_SOURCES];
350 
351 	// True if the driver should scale MIDI channel volume to the user
352 	// specified volume settings.
353 	bool _userVolumeScaling;
354 
355 	// User volume settings
356 	uint16 _userMusicVolume;
357 	uint16 _userSfxVolume;
358 	bool _userMute;
359 
360 	Common::Mutex _fadingMutex; // For operations on fades
361 
362 	// The number of microseconds to wait before the next fading step.
363 	uint16 _fadeDelay;
364 
365 	// The number of microseconds between timer callback invocations.
366 	uint32 _timerRate;
367 
368 	// External timer callback
369 	void *_timer_param;
370 	Common::TimerManager::TimerProc _timer_proc;
371 };
372 
373 class MidiDriver_NULL_Multisource : public MidiDriver_Multisource {
374 public:
375 	~MidiDriver_NULL_Multisource();
376 
377 	int open() override;
isOpen()378 	bool isOpen() const override { return true; }
close()379 	void close() override { }
getBaseTempo()380 	uint32 getBaseTempo() override { return 10000; }
allocateChannel()381 	MidiChannel *allocateChannel() override { return 0; }
getPercussionChannel()382 	MidiChannel *getPercussionChannel() override { return 0; }
383 
384 	using MidiDriver_Multisource::send;
send(int8 source,uint32 b)385 	void send(int8 source, uint32 b) override { }
386 	using MidiDriver_Multisource::stopAllNotes;
stopAllNotes(uint8 source,uint8 channel)387 	void stopAllNotes(uint8 source, uint8 channel) override { }
388 
389 	static void timerCallback(void *data);
390 
391 protected:
applySourceVolume(uint8 source)392 	void applySourceVolume(uint8 source) override { }
393 };
394 
395 #endif
396