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 
24 
25 #include "common/debug.h"
26 #include "common/textconsole.h"
27 #include "common/util.h"
28 #include "scumm/imuse/imuse_internal.h"
29 #include "scumm/scumm.h"
30 
31 namespace Scumm {
32 
33 ////////////////////////////////////////
34 //
35 //  IMuse Part implementation
36 //
37 ////////////////////////////////////////
38 
Part()39 Part::Part() {
40 	_slot = 0;
41 	_next = 0;
42 	_prev = 0;
43 	_mc = 0;
44 	_player = 0;
45 	_pitchbend = 0;
46 	_pitchbend_factor = 0;
47 	_transpose = 0;
48 	_transpose_eff = 0;
49 	_vol = 0;
50 	_vol_eff = 0;
51 	_detune = 0;
52 	_detune_eff = 0;
53 	_pan = 0;
54 	_pan_eff = 0;
55 	_on = false;
56 	_modwheel = 0;
57 	_pedal = false;
58 	_pri = 0;
59 	_pri_eff = 0;
60 	_chan = 0;
61 	_effect_level = 0;
62 	_chorus = 0;
63 	_percussion = 0;
64 	_bank = 0;
65 	_unassigned_instrument = false;
66 }
67 
saveLoadWithSerializer(Common::Serializer & ser)68 void Part::saveLoadWithSerializer(Common::Serializer &ser) {
69 	int num;
70 	if (ser.isSaving()) {
71 		num = (_next ? (_next - _se->_parts + 1) : 0);
72 		ser.syncAsUint16LE(num);
73 
74 		num = (_prev ? (_prev - _se->_parts + 1) : 0);
75 		ser.syncAsUint16LE(num);
76 
77 		num = (_player ? (_player - _se->_players + 1) : 0);
78 		ser.syncAsUint16LE(num);
79 	} else {
80 		ser.syncAsUint16LE(num);
81 		_next = (num ? &_se->_parts[num - 1] : 0);
82 
83 		ser.syncAsUint16LE(num);
84 		_prev = (num ? &_se->_parts[num - 1] : 0);
85 
86 		ser.syncAsUint16LE(num);
87 		_player = (num ? &_se->_players[num - 1] : 0);
88 	}
89 
90 	ser.syncAsSint16LE(_pitchbend, VER(8));
91 	ser.syncAsByte(_pitchbend_factor, VER(8));
92 	ser.syncAsSByte(_transpose, VER(8));
93 	ser.syncAsByte(_vol, VER(8));
94 	ser.syncAsSByte(_detune, VER(8));
95 	ser.syncAsSByte(_pan, VER(8));
96 	ser.syncAsByte(_on, VER(8));
97 	ser.syncAsByte(_modwheel, VER(8));
98 	ser.syncAsByte(_pedal, VER(8));
99 	ser.skip(1, VER(8), VER(16)); // _program
100 	ser.syncAsByte(_pri, VER(8));
101 	ser.syncAsByte(_chan, VER(8));
102 	ser.syncAsByte(_effect_level, VER(8));
103 	ser.syncAsByte(_chorus, VER(8));
104 	ser.syncAsByte(_percussion, VER(8));
105 	ser.syncAsByte(_bank, VER(8));
106 }
107 
set_detune(int8 detune)108 void Part::set_detune(int8 detune) {
109 	// Sam&Max does not have detune, so we just ignore this here. We still get
110 	// this called, since Sam&Max uses the same controller for a different
111 	// purpose.
112 	if (_se->_game_id == GID_SAMNMAX) {
113 #if 0
114 		if (_mc) {
115 			_mc->controlChange(17, detune + 0x40);
116 		}
117 #endif
118 	} else {
119 		_detune_eff = clamp((_detune = detune) + _player->getDetune(), -128, 127);
120 		sendPitchBend();
121 	}
122 }
123 
pitchBend(int16 value)124 void Part::pitchBend(int16 value) {
125 	_pitchbend = value;
126 	sendPitchBend();
127 }
128 
volume(byte value)129 void Part::volume(byte value) {
130 	_vol_eff = ((_vol = value) + 1) * _player->getEffectiveVolume() >> 7;
131 	if (_mc)
132 		_mc->volume(_vol_eff);
133 }
134 
set_pri(int8 pri)135 void Part::set_pri(int8 pri) {
136 	_pri_eff = clamp((_pri = pri) + _player->getPriority(), 0, 255);
137 	if (_mc)
138 		_mc->priority(_pri_eff);
139 }
140 
set_pan(int8 pan)141 void Part::set_pan(int8 pan) {
142 	_pan_eff = clamp((_pan = pan) + _player->getPan(), -64, 63);
143 	sendPanPosition(_pan_eff + 0x40);
144 }
145 
set_transpose(int8 transpose)146 void Part::set_transpose(int8 transpose) {
147 	_transpose = transpose;
148 
149 	if (_se->_isAmiga) {
150 		// The Amiga version does a check like this. While this is probably a bug (a signed int8 can never be 128),
151 		// the playback depends on this being implemented exactly like in the original driver. I found this bug with
152 		// the WinUAE debugger. I don't know whether this is an Amiga only thing...
153 		_transpose_eff = /*(_transpose == 128) ? 0 : */transpose_clamp(_transpose + _player->getTranspose(), -12, 12);
154 		sendTranspose();
155 	} else {
156 		_transpose_eff = (_transpose == -128) ? 0 : transpose_clamp(_transpose + _player->getTranspose(), -24, 24);
157 		sendPitchBend();
158 	}
159 }
160 
sustain(bool value)161 void Part::sustain(bool value) {
162 	_pedal = value;
163 	if (_mc)
164 		_mc->sustain(value);
165 }
166 
modulationWheel(byte value)167 void Part::modulationWheel(byte value) {
168 	_modwheel = value;
169 	if (_mc)
170 		_mc->modulationWheel(value);
171 }
172 
chorusLevel(byte value)173 void Part::chorusLevel(byte value) {
174 	_chorus = value;
175 	if (_mc)
176 		_mc->chorusLevel(value);
177 }
178 
effectLevel(byte value)179 void Part::effectLevel(byte value) {
180 	_effect_level = value;
181 	sendEffectLevel(value);
182 }
183 
fix_after_load()184 void Part::fix_after_load() {
185 	set_transpose(_transpose);
186 	volume(_vol);
187 	set_detune(_detune);
188 	set_pri(_pri);
189 	set_pan(_pan);
190 	sendAll();
191 }
192 
pitchBendFactor(byte value)193 void Part::pitchBendFactor(byte value) {
194 	if (value > 12)
195 		return;
196 	pitchBend(0);
197 	_pitchbend_factor = value;
198 	if (_mc)
199 		_mc->pitchBendFactor(value);
200 }
201 
set_onoff(bool on)202 void Part::set_onoff(bool on) {
203 	if (_on != on) {
204 		_on = on;
205 		if (!on)
206 			off();
207 		if (!_percussion)
208 			_player->_se->reallocateMidiChannels(_player->getMidiDriver());
209 	}
210 }
211 
set_instrument(byte * data)212 void Part::set_instrument(byte *data) {
213 	if (_se->_pcSpeaker)
214 		_instrument.pcspk(data);
215 	else
216 		_instrument.adlib(data);
217 
218 	if (clearToTransmit())
219 		_instrument.send(_mc);
220 }
221 
load_global_instrument(byte slot)222 void Part::load_global_instrument(byte slot) {
223 	_player->_se->copyGlobalInstrument(slot, &_instrument);
224 	if (clearToTransmit())
225 		_instrument.send(_mc);
226 }
227 
noteOn(byte note,byte velocity)228 void Part::noteOn(byte note, byte velocity) {
229 	if (!_on)
230 		return;
231 
232 	MidiChannel *mc = _mc;
233 
234 	// DEBUG
235 	if (_unassigned_instrument && !_percussion) {
236 		_unassigned_instrument = false;
237 		if (!_instrument.isValid()) {
238 			debug(0, "[%02d] No instrument specified", (int)_chan);
239 			return;
240 		}
241 	}
242 
243 	if (mc && _instrument.isValid()) {
244 		mc->noteOn(note, velocity);
245 	} else if (_percussion) {
246 		mc = _player->getMidiDriver()->getPercussionChannel();
247 		if (!mc)
248 			return;
249 
250 		// FIXME: The following is evil, EVIL!!! Either prev_vol_eff is
251 		// actually meant to be a member of the Part class (i.e. each
252 		// instance of Part keeps a separate copy of it); or it really
253 		// is supposed to be shared by all Part instances -- but then it
254 		// should be implemented as a class static var. As it is, using
255 		// a function level static var in most cases is arcane and evil.
256 		static byte prev_vol_eff = 128;
257 		if (_vol_eff != prev_vol_eff) {
258 			mc->volume(_vol_eff);
259 			prev_vol_eff = _vol_eff;
260 		}
261 		if ((note < 35) && (!_player->_se->isNativeMT32()))
262 			note = Instrument::_gmRhythmMap[note];
263 
264 		mc->noteOn(note, velocity);
265 	}
266 }
267 
noteOff(byte note)268 void Part::noteOff(byte note) {
269 	if (!_on)
270 		return;
271 
272 	MidiChannel *mc = _mc;
273 	if (mc) {
274 		mc->noteOff(note);
275 	} else if (_percussion) {
276 		mc = _player->getMidiDriver()->getPercussionChannel();
277 		if (mc)
278 			mc->noteOff(note);
279 	}
280 }
281 
init()282 void Part::init() {
283 	_player = NULL;
284 	_next = NULL;
285 	_prev = NULL;
286 	_mc = NULL;
287 }
288 
setup(Player * player)289 void Part::setup(Player *player) {
290 	_player = player;
291 
292 	_percussion = (player->isMIDI() && _chan == 9); // true;
293 	_on = true;
294 	_pri_eff = player->getPriority();
295 	_pri = 0;
296 	_vol = 127;
297 	_vol_eff = player->getEffectiveVolume();
298 	_pan = clamp(player->getPan(), -64, 63);
299 	_transpose_eff = player->getTranspose();
300 	_transpose = 0;
301 	_detune = 0;
302 	_detune_eff = player->getDetune();
303 	_pitchbend_factor = 2;
304 	_pitchbend = 0;
305 	_effect_level = player->_se->isNativeMT32() ? 127 : 64;
306 	_instrument.clear();
307 	_unassigned_instrument = true;
308 	_chorus = 0;
309 	_modwheel = 0;
310 	_bank = 0;
311 	_pedal = false;
312 	_mc = NULL;
313 }
314 
uninit()315 void Part::uninit() {
316 	if (!_player)
317 		return;
318 	off();
319 	_player->removePart(this);
320 	_player = NULL;
321 }
322 
off()323 void Part::off() {
324 	if (_mc) {
325 		_mc->allNotesOff();
326 		_mc->release();
327 		_mc = NULL;
328 	}
329 }
330 
clearToTransmit()331 bool Part::clearToTransmit() {
332 	if (_mc)
333 		return true;
334 	if (_instrument.isValid())
335 		_player->_se->reallocateMidiChannels(_player->getMidiDriver());
336 	return false;
337 }
338 
sendAll()339 void Part::sendAll() {
340 	if (!clearToTransmit())
341 		return;
342 
343 	_mc->pitchBendFactor(_pitchbend_factor);
344 	sendTranspose();
345 	sendPitchBend();
346 	_mc->volume(_vol_eff);
347 	_mc->sustain(_pedal);
348 	_mc->modulationWheel(_modwheel);
349 	sendPanPosition(_pan_eff + 0x40);
350 
351 	if (_instrument.isValid())
352 		_instrument.send(_mc);
353 
354 	// We need to send the effect level after setting up the instrument
355 	// otherwise the reverb setting for MT-32 will be overwritten.
356 	sendEffectLevel(_effect_level);
357 
358 	_mc->chorusLevel(_chorus);
359 	_mc->priority(_pri_eff);
360 }
361 
sendPitchBend()362 void Part::sendPitchBend() {
363 	if (!_mc)
364 		return;
365 
366 	int16 bend = _pitchbend;
367 	// RPN-based pitchbend range doesn't work for the MT32,
368 	// so we'll do the scaling ourselves.
369 	if (_player->_se->isNativeMT32())
370 		bend = bend * _pitchbend_factor / 12;
371 
372 	// We send the transpose value separately for Amiga (which is more like the original handles this).
373 	// Some rhythm instruments depend on this.
374 	int8 transpose = _se->_isAmiga ? 0 : _transpose_eff;
375 	_mc->pitchBend(clamp(bend + (_detune_eff * 64 / 12) + (transpose * 8192 / 12), -8192, 8191));
376 }
377 
sendTranspose()378 void Part::sendTranspose() {
379 	if (!_mc)
380 		return;
381 
382 	// See comment above. The transpose function was never implemented into our other drivers,
383 	// since this seems to have been handled via pitchBend() instead. The original drivers do have
384 	// such functions.
385 	if (!_se->_isAmiga)
386 		return;
387 
388 	_mc->transpose(_transpose_eff);
389 }
390 
programChange(byte value)391 void Part::programChange(byte value) {
392 	_bank = 0;
393 	_instrument.program(value, _player->isMT32());
394 	if (clearToTransmit())
395 		_instrument.send(_mc);
396 }
397 
set_instrument(uint b)398 void Part::set_instrument(uint b) {
399 	_bank = (byte)(b >> 8);
400 	if (_bank)
401 		error("Non-zero instrument bank selection. Please report this");
402 	// HACK: Horrible hack to allow tracing of program change source.
403 	// The Mac m68k versions of MI2 and Indy4 use a different program "bank"
404 	// when it gets program change events through the iMuse SysEx handler.
405 	// We emulate this by introducing a special instrument, which sets
406 	// the instrument via sysEx_customInstrument. This seems to be
407 	// exclusively used for special sound effects like the "spit" sound.
408 	if (g_scumm->isMacM68kIMuse()) {
409 		_instrument.macSfx(b);
410 	} else {
411 		_instrument.program((byte)b, _player->isMT32());
412 	}
413 	if (clearToTransmit())
414 		_instrument.send(_mc);
415 }
416 
allNotesOff()417 void Part::allNotesOff() {
418 	if (!_mc)
419 		return;
420 	_mc->allNotesOff();
421 }
422 
sendPanPosition(uint8 value)423 void Part::sendPanPosition(uint8 value) {
424 	if (!_mc)
425 		return;
426 
427 	// As described in bug report #1088045 "MI2: Minor problems in native MT-32 mode"
428 	// the original iMuse MT-32 driver did revert the panning. So we do the same
429 	// here in our code to have correctly panned sound output.
430 	if (_player->_se->isNativeMT32())
431 		value = 127 - value;
432 
433 	_mc->panPosition(value);
434 }
435 
sendEffectLevel(uint8 value)436 void Part::sendEffectLevel(uint8 value) {
437 	if (!_mc)
438 		return;
439 
440 	// As described in bug report #1088045 "MI2: Minor problems in native MT-32 mode"
441 	// for the MT-32 one has to use a sysEx event to change the effect level (rather
442 	// the reverb setting).
443 	if (_player->_se->isNativeMT32()) {
444 		if (value != 127 && value != 0) {
445 			warning("Trying to use unsupported effect level value %d in native MT-32 mode.", value);
446 
447 			if (value >= 64)
448 				value = 127;
449 			else
450 				value = 0;
451 		}
452 
453 		byte message[9];
454 		memcpy(message, "\x41\x00\x16\x12\x00\x00\x06\x00\x00", 9);
455 		message[1] = _mc->getNumber();
456 		message[7] = (value == 127) ? 1 : 0;
457 		message[8] = 128 - (6 + message[7]);
458 		_player->getMidiDriver()->sysEx(message, 9);
459 	} else {
460 		_mc->effectLevel(value);
461 	}
462 }
463 
464 } // End of namespace Scumm
465