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