[Scummvm-cvs-logs] CVS: scummvm/sound adlib.cpp,NONE,1.3.2.1 fmopl.cpp,NONE,1.1.2.1 fmopl.h,NONE,1.1.2.1 gmidi.cpp,NONE,1.2.2.1 imuse.cpp,NONE,1.1.2.1

Vincent Hamm yazoo at users.sourceforge.net
Wed Dec 19 16:35:02 CET 2001


Update of /cvsroot/scummvm/scummvm/sound
In directory usw-pr-cvs1:/tmp/cvs-serv11883

Added Files:
      Tag: exp_1
	adlib.cpp fmopl.cpp fmopl.h gmidi.cpp imuse.cpp 
Log Message:


--- NEW FILE: adlib.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sound/adlib.cpp,v 1.3.2.1 2001/12/20 00:34:06 yazoo Exp $
 */

#include "stdafx.h"
#include "scumm.h"
#include "sound.h"
#include "fmopl.h"

#if defined USE_ADLIB

static byte lookup_table[64][32];
const byte volume_table[] = {
0, 4, 7, 11,
13, 16, 18, 20,
22, 24, 26, 27,
29, 30, 31, 33,
34, 35, 36, 37,
38, 39, 40, 41,
42, 43, 44, 44,
45, 46, 47, 47,
48, 49, 49, 50,
51, 51, 52, 53,
53, 54, 54, 55,
55, 56, 56, 57,
57, 58, 58, 59,
59, 60, 60, 60,
61, 61, 62, 62,
62, 63, 63, 63
};

int lookup_volume(int a, int b) {
	if (b==0)
		return 0;

	if (b==31)
		return a;
	
	if (a<-63 || a>63) {
		return b * (a+1) >> 5;
	}
	
	if (b<0) {
		if (a<0) {
			return lookup_table[-a][-b];
		} else {
			return -lookup_table[a][-b];
		}
	} else {
		if (a<0) {
			return -lookup_table[-a][b];
		} else {
			return lookup_table[a][b];
		}
	}
}

void create_lookup_table() {
	int i,j;
	int sum;

	for (i=0; i<64; i++) {
		sum = i;
		for (j=0; j<32; j++) {
			lookup_table[i][j] = sum >> 5;
			sum += i;
		}
	}
	for (i=0; i<64; i++)
		lookup_table[i][0] = 0;
}

MidiChannelAdl *AdlibSoundDriver::allocate_midichan(byte pri) {
	MidiChannelAdl *ac,*best=NULL;
	int i;

	for (i=0; i<9; i++) {
		if (++_midichan_index >= 9)
			_midichan_index = 0;
		ac = &_midi_channels[_midichan_index];
		if (!ac->_part)
			return ac;
		if (!ac->_next) {
			if (ac->_part->_pri_eff <= pri) {
				pri = ac->_part->_pri_eff;
				best = ac;
			}
		}
	}

	if (best)
		mc_off(best);
	else
		;//debug(1, "Denying adlib channel request");
	return best;
}

void AdlibSoundDriver::init(SoundEngine *eng) {
	int i;
	MidiChannelAdl *mc;

	_se = eng;

	for(i=0,mc=_midi_channels; i!=ARRAYSIZE(_midi_channels);i++,mc++) {
		mc->_channel = i;
		mc->_s11a.s10 = &mc->_s10b;
		mc->_s11b.s10 = &mc->_s10a;
	}

	_adlib_reg_cache = (byte*)calloc(256,1);
	_opl = OPLCreate(OPL_TYPE_YM3812,3579545,22050);
	adlib_write(1,0x20);
	adlib_write(8,0x40);
	adlib_write(0xBD, 0x00);
	create_lookup_table();
}

void AdlibSoundDriver::adlib_write(byte port, byte value) {
	if (_adlib_reg_cache[port] == value)
		return;
	_adlib_reg_cache[port] = value;

	OPLWriteReg(_opl, port, value);
}

void AdlibSoundDriver::adlib_key_off(int chan) {
	byte port = chan + 0xB0;
	adlib_write(port, adlib_read(port)&~0x20);
}

struct AdlibSetParams {
	byte a,b,c,d;
};

static const byte channel_mappings[9] = {
	0, 1, 2, 8,
	9,10,16,17,
	18
};

static const byte channel_mappings_2[9] = {
	3, 4, 5, 11,
	12,13,19,20,
	21
};

static const AdlibSetParams adlib_setparam_table[] = {
{0x40,0,63,63}, /* level */
{0xE0,2,0,0},   /* unused */
{0x40,6,192,0}, /* level key scaling */
{0x20,0,15,0},  /* modulator frequency multiple */
{0x60,4,240,15},/* attack rate */
{0x60,0,15,15}, /* decay rate */
{0x80,4,240,15}, /* sustain level */
{0x80,0,15,15}, /* release rate */
{0xE0,0,3,0},   /* waveform select */
{0x20,7,128,0}, /* amp mod */
{0x20,6,64,0},  /* vib */
{0x20,5,32,0},  /* eg typ */
{0x20,4,16,0},  /* ksr */
{0xC0,0,1,0},   /* decay alg */
{0xC0,1,14,0}   /* feedback */
};

void AdlibSoundDriver::adlib_set_param(int channel, byte param, int value) {
	const AdlibSetParams *as;
	byte port;

	assert(channel>=0 && channel<9);

	if (param <= 12) {
		port = channel_mappings_2[channel];
	} else if (param <= 25) {
		param -= 13;
		port = channel_mappings[channel];
	} else if (param <= 27) {
		param -= 13;
		port = channel;
	} else if (param==28 || param==29) {
		if (param==28)
			value -= 15;
		else
			value -= 383;
		value <<= 4;
		channel_table_2[channel] = value;
		adlib_playnote(channel, curnote_table[channel] + value);
		return;
	}else {
		return;
	}

	as = &adlib_setparam_table[param];
	if (as->d)
		value = as->d - value;
	port += as->a;
	adlib_write(port, (adlib_read(port) & ~as->c) | (((byte)value)<<as->b));
}

static const byte octave_numbers[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7
};

static const byte note_numbers[]= {
 3,   4,   5,   6,   7,   8,   9,  10,
11,  12,  13,  14,   3,   4,   5,   6,
 7,   8,   9,  10,  11,  12,  13,  14,
 3,   4,   5,   6,   7,   8,   9,  10,
11,  12,  13,  14,   3,   4,   5,   6,
 7,   8,   9,  10,  11,  12,  13,  14,
 3,   4,   5,   6,   7,   8,   9,  10,
11,  12,  13,  14,   3,   4,   5,   6,
 7,   8,   9,  10,  11,  12,  13,  14,
 3,   4,   5,   6,   7,   8,   9,  10,
11,  12,  13,  14,   3,   4,   5,   6,
 7,   8,   9,  10,  11,  12,  13,  14,
 3,   4,   5,   6,   7,   8,   9,  10,
11,  12,  13,  14,   3,   4,   5,   6,
 7,   8,   9,  10,  11,  12,  13,  14,
 3,   4,   5,   6,   7,   8,   9,  10
};

static const byte note_to_f_num[] = {
 90,  91,  92,  92,  93,  94,  94,  95,
 96,  96,  97,  98,  98,  99, 100, 101,
101, 102, 103, 104, 104, 105, 106, 107,
107, 108, 109, 110, 111, 111, 112, 113,
114, 115, 115, 116, 117, 118, 119, 120,
121, 121, 122, 123, 124, 125, 126, 127,
128, 129, 130, 131, 132, 132, 133, 134,
135, 136, 137, 138, 139, 140, 141, 142,
143, 145, 146, 147, 148, 149, 150, 151,
152, 153, 154, 155, 157, 158, 159, 160,
161, 162, 163, 165, 166, 167, 168, 169,
171, 172, 173, 174, 176, 177, 178, 180,
181, 182, 184, 185, 186, 188, 189, 190,
192, 193, 194, 196, 197, 199, 200, 202,
203, 205, 206, 208, 209, 211, 212, 214,
215, 217, 218, 220, 222, 223, 225, 226,
228, 230, 231, 233, 235, 236, 238, 240,
242, 243, 245, 247, 249, 251, 252, 254,
};

void AdlibSoundDriver::adlib_playnote(int channel, int note) {
	byte old,oct,notex;
	int note2;
	int i;

	note2 = (note>>7) - 4;

	oct = octave_numbers[note2]<<2;
	notex = note_numbers[note2];

	old = adlib_read(channel + 0xB0);
	if (old&0x20) {
		old &= ~0x20;
		if (oct > old) {
			if (notex < 6) {
				notex += 12;
				oct -= 4;
			}
		} else if (oct < old) {
			if (notex > 11) {
				notex -= 12;
				oct += 4;
			}
		}
	}
	
	i = (notex<<3) + ((note>>4)&0x7);
	adlib_write(channel + 0xA0, note_to_f_num[i]);
	adlib_write(channel + 0xB0, oct|0x20);
}

void AdlibSoundDriver::adlib_note_on(int chan, byte note, int mod) {
	int code;
	assert(chan>=0 && chan<9);
	code = (note<<7) + mod;
	curnote_table[chan] = code;
	adlib_playnote(chan, channel_table_2[chan] + code);
}

void AdlibSoundDriver::adlib_note_on_ex(int chan, byte note, int mod) {
	int code;
	assert(chan>=0 && chan<9);
	code = (note<<7) + mod;
	curnote_table[chan] = code;
	channel_table_2[chan] = 0;
	adlib_playnote(chan, code);
}

void AdlibSoundDriver::adlib_key_onoff(int channel) {
	byte val;
	byte port = channel + 0xB0;
	assert(channel>=0 && channel<9);

	val = adlib_read(port);
	adlib_write(port, val&~0x20);
	adlib_write(port, val|0x20);
}

void AdlibSoundDriver::adlib_setup_channel(int chan, Instrument *instr, byte vol_1, byte vol_2) {
	byte port;

	assert(chan>=0 && chan<9);

	port = channel_mappings[chan];
	adlib_write(port + 0x20, instr->flags_1);
	adlib_write(port + 0x40, (instr->oplvl_1|0x3F) - vol_1);
	adlib_write(port + 0x60, ~instr->atdec_1);
	adlib_write(port + 0x80, ~instr->sustrel_1);
	adlib_write(port + 0xE0, instr->waveform_1);
	
	port = channel_mappings_2[chan];
	adlib_write(port + 0x20, instr->flags_2);
	adlib_write(port + 0x40, (instr->oplvl_2|0x3F) - vol_2);
	adlib_write(port + 0x60, ~instr->atdec_2);
	adlib_write(port + 0x80, ~instr->sustrel_2);
	adlib_write(port + 0xE0, instr->waveform_2);

	adlib_write((byte)chan + 0xC0, instr->feedback);
}

int AdlibSoundDriver::adlib_read_param(int chan, byte param) {
	const AdlibSetParams *as;
	byte val;
	byte port;

	assert(chan>=0 && chan<9);

	if (param <= 12) {
		port = channel_mappings_2[chan];
	} else if (param <= 25) {
		param -= 13;
		port = channel_mappings[chan];
	} else if (param <= 27) {
		param -= 13;
		port = chan;
	} else if (param==28) {
		return 0xF;
	} else if (param==29) {
		return 0x17F;
	} else {
		return 0;
	}

	as = &adlib_setparam_table[param];
	val = adlib_read(port + as->a);
	val &= as->c;
	val >>= as->b;
	if (as->d)
		val = as->d - val;

	return val;
}

void AdlibSoundDriver::generate_samples(int16 *data, int len) {
	int step;

	if (!_opl) {
		memset(data, 0, len*sizeof(int16));
		return;
	}

	do {
		step = len;
		if (step > _next_tick)
			step = _next_tick;
		YM3812UpdateOne(_opl,data,step);
		
		if(!(_next_tick -= step)) {
			_se->on_timer();
			reset_tick();
		}
		data += step;
	} while (len-=step);
}

void AdlibSoundDriver::reset_tick() {
	_next_tick = 88;
}

void AdlibSoundDriver::on_timer() {
	MidiChannelAdl *mc;
	int i;

	_adlib_timer_counter += 0xD69;
	while (_adlib_timer_counter >= 0x411B) {
		_adlib_timer_counter -= 0x411B;
		mc = _midi_channels;
		for (i=0; i!=ARRAYSIZE(_midi_channels); i++,mc++) {
			if (!mc->_part)
				continue;
			if (mc->_duration && (mc->_duration -= 0x11) <= 0) {
				mc_off(mc);
				return;
			}
			if (mc->_s10a.active) {
				mc_inc_stuff(mc, &mc->_s10a, &mc->_s11a);
			}
			if (mc->_s10b.active) {
				mc_inc_stuff(mc, &mc->_s10b, &mc->_s11b);
			}
		}
	}
}

const byte param_table_1[16] = {
29,28,27,0,
3,4,7,8,
13,16,17,20,
21,30,31,0
};

const uint16 param_table_2[16] = {
0x2FF,0x1F,0x7,0x3F,
0x0F,0x0F,0x0F,0x3,
0x3F,0x0F,0x0F,0x0F,
0x3,0x3E,0x1F, 0
};

static const uint16 num_steps_table[] = {
1, 2, 4, 5,
6, 7, 8, 9,
10, 12, 14, 16,
18, 21, 24, 30,
36, 50, 64, 82,
100, 136, 160, 192,
240, 276, 340, 460,
600, 860, 1200, 1600
};

int AdlibSoundDriver::random_nr(int a) {
	static byte _rand_seed = 1;
	if (_rand_seed&1) {
		_rand_seed>>=1;
		_rand_seed ^= 0xB8;
	} else {
		_rand_seed>>=1;
	}
	return _rand_seed * a >> 8;
}

void AdlibSoundDriver::struct10_setup(Struct10 *s10) {
	int b,c,d,e,f,g,h;
	byte t;

	b = s10->unk3;
	f = s10->active - 1;

	t = s10->table_a[f];
	e = num_steps_table[lookup_table[t&0x7F][b]];
	if (t&0x80) {
		e = random_nr(e);
	}
	if (e==0)
		e++;
	
	s10->num_steps = s10->speed_lo_max = e;

	if (f != 2) {
		c = s10->param;
		g = s10->start_value;
		t = s10->table_b[f];
		d = lookup_volume(c, (t&0x7F) - 31);
		if (t&0x80) {
			d = random_nr(d);
		}
		if (d+g > c) {
			h = c - g;
		} else {
			h = d;
			if (d+g<0)
				h = -g;
		}
		h -= s10->cur_val;
	} else {
		h = 0;
	}

	s10->speed_hi = h / e;
	if (h<0) {
		h = -h;
		s10->direction = -1;
	} else {
		s10->direction = 1;
	}

	s10->speed_lo = h % e;
	s10->speed_lo_counter = 0;
}

byte AdlibSoundDriver::struct10_ontimer(Struct10 *s10, Struct11 *s11) {
	byte result = 0;
	int i;

	if (s10->count && (s10->count-=17)<=0) {
		s10->active = 0;
		return 0;
	}

	i = s10->cur_val + s10->speed_hi;
	s10->speed_lo_counter += s10->speed_lo;
	if (s10->speed_lo_counter >= s10->speed_lo_max) {
		s10->speed_lo_counter -= s10->speed_lo_max;
		i += s10->direction;
	}
	if (s10->cur_val != i || s10->modwheel != s10->modwheel_last) {
		s10->cur_val = i;
		s10->modwheel_last = s10->modwheel;
		i = lookup_volume(i, s10->modwheel_last);
		if (i != s11->modify_val) {
			s11->modify_val = i;
			result = 1;
		}
	}
	assert(s10->num_steps>=0);
	if (!--s10->num_steps) {
		s10->active++;
		if (s10->active > 4) {
			if (s10->loop) {
				s10->active = 1;
				result |= 2;
				struct10_setup(s10);
			} else {
				s10->active = 0;
			}
		} else {
			struct10_setup(s10);
		}
	}

	return result;
}

void AdlibSoundDriver::struct10_init(Struct10 *s10, InstrumentExtra *ie) {
	s10->active = 1;
	s10->cur_val = 0;
	s10->modwheel_last = 31;
	s10->count = ie->a;
	if (s10->count)
		s10->count *= 63;
	s10->table_a[0] = ie->b;
	s10->table_a[1] = ie->d;
	s10->table_a[2] = ie->f;
	s10->table_a[3] = ie->g;

	s10->table_b[0] = ie->c;
	s10->table_b[1] = ie->e;
	s10->table_b[2] = 0;
	s10->table_b[3] = ie->h;
		
	struct10_setup(s10);
}

void AdlibSoundDriver::mc_init_stuff(MidiChannelAdl *mc, Struct10 *s10, Struct11 *s11, byte flags, InstrumentExtra *ie) {
	Part *part = mc->_part;

	s11->modify_val = 0;
	s11->flag0x40 = flags & 0x40;
	s10->loop = flags & 0x20;
	s11->flag0x10 = flags & 0x10;
	s11->param = param_table_1[flags&0xF];
	s10->param = param_table_2[flags&0xF];
	s10->unk3 = 31;
	if (s11->flag0x40) {
		s10->modwheel = part->_modwheel>>2;
	} else {
		s10->modwheel = 31;
	}

	switch(s11->param) {
	case 0:
		s10->start_value = mc->_vol_2;
		break;
	case 13:
		s10->start_value = mc->_vol_1;
		break;
	case 30:
		s10->start_value = 31;
		s11->s10->modwheel = 0;
		break;
	case 31:
		s10->start_value = 0;
		s11->s10->unk3 = 0;
		break;
	default:
		s10->start_value = part->_drv->adlib_read_param(mc->_channel, s11->param);
	}

	struct10_init(s10, ie);
}

void AdlibSoundDriver::mc_inc_stuff(MidiChannelAdl *mc, Struct10 *s10, Struct11 *s11) {
	byte code;
	Part *part= mc->_part;

	code = struct10_ontimer(s10,s11);

	if (code&1) {
		switch(s11->param) {
		case 0:
			mc->_vol_2 = s10->start_value + s11->modify_val;
			part->_drv->adlib_set_param(mc->_channel, 0, volume_table[lookup_table[mc->_vol_2][part->_vol_eff>>2]]);
			break;
		case 13:
			mc->_vol_1 = s10->start_value + s11->modify_val;
			if (mc->_twochan) {
				part->_drv->adlib_set_param(mc->_channel, 13, volume_table[lookup_table[mc->_vol_1][part->_vol_eff>>2]]);
			} else {
				part->_drv->adlib_set_param(mc->_channel, 13, mc->_vol_1);
			}
			break;
		case 30:
			s11->s10->modwheel = s11->modify_val;
			break;
		case 31:
			s11->s10->unk3 = s11->modify_val;
			break;
		default:
			part->_drv->adlib_set_param(mc->_channel, s11->param, s10->start_value + s11->modify_val);
			break;
		}
	}

	if (code&2 && s11->flag0x10)
		part->_drv->adlib_key_onoff(mc->_channel);
}

void AdlibSoundDriver::part_changed(Part *part,byte what) {
	MidiChannelAdl *mc;

	if (what & pcProgram) {
		if (part->_program < 32) {
			part_set_instrument(part, &_glob_instr[part->_program]);
		}
	}

	if (what & pcMod) {
		for(mc=part->_mc->adl(); mc; mc=mc->_next) {
			adlib_note_on(mc->_channel, mc->_note + part->_transpose_eff, part->_pitchbend + part->_detune_eff);
		}
	}

	if (what & pcVolume) {
		for(mc=part->_mc->adl(); mc; mc=mc->_next) {
			adlib_set_param(mc->_channel, 0, volume_table[lookup_table[mc->_vol_2][part->_vol_eff>>2]]);
			if (mc->_twochan) {
				adlib_set_param(mc->_channel, 13, volume_table[lookup_table[mc->_vol_1][part->_vol_eff>>2]]);
			}
		}
	}

	if (what & pcPedal) {
		if (!part->_pedal) {
			for(mc=(MidiChannelAdl*)part->_mc; mc; mc=mc->_next) {
				if (mc->_waitforpedal)
					mc_off(mc);
			}
		}
	}

	if (what & pcModwheel) {
		for(mc=(MidiChannelAdl*)part->_mc; mc; mc=mc->_next) {
			if (mc->_s10a.active && mc->_s11a.flag0x40)
				mc->_s10a.modwheel = part->_modwheel>>2;
			if (mc->_s10b.active && mc->_s11b.flag0x40)
				mc->_s10b.modwheel = part->_modwheel>>2;
		}
	}
}

void AdlibSoundDriver::mc_key_on(MidiChannel *mc2, byte note, byte velocity) {
	MidiChannelAdl *mc = (MidiChannelAdl*)mc2;
	Part *part = mc->_part;
	Instrument *instr = &_part_instr[part->_slot];
	int c;
	byte vol_1,vol_2;

	mc->_twochan = instr->feedback&1;
	mc->_note = note;
	mc->_waitforpedal = false;
	mc->_duration = instr->duration;
	if (mc->_duration != 0)
		mc->_duration *= 63;

	vol_1 = (instr->oplvl_1&0x3F) + lookup_table[velocity>>1][instr->waveform_1>>2];
	if (vol_1 > 0x3F)
		vol_1 = 0x3F;
	mc->_vol_1 = vol_1;

	vol_2 = (instr->oplvl_2&0x3F) + lookup_table[velocity>>1][instr->waveform_2>>2];
	if (vol_2 > 0x3F)
		vol_2 = 0x3F;
	mc->_vol_2 = vol_2;

	c = part->_vol_eff >> 2;
	
	vol_2 = volume_table[lookup_table[vol_2][c]];
	if (mc->_twochan)
		vol_1 = volume_table[lookup_table[vol_1][c]];
	
	adlib_setup_channel(mc->_channel, instr, vol_1, vol_2);
	adlib_note_on_ex(mc->_channel, part->_transpose_eff + note, part->_detune_eff + part->_pitchbend);

	if (instr->flags_a & 0x80) {
		mc_init_stuff(mc, &mc->_s10a, &mc->_s11a, instr->flags_a, &instr->extra_a);
	} else {
		mc->_s10a.active = 0;
	}
	
	if (instr->flags_b & 0x80) {
		mc_init_stuff(mc, &mc->_s10b, &mc->_s11b, instr->flags_b, &instr->extra_b); 
	} else {
		mc->_s10b.active = 0;
	}
}

void AdlibSoundDriver::set_instrument(uint slot, byte *data) {
	if (slot < 32) {
		memcpy(&_glob_instr[slot], data, sizeof(Instrument));
	}
}


void AdlibSoundDriver::link_mc(Part *part, MidiChannelAdl *mc) {
	mc->_part = part;
	mc->_next = (MidiChannelAdl*)part->_mc;
	part->_mc = mc;
	mc->_prev = NULL;
	
	if (mc->_next)
		mc->_next->_prev = mc;
}

void AdlibSoundDriver::part_key_on(Part *part, byte note, byte velocity) {
	MidiChannelAdl *mc;

	mc = allocate_midichan(part->_pri_eff);
	if (!mc)
		return;

	link_mc(part, mc);
	mc_key_on(mc,note, velocity);
}

void AdlibSoundDriver::part_key_off(Part *part, byte note) {
	MidiChannelAdl *mc;

	for(mc=(MidiChannelAdl*)part->_mc; mc; mc=mc->_next) {
		if (mc->_note==note) {
			if (part->_pedal)
				mc->_waitforpedal = true;
			else
				mc_off(mc);
		}
	}
}

struct AdlibInstrSetParams {
	byte param;
	byte shl;
	byte mask;
};

#define MKLINE(_a_,_b_,_c_) { (int)&((Instrument*)0)->_a_, _b_, ((1<<(_c_))-1)<<(_b_) }
static const AdlibInstrSetParams adlib_instr_params[69] = {
	MKLINE(oplvl_2,0,6),
	MKLINE(waveform_2,2,5),
	MKLINE(oplvl_2,6,2),
	MKLINE(flags_2,0,4),
	MKLINE(atdec_2,4,4),
	MKLINE(atdec_2,0,4),
	MKLINE(sustrel_2,4,4),
	MKLINE(sustrel_2,0,4),
	MKLINE(waveform_2,0,2),
	MKLINE(flags_2,7,1),
	MKLINE(flags_2,6,1),
	MKLINE(flags_2,5,1),
	MKLINE(flags_2,4,1),

	MKLINE(oplvl_1,0,6),
	MKLINE(waveform_1,2,5),
	MKLINE(oplvl_1,6,2),
	MKLINE(flags_1,0,4),
	MKLINE(atdec_1,4,4),
	MKLINE(atdec_1,0,4),
	MKLINE(sustrel_1,4,4),
	MKLINE(sustrel_1,0,4),
	MKLINE(waveform_1,0,2),
	MKLINE(flags_1,7,1),
	MKLINE(flags_1,6,1),
	MKLINE(flags_1,5,1),
	MKLINE(flags_1,4,1),

	MKLINE(feedback,0,1),
	MKLINE(feedback,1,3),

	MKLINE(flags_a,7,1),
	MKLINE(flags_a,6,1),
	MKLINE(flags_a,5,1),
	MKLINE(flags_a,4,1),
	MKLINE(flags_a,0,4),
	MKLINE(extra_a.a,0,8),
	MKLINE(extra_a.b,0,7),
	MKLINE(extra_a.c,0,7),
	MKLINE(extra_a.d,0,7),
	MKLINE(extra_a.e,0,7),
	MKLINE(extra_a.f,0,7),
	MKLINE(extra_a.g,0,7),
	MKLINE(extra_a.h,0,7),
	MKLINE(extra_a.b,7,1),
	MKLINE(extra_a.c,7,1),
	MKLINE(extra_a.d,7,1),
	MKLINE(extra_a.e,7,1),
	MKLINE(extra_a.f,7,1),
	MKLINE(extra_a.g,7,1),
	MKLINE(extra_a.h,7,1),

	MKLINE(flags_b,7,1),
	MKLINE(flags_b,6,1),
	MKLINE(flags_b,5,1),
	MKLINE(flags_b,4,1),
	MKLINE(flags_b,0,4),
	MKLINE(extra_b.a,0,8),
	MKLINE(extra_b.b,0,7),
	MKLINE(extra_b.c,0,7),
	MKLINE(extra_b.d,0,7),
	MKLINE(extra_b.e,0,7),
	MKLINE(extra_b.f,0,7),
	MKLINE(extra_b.g,0,7),
	MKLINE(extra_b.h,0,7),
	MKLINE(extra_b.b,7,1),
	MKLINE(extra_b.c,7,1),
	MKLINE(extra_b.d,7,1),
	MKLINE(extra_b.e,7,1),
	MKLINE(extra_b.f,7,1),
	MKLINE(extra_b.g,7,1),
	MKLINE(extra_b.h,7,1),

	MKLINE(duration,0,8),
};
#undef MKLINE

void AdlibSoundDriver::part_set_param(Part *part, byte param, int value) {
	const AdlibInstrSetParams *sp = &adlib_instr_params[param];
	byte *p = (byte*)&_part_instr[part->_slot] + sp->param;
	*p = (*p&~sp->mask) | (value<<sp->shl);

	if (param < 28) {
		MidiChannelAdl *mc;

		for(mc=(MidiChannelAdl*)part->_mc; mc; mc=mc->_next) {
			adlib_set_param(mc->_channel, param, value);
		}
	}
}

void AdlibSoundDriver::part_off(Part *part) {
	MidiChannelAdl *mc = (MidiChannelAdl*)part->_mc;
	part->_mc = NULL;
	for(; mc; mc=mc->_next) {
		mc_off(mc);
	}
}

void AdlibSoundDriver::mc_off(MidiChannel *mc2) {
	MidiChannelAdl *mc = (MidiChannelAdl*)mc2, *tmp;

	adlib_key_off(mc->_channel);

	tmp = mc->_prev;

	if (mc->_next)
		mc->_next->_prev = tmp;
	if (tmp)
		tmp->_next = mc->_next;
	else
		mc->_part->_mc = mc->_next;
	mc->_part = NULL;
}

void AdlibSoundDriver::part_set_instrument(Part *part, Instrument *instr) {
	Instrument *i = &_part_instr[part->_slot];
	memcpy(i, instr, sizeof(Instrument));
}

int AdlibSoundDriver::part_update_active(Part *part,uint16 *active) {
	int i;
	uint16 bits;
	int count = 0;
	MidiChannelAdl *mc;

	bits = 1<<part->_chan;

	for(mc=part->_mc->adl(); mc; mc=mc->_next) {
		if (!(active[mc->_note] & bits)) {
			active[mc->_note] |= bits;
			count++;
		}
	}
	return count;
}

#endif
--- NEW FILE: fmopl.cpp ---
/*
**
** File: fmopl.c -- software implementation of FM sound generator
**
** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmurator development
** Modified for ScummVM by Ludvig Strigeus
** Version 0.37a (modified)
**
*/

#include "stdafx.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include "fmopl.h"

[...1067 lines suppressed...]
	if( c )
	{	/* Timer B */
		OPL_STATUS_SET(OPL,0x20);
	}
	else
	{	/* Timer A */
		OPL_STATUS_SET(OPL,0x40);
		/* CSM mode key,TL controll */
		if( OPL->mode & 0x80 )
		{	/* CSM mode total level latch and auto key on */
			int ch;
			if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
			for(ch=0;ch<9;ch++)
				CSMKeyControll( &OPL->P_CH[ch] );
		}
	}
	/* reload timer */
	if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase);
	return OPL->status>>7;
}

--- NEW FILE: fmopl.h ---

#ifndef __FMOPL_H_
#define __FMOPL_H_

/* --- select emulation chips --- */
#define BUILD_YM3812 (HAS_YM3812)
#define BUILD_YM3526 (HAS_YM3526)
#define BUILD_Y8950  (HAS_Y8950)

/* --- system optimize --- */
/* select bit size of output : 8 or 16 */
#define OPL_OUTPUT_BIT 16

/* compiler dependence */
#ifndef OSD_CPU_H
#define OSD_CPU_H
typedef unsigned char	UINT8;   /* unsigned  8bit */
typedef unsigned short	UINT16;  /* unsigned 16bit */
typedef unsigned int	UINT32;  /* unsigned 32bit */
typedef signed char		INT8;    /* signed  8bit   */
typedef signed short	INT16;   /* signed 16bit   */
typedef signed int		INT32;   /* signed 32bit   */
#endif

#if (OPL_OUTPUT_BIT==16)
typedef INT16 OPLSAMPLE;
#endif
#if (OPL_OUTPUT_BIT==8)
typedef unsigned char  OPLSAMPLE;
#endif


typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
typedef void (*OPL_IRQHANDLER)(int param,int irq);
typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
typedef unsigned char (*OPL_PORTHANDLER_R)(int param);

/* !!!!! here is private section , do not access there member direct !!!!! */

#define OPL_TYPE_WAVESEL   0x01  /* waveform select    */
#define OPL_TYPE_ADPCM     0x02  /* DELTA-T ADPCM unit */
#define OPL_TYPE_KEYBOARD  0x04  /* keyboard interface */
#define OPL_TYPE_IO        0x08  /* I/O port */

/* Saving is necessary for member of the 'R' mark for suspend/resume */
/* ---------- OPL one of slot  ---------- */
typedef struct fm_opl_slot {
	INT32 TL;		/* total level     :TL << 8            */
	INT32 TLL;		/* adjusted now TL                     */
	UINT8  KSR;		/* key scale rate  :(shift down bit)   */
	INT32 *AR;		/* attack rate     :&AR_TABLE[AR<<2]   */
	INT32 *DR;		/* decay rate      :&DR_TALBE[DR<<2]   */
	INT32 SL;		/* sustin level    :SL_TALBE[SL]       */
	INT32 *RR;		/* release rate    :&DR_TABLE[RR<<2]   */
	UINT8 ksl;		/* keyscale level  :(shift down bits)  */
	UINT8 ksr;		/* key scale rate  :kcode>>KSR         */
	UINT32 mul;		/* multiple        :ML_TABLE[ML]       */
	UINT32 Cnt;		/* frequency count :                   */
	UINT32 Incr;	/* frequency step  :                   */
	/* envelope generator state */
	UINT8 eg_typ;	/* envelope type flag                  */
	UINT8 evm;		/* envelope phase                      */
	INT32 evc;		/* envelope counter                    */
	INT32 eve;		/* envelope counter end point          */
	INT32 evs;		/* envelope counter step               */
	INT32 evsa;	/* envelope step for AR :AR[ksr]           */
	INT32 evsd;	/* envelope step for DR :DR[ksr]           */
	INT32 evsr;	/* envelope step for RR :RR[ksr]           */
	/* LFO */
	UINT8 ams;		/* ams flag                            */
	UINT8 vib;		/* vibrate flag                        */
	/* wave selector */
	INT32 **wavetable;
}OPL_SLOT;

/* ---------- OPL one of channel  ---------- */
typedef struct fm_opl_channel {
	OPL_SLOT SLOT[2];
	UINT8 CON;			/* connection type                     */
	UINT8 FB;			/* feed back       :(shift down bit)   */
	INT32 *connect1;	/* slot1 output pointer                */
	INT32 *connect2;	/* slot2 output pointer                */
	INT32 op1_out[2];	/* slot1 output for selfeedback        */
	/* phase generator state */
	UINT32  block_fnum;	/* block+fnum      :                   */
	UINT8 kcode;		/* key code        : KeyScaleCode      */
	UINT32  fc;			/* Freq. Increment base                */
	UINT32  ksl_base;	/* KeyScaleLevel Base step             */
	UINT8 keyon;		/* key on/off flag                     */
} OPL_CH;

/* OPL state */
struct FM_OPL {
	UINT8 type;			/* chip type                         */
	int clock;			/* master clock  (Hz)                */
	int rate;			/* sampling rate (Hz)                */
	double freqbase;	/* frequency base                    */
	double TimerBase;	/* Timer base time (==sampling time) */
	UINT8 address;		/* address register                  */
	UINT8 status;		/* status flag                       */
	UINT8 statusmask;	/* status mask                       */
	UINT32 mode;		/* Reg.08 : CSM , notesel,etc.       */
	/* Timer */
	int T[2];			/* timer counter                     */
	UINT8 st[2];		/* timer enable                      */
	/* FM channel slots */
	OPL_CH *P_CH;		/* pointer of CH                     */
	int	max_ch;			/* maximum channel                   */
	/* Rythm sention */
	UINT8 rythm;		/* Rythm mode , key flag */
	/* time tables */
	/* LFO */
	INT32 *ams_table;
	INT32 *vib_table;
	INT32 amsCnt;
	INT32 amsIncr;
	INT32 vibCnt;
	INT32 vibIncr;
	/* wave selector enable flag */
	UINT8 wavesel;
	/* external event callback handler */
	OPL_TIMERHANDLER  TimerHandler;		/* TIMER handler   */
	int TimerParam;						/* TIMER parameter */
	OPL_IRQHANDLER    IRQHandler;		/* IRQ handler    */
	int IRQParam;						/* IRQ parameter  */
	OPL_UPDATEHANDLER UpdateHandler;	/* stream update handler   */
	int UpdateParam;					/* stream update parameter */
	INT32 AR_TABLE[75];	/* atttack rate tables */
	INT32 DR_TABLE[75];	/* decay rate tables   */
	UINT32 FN_TABLE[1024];  /* fnumber -> increment counter */
};

/* ---------- Generic interface section ---------- */
#define OPL_TYPE_YM3526 (0)
#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
#define OPL_TYPE_Y8950  (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)

FM_OPL *OPLCreate(int type, int clock, int rate);
void OPLDestroy(FM_OPL *OPL);
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);

void OPLResetChip(FM_OPL *OPL);
int OPLWrite(FM_OPL *OPL,int a,int v);
unsigned char OPLRead(FM_OPL *OPL,int a);
int OPLTimerOver(FM_OPL *OPL,int c);

void OPLWriteReg(FM_OPL *OPL, int r, int v);

/* YM3626/YM3812 local section */
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);

#endif

--- NEW FILE: gmidi.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sound/gmidi.cpp,v 1.2.2.1 2001/12/20 00:34:06 yazoo Exp $
 */

/*
 * Timidity support by Lionel Ulmer <lionel.ulmer at free.fr>
 */


#include "stdafx.h"

#if !defined USE_ADLIB

#include "scumm.h"
#include "sound.h"

#ifdef USE_TIMIDITY
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Copy-pasted from Timidity */
#define SEQ_MIDIPUTC		5

#endif /* USE_TIMIDITY */


#define SPECIAL_CHANNEL 9

#if defined(WIN32)

void MidiSoundDriver::midiInit() {
	if (midiOutOpen((HMIDIOUT*)&_mo, MIDI_MAPPER, NULL, NULL, 0) != MMSYSERR_NOERROR)
		error("midiOutOpen failed");
}

#define MIDI_OUT(a,b) midiOutShortMsg((HMIDIOUT)(a), (b))

#elif defined(USE_TIMIDITY)

static int connect_to_timidity(int port)
{
	struct hostent *serverhost;
	struct sockaddr_in sadd;
	int s;
	
	serverhost = gethostbyname("localhost");
	if (serverhost == NULL)
		error("Could not resolve host");
	sadd.sin_family = serverhost->h_addrtype;
	sadd.sin_port = htons(port);
	memcpy(&(sadd.sin_addr), serverhost->h_addr_list[0], serverhost->h_length);
	
	s = socket(AF_INET,SOCK_STREAM,0);
	if (s < 0)
		error("Could not open socket");
	if (connect(s, (struct sockaddr *) &sadd, sizeof(struct sockaddr_in)) < 0)
		error("Could not connect to server");
	
	return s;
}

void MidiSoundDriver::midiInit() {
	int s, s2;
	int len;
	int dummy, newport;
	char buf[256];

	s = connect_to_timidity(7777);
	len = read(s, buf, 256);
	buf[len] = '\0';
	printf("%s", buf);

	sprintf(buf, "SETBUF %f %f\n", 0.1, 0.15);
	write(s, buf, strlen(buf));
	len = read(s, buf, 256);
	buf[len] = '\0';
	printf("%s", buf);	
	
	sprintf(buf, "OPEN lsb\n");
	write(s, buf, strlen(buf));
	len = read(s, buf, 256);
	buf[len] = '\0';
	printf("%s", buf);	

	sscanf(buf, "%d %d", &dummy, &newport);
	printf("	 => port = %d\n", newport);
	
	s2 = connect_to_timidity(newport);
	_mo = (void *) s2;
}

#define DEVICE_NUM 0

static inline void MIDI_OUT(void *a, int b) {
	int s = (int) a;
	unsigned char buf[256];
	int position = 0;
	
	switch (b & 0xF0) {
	case 0x80:
	case 0x90:
	case 0xA0:
	case 0xB0:
	case 0xE0:
		buf[position++] = SEQ_MIDIPUTC;
		buf[position++] = b;
		buf[position++] = DEVICE_NUM;		
		buf[position++] = 0;
		buf[position++] = SEQ_MIDIPUTC;
		buf[position++] = (b >> 8) & 0x7F;
		buf[position++] = DEVICE_NUM;		
		buf[position++] = 0;
		buf[position++] = SEQ_MIDIPUTC;
		buf[position++] = (b >> 16) & 0x7F;
		buf[position++] = DEVICE_NUM;		
		buf[position++] = 0;
		break;
	case 0xC0:
	case 0xD0:
		buf[position++] = SEQ_MIDIPUTC;
		buf[position++] = b;
		buf[position++] = DEVICE_NUM;		
		buf[position++] = 0;
		buf[position++] = SEQ_MIDIPUTC;
		buf[position++] = (b >> 8) & 0x7F;
		buf[position++] = DEVICE_NUM;		
		buf[position++] = 0;
		break;
	default:
		fprintf(stderr, "Unknown : %08x\n", b);
		break;
	}
	write(s, buf, position);
}

#else
#define MIDI_OUT(a,b)
void MidiSoundDriver::midiInit() { }
#endif

void MidiSoundDriver::midiPitchBend(byte chan, int16 pitchbend) {
	uint16 tmp;

	if (_midi_pitchbend_last[chan] != pitchbend) {
		_midi_pitchbend_last[chan] = pitchbend;
		tmp = (pitchbend<<2) + 0x2000;
		MIDI_OUT(_mo, ((tmp>>7)&0x7F)<<16 | (tmp&0x7F)<<8 | 0xE0 | chan);
	}
}

void MidiSoundDriver::midiVolume(byte chan, byte volume) {
	if (_midi_volume_last[chan] != volume) {
		_midi_volume_last[chan] = volume;
		MIDI_OUT(_mo, volume<<16 | 7<<8 | 0xB0 | chan);
	}
}
void MidiSoundDriver::midiPedal(byte chan, bool pedal) {
	if (_midi_pedal_last[chan] != pedal) {
		_midi_pedal_last[chan] = pedal;
		MIDI_OUT(_mo, pedal<<16 | 64<<8 | 0xB0 | chan);
	}
}

void MidiSoundDriver::midiModWheel(byte chan, byte modwheel) {
	if (_midi_modwheel_last[chan] != modwheel) {
		_midi_modwheel_last[chan] = modwheel;
		MIDI_OUT(_mo, modwheel<<16 | 1<<8 | 0xB0 | chan);
	}
}

void MidiSoundDriver::midiEffectLevel(byte chan, byte level) {
	if (_midi_effectlevel_last[chan] != level) {
		_midi_effectlevel_last[chan] = level;
		MIDI_OUT(_mo, level<<16 | 91<<8 | 0xB0 | chan);
	}
}

void MidiSoundDriver::midiChorus(byte chan, byte chorus) {
	if (_midi_chorus_last[chan] != chorus) {
		_midi_chorus_last[chan] = chorus;
		MIDI_OUT(_mo, chorus<<16 | 93<<8 | 0xB0 | chan);
	}
}

void MidiSoundDriver::midiControl0(byte chan, byte value) {
	MIDI_OUT(_mo, value<<16 | 0<<8 | 0xB0 | chan);
}

static const byte mt32_to_gmidi[128] = {
   0,   1,   2,   4,   4,   5,   5,   3,  16,  17,  18,  18,  19,
  19,  20,  21,   6,   6,   6,   7,   7,   7,   8,   8,  62,  63,
  62,  63,  38,  39,  38,  39,  88,  89,  52, 113,  97,  96,  91,
  85,  14, 101,  68,  95,  86, 103,  88,  80,  48,  49,  51,  45,
  40,  40,  42,  42,  43,  46,  46,  24,  25,  26,  27, 104,  32,
  33,  34,  39,  36,  37,  38,  35,  79,  73,  72,  72,  74,  75,
  64,  65,  66,  67,  71,  71,  68,  69,  70,  22,  56,  59,  57,
  63,  60,  60,  58,  61,  61,  11,  11,  12,  88,   9,  14,  13,
  12, 107, 111,  77,  78,  78,  76, 121,  47, 117, 127, 115, 118,
 116, 118,  94, 115,   9,  55, 124, 123, 125, 126, 127
};


void MidiSoundDriver::midiProgram(byte chan, byte program) {
	if (_mt32emulate)
		program=mt32_to_gmidi[program];
	MIDI_OUT(_mo, program<<8 | 0xC0 | chan);
}

void MidiSoundDriver::midiPan(byte chan, int8 pan) {
	if (_midi_pan_last[chan] != pan) {
		_midi_pan_last[chan] = pan;
		MIDI_OUT(_mo, ((pan-64)&0x7F)<<16 | 10<<8 | 0xB0 | chan);
	}
}

void MidiSoundDriver::midiNoteOn(byte chan, byte note, byte velocity) {
	MIDI_OUT(_mo, velocity<<16 | note<<8 | 0x90 | chan);	
}

void MidiSoundDriver::midiNoteOff(byte chan, byte note) {
	MIDI_OUT(_mo, note<<8 | 0x80 | chan);	
}

void MidiSoundDriver::midiSilence(byte chan) {
	MIDI_OUT(_mo, (64<<8)|0xB0|chan);
	MIDI_OUT(_mo, (123<<8)|0xB0|chan);
}


void MidiSoundDriver::part_key_on(Part *part, byte note, byte velocity) {
	MidiChannelGM *mc = part->_mc->gm();

	if (mc) {
		mc->_actives[note>>4] |= (1<<(note&0xF));
		midiNoteOn(mc->_chan, note, velocity);
	} else if (part->_percussion) {
		midiVolume(SPECIAL_CHANNEL, part->_vol_eff);
		midiProgram(SPECIAL_CHANNEL, part->_bank);
		midiNoteOn(SPECIAL_CHANNEL, note, velocity);
	}
}

void MidiSoundDriver::part_key_off(Part *part, byte note) {
	MidiChannelGM *mc = part->_mc->gm();

	if (mc) {
		mc->_actives[note>>4] &= ~(1<<(note&0xF));
		midiNoteOff(mc->_chan, note);
	} else if (part->_percussion) {
		midiNoteOff(SPECIAL_CHANNEL, note);
	}
}

void MidiSoundDriver::init(SoundEngine *eng) {
	int i;
	MidiChannelGM *mc;

	_se = eng;

	for(i=0,mc=_midi_channels; i!=ARRAYSIZE(_midi_channels);i++,mc++)
		mc->_chan = i;

	midiInit();
}

void MidiSoundDriver::update_pris() {
	Part *part,*hipart;
	int i;
	byte hipri,lopri;
	MidiChannelGM *mc,*lomc;

	while(true) {
		hipri = 0;
		hipart = NULL;
		for(i=32,part=_se->parts_ptr(); i; i--,part++) {
			if (part->_player && !part->_percussion && part->_on && !part->_mc && part->_pri_eff>=hipri) {
				hipri = part->_pri_eff;
				hipart = part;
			}
		}

		if (!hipart)
			return;

		lopri = 255;
		lomc = NULL;
		for(i=ARRAYSIZE(_midi_channels),mc=_midi_channels;;mc++) {
			if (!mc->_part) {
				lomc = mc;
				break;
			}
			if (mc->_part->_pri_eff<=lopri) {
				lopri = mc->_part->_pri_eff;
				lomc = mc;
			}

			if (!--i) {
				if (lopri >= hipri)
					return;
				lomc->_part->off();
				break;
			}
		}

		hipart->_mc = lomc;
		lomc->_part = hipart;
		hipart->changed(pcAll);
	}
}

int MidiSoundDriver::part_update_active(Part *part, uint16 *active) {
	int i,j;
	uint16 *act,mask,bits;
	int count = 0;

	bits = 1<<part->_chan;

	act = part->_mc->gm()->_actives;

	for(i=8; i; i--) {
		mask = *act++;
		if (mask) {
			for(j=16; j; j--,mask>>=1,active++) {
				if (mask&1 && !(*active&bits)) {
					*active|=bits;
					count++;
				}
			}
		} else {
			active += 16;
		}
	}
	return count;
}

void MidiSoundDriver::part_changed(Part *part, byte what) {
	MidiChannelGM *mc;

	/* Mark for re-schedule if program changed when in pre-state */
	if (what&pcProgram && part->_percussion) {
		part->_percussion = false;
		update_pris();
	}
	
	if (!(mc = part->_mc->gm()))
		return;

	if (what & pcMod)
		midiPitchBend(mc->_chan, clamp(part->_pitchbend + part->_detune_eff + (part->_transpose_eff<<7), -2048, 2047));	

	if (what & pcVolume)
		midiVolume(mc->_chan, part->_vol_eff);

	if (what & pcPedal)
		midiPedal(mc->_chan, part->_pedal);

	if (what & pcModwheel)
		midiModWheel(mc->_chan, part->_modwheel);

	if (what & pcPan)
		midiPan(mc->_chan, part->_pan_eff);

	if (what & pcEffectLevel)
		midiEffectLevel(mc->_chan, part->_effect_level);

	if (what & pcProgram) {
		if (part->_bank) {
			midiControl0(mc->_chan, part->_bank);
			midiProgram(mc->_chan, part->_program);
			midiControl0(mc->_chan, 0);
		} else {
			midiProgram(mc->_chan, part->_program);
		}
	}

	if (what & pcChorus)
		midiChorus(mc->_chan, part->_effect_level);
}


void MidiSoundDriver::part_off(Part *part) {
	MidiChannelGM *mc = part->_mc->gm();
	if (mc) {
		part->_mc = NULL;
		mc->_part = NULL;
		memset(mc->_actives, 0, sizeof(mc->_actives));
		midiSilence(mc->_chan);
	}
}

#endif
--- NEW FILE: imuse.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sound/imuse.cpp,v 1.1.2.1 2001/12/20 00:34:06 yazoo Exp $
 */
[...2273 lines suppressed...]
}

int Part::update_actives(uint16 *active) {
	return _drv->part_update_active(this, active);
}

void Part::set_program(byte program) {
	if (_program!=program || _bank!=0) {
		_program = program;
		_bank = 0;
		changed(SoundDriver::pcProgram);
	}
}

void Part::set_instrument(uint b) {
	_bank = (byte)(b>>8);
	_program = (byte)b;
	changed(SoundDriver::pcProgram);
}






More information about the Scummvm-git-logs mailing list