[Scummvm-cvs-logs] CVS: scummvm/backends/midi/mt32 .cvsignore,NONE,1.1 freeverb.cpp,NONE,1.1 freeverb.h,NONE,1.1 mt32.cpp,NONE,1.1 partial.cpp,NONE,1.1 partial.h,NONE,1.1 structures.h,NONE,1.1 synth.cpp,NONE,1.1 synth.h,NONE,1.1

Eugene Sandulenko sev at users.sourceforge.net
Thu Oct 21 15:43:37 CEST 2004


Update of /cvsroot/scummvm/scummvm/backends/midi/mt32
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22342/backends/midi/mt32

Added Files:
	.cvsignore freeverb.cpp freeverb.h mt32.cpp partial.cpp 
	partial.h structures.h synth.cpp synth.h 
Log Message:
Patch #1048326 Better MT-32 support 


--- NEW FILE: .cvsignore ---
.deps

--- NEW FILE: freeverb.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 The ScummVM project
 * Copyright (C) 2000 Jezar at Dreampoint
 *
 * This code is public domain
 *
 * Parts of this code are:
 *
 * 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/backends/midi/mt32/freeverb.cpp,v 1.1 2004/10/21 22:37:30 sev Exp $
 *
 */

// Comb filter implementation
//
// Written by 
// http://www.dreampoint.co.uk
// This code is public domain

#include "stdafx.h"
#include "backends/midi/mt32/freeverb.h"

comb::comb()
{
	filterstore = 0;
	bufidx = 0;
}

void comb::setbuffer(float *buf, int size) 
{
	buffer = buf; 
	bufsize = size;
}

void comb::mute()
{
	for (int i=0; i<bufsize; i++)
		buffer[i]=0;
}

void comb::setdamp(float val) 
{
	damp1 = val; 
	damp2 = 1-val;
}

float comb::getdamp() 
{
	return damp1;
}

void comb::setfeedback(float val) 
{
	feedback = val;
}

float comb::getfeedback() 
{
	return feedback;
}

// Allpass filter implementation

allpass::allpass()
{
	bufidx = 0;
}

void allpass::setbuffer(float *buf, int size) 
{
	buffer = buf; 
	bufsize = size;
}

void allpass::mute()
{
	for (int i=0; i<bufsize; i++)
		buffer[i]=0;
}

void allpass::setfeedback(float val) 
{
	feedback = val;
}

float allpass::getfeedback() 
{
	return feedback;
}

// Reverb model implementation

revmodel::revmodel()
{
	// Tie the components to their buffers
	combL[0].setbuffer(bufcombL1,combtuningL1);
	combR[0].setbuffer(bufcombR1,combtuningR1);
	combL[1].setbuffer(bufcombL2,combtuningL2);
	combR[1].setbuffer(bufcombR2,combtuningR2);
	combL[2].setbuffer(bufcombL3,combtuningL3);
	combR[2].setbuffer(bufcombR3,combtuningR3);
	combL[3].setbuffer(bufcombL4,combtuningL4);
	combR[3].setbuffer(bufcombR4,combtuningR4);
	combL[4].setbuffer(bufcombL5,combtuningL5);
	combR[4].setbuffer(bufcombR5,combtuningR5);
	combL[5].setbuffer(bufcombL6,combtuningL6);
	combR[5].setbuffer(bufcombR6,combtuningR6);
	combL[6].setbuffer(bufcombL7,combtuningL7);
	combR[6].setbuffer(bufcombR7,combtuningR7);
	combL[7].setbuffer(bufcombL8,combtuningL8);
	combR[7].setbuffer(bufcombR8,combtuningR8);
	allpassL[0].setbuffer(bufallpassL1,allpasstuningL1);
	allpassR[0].setbuffer(bufallpassR1,allpasstuningR1);
	allpassL[1].setbuffer(bufallpassL2,allpasstuningL2);
	allpassR[1].setbuffer(bufallpassR2,allpasstuningR2);
	allpassL[2].setbuffer(bufallpassL3,allpasstuningL3);
	allpassR[2].setbuffer(bufallpassR3,allpasstuningR3);
	allpassL[3].setbuffer(bufallpassL4,allpasstuningL4);
	allpassR[3].setbuffer(bufallpassR4,allpasstuningR4);

	// Set default values
	allpassL[0].setfeedback(0.5f);
	allpassR[0].setfeedback(0.5f);
	allpassL[1].setfeedback(0.5f);
	allpassR[1].setfeedback(0.5f);
	allpassL[2].setfeedback(0.5f);
	allpassR[2].setfeedback(0.5f);
	allpassL[3].setfeedback(0.5f);
	allpassR[3].setfeedback(0.5f);
	setwet(initialwet);
	setroomsize(initialroom);
	setdry(initialdry);
	setdamp(initialdamp);
	setwidth(initialwidth);
	setmode(initialmode);

	// Buffer will be full of rubbish - so we MUST mute them
	mute();
}

void revmodel::mute()
{
	int i;

	if (getmode() >= freezemode)
		return;

	for (i=0;i<numcombs;i++)
	{
		combL[i].mute();
		combR[i].mute();
	}
	for (i=0;i<numallpasses;i++)
	{
		allpassL[i].mute();
		allpassR[i].mute();
	}
}

void revmodel::processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip)
{
	float outL,outR,input;

	while(numsamples-- > 0)
	{
		int i;

		outL = outR = 0;
		input = (*inputL + *inputR) * gain;

		// Accumulate comb filters in parallel
		for(i=0; i<numcombs; i++)
		{
			outL += combL[i].process(input);
			outR += combR[i].process(input);
		}

		// Feed through allpasses in series
		for(i=0; i<numallpasses; i++)
		{
			outL = allpassL[i].process(outL);
			outR = allpassR[i].process(outR);
		}

		// Calculate output REPLACING anything already there
		*outputL = outL*wet1 + outR*wet2 + *inputL*dry;
		*outputR = outR*wet1 + outL*wet2 + *inputR*dry;

		// Increment sample pointers, allowing for interleave (if any)
		inputL += skip;
		inputR += skip;
		outputL += skip;
		outputR += skip;
	}
}

void revmodel::processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip)
{
	float outL,outR,input;

	while(numsamples-- > 0)
	{
		int i;

		outL = outR = 0;
		input = (*inputL + *inputR) * gain;

		// Accumulate comb filters in parallel
		for(i=0; i<numcombs; i++)
		{
			outL += combL[i].process(input);
			outR += combR[i].process(input);
		}

		// Feed through allpasses in series
		for(i=0; i<numallpasses; i++)
		{
			outL = allpassL[i].process(outL);
			outR = allpassR[i].process(outR);
		}

		// Calculate output MIXING with anything already there
		*outputL += outL*wet1 + outR*wet2 + *inputL*dry;
		*outputR += outR*wet1 + outL*wet2 + *inputR*dry;

		// Increment sample pointers, allowing for interleave (if any)
		inputL += skip;
		inputR += skip;
		outputL += skip;
		outputR += skip;
	}
}

void revmodel::update()
{
// Recalculate internal values after parameter change

	int i;

	wet1 = wet*(width/2 + 0.5f);
	wet2 = wet*((1-width)/2);

	if (mode >= freezemode)
	{
		roomsize1 = 1;
		damp1 = 0;
		gain = muted;
	}
	else
	{
		roomsize1 = roomsize;
		damp1 = damp;
		gain = fixedgain;
	}

	for(i=0; i<numcombs; i++)
	{
		combL[i].setfeedback(roomsize1);
		combR[i].setfeedback(roomsize1);
	}

	for(i=0; i<numcombs; i++)
	{
		combL[i].setdamp(damp1);
		combR[i].setdamp(damp1);
	}
}

// The following get/set functions are not inlined, because
// speed is never an issue when calling them, and also
// because as you develop the reverb model, you may
// wish to take dynamic action when they are called.

void revmodel::setroomsize(float value)
{
	roomsize = (value*scaleroom) + offsetroom;
	update();
}

float revmodel::getroomsize()
{
	return (roomsize-offsetroom)/scaleroom;
}

void revmodel::setdamp(float value)
{
	damp = value*scaledamp;
	update();
}

float revmodel::getdamp()
{
	return damp/scaledamp;
}

void revmodel::setwet(float value)
{
	wet = value*scalewet;
	update();
}

float revmodel::getwet()
{
	return wet/scalewet;
}

void revmodel::setdry(float value)
{
	dry = value*scaledry;
}

float revmodel::getdry()
{
	return dry/scaledry;
}

void revmodel::setwidth(float value)
{
	width = value;
	update();
}

float revmodel::getwidth()
{
	return width;
}

void revmodel::setmode(float value)
{
	mode = value;
	update();
}

float revmodel::getmode()
{
	if (mode >= freezemode)
		return 1;
	else
		return 0;
}

//ends


--- NEW FILE: freeverb.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 The ScummVM project
 * Copyright (C) 2000 Jezar at Dreampoint
 *
 * This code is public domain
 *
 * Parts of this code are:
 *
 * 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/backends/midi/mt32/freeverb.h,v 1.1 2004/10/21 22:37:30 sev Exp $
 *
 */

// Macro for killing denormalled numbers
//
// Written by Jezar at Dreampoint, June 2000
// http://www.dreampoint.co.uk
// Based on IS_DENORMAL macro by Jon Watte
// This code is public domain

#ifndef _freeverb_h_
#define _freeverb_h_

#define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f

// Comb filter class declaration

class comb
{
public:
					comb();
			void	setbuffer(float *buf, int size);
	inline  float	process(float inp);
			void	mute();
			void	setdamp(float val);
			float	getdamp();
			void	setfeedback(float val);
			float	getfeedback();
private:
	float	feedback;
	float	filterstore;
	float	damp1;
	float	damp2;
	float	*buffer;
	int		bufsize;
	int		bufidx;
};


// Big to inline - but crucial for speed

inline float comb::process(float input)
{
	float output;

	output = buffer[bufidx];
	undenormalise(output);

	filterstore = (output*damp2) + (filterstore*damp1);
	undenormalise(filterstore);

	buffer[bufidx] = input + (filterstore*feedback);

	if(++bufidx>=bufsize) bufidx = 0;

	return output;
}

// Allpass filter declaration

class allpass
{
public:
					allpass();
			void	setbuffer(float *buf, int size);
	inline  float	process(float inp);
			void	mute();
			void	setfeedback(float val);
			float	getfeedback();
// private:
	float	feedback;
	float	*buffer;
	int		bufsize;
	int		bufidx;
};


// Big to inline - but crucial for speed

inline float allpass::process(float input)
{
	float output;
	float bufout;
	
	bufout = buffer[bufidx];
	undenormalise(bufout);
	
	output = -input + bufout;
	buffer[bufidx] = input + (bufout*feedback);

	if(++bufidx>=bufsize) bufidx = 0;

	return output;
}


// Reverb model tuning values

const int	numcombs		= 8;
const int	numallpasses	= 4;
const float	muted			= 0;
const float	fixedgain		= 0.015f;
const float scalewet		= 3;
const float scaledry		= 2;
const float scaledamp		= 0.4f;
const float scaleroom		= 0.28f;
const float offsetroom		= 0.7f;
const float initialroom		= 0.5f;
const float initialdamp		= 0.5f;
const float initialwet		= 1/scalewet;
const float initialdry		= 0;
const float initialwidth	= 1;
const float initialmode		= 0;
const float freezemode		= 0.5f;
const int	stereospread	= 23;

// These values assume 44.1KHz sample rate
// they will probably be OK for 48KHz sample rate
// but would need scaling for 96KHz (or other) sample rates.
// The values were obtained by listening tests.
const int combtuningL1		= 1116;
const int combtuningR1		= 1116+stereospread;
const int combtuningL2		= 1188;
const int combtuningR2		= 1188+stereospread;
const int combtuningL3		= 1277;
const int combtuningR3		= 1277+stereospread;
const int combtuningL4		= 1356;
const int combtuningR4		= 1356+stereospread;
const int combtuningL5		= 1422;
const int combtuningR5		= 1422+stereospread;
const int combtuningL6		= 1491;
const int combtuningR6		= 1491+stereospread;
const int combtuningL7		= 1557;
const int combtuningR7		= 1557+stereospread;
const int combtuningL8		= 1617;
const int combtuningR8		= 1617+stereospread;
const int allpasstuningL1	= 556;
const int allpasstuningR1	= 556+stereospread;
const int allpasstuningL2	= 441;
const int allpasstuningR2	= 441+stereospread;
const int allpasstuningL3	= 341;
const int allpasstuningR3	= 341+stereospread;
const int allpasstuningL4	= 225;
const int allpasstuningR4	= 225+stereospread;


// Reverb model declaration

class revmodel
{
public:
					revmodel();
			void	mute();
			void	processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip);
			void	processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip);
			void	setroomsize(float value);
			float	getroomsize();
			void	setdamp(float value);
			float	getdamp();
			void	setwet(float value);
			float	getwet();
			void	setdry(float value);
			float	getdry();
			void	setwidth(float value);
			float	getwidth();
			void	setmode(float value);
			float	getmode();
private:
			void	update();
private:
	float	gain;
	float	roomsize,roomsize1;
	float	damp,damp1;
	float	wet,wet1,wet2;
	float	dry;
	float	width;
	float	mode;

	// The following are all declared inline 
	// to remove the need for dynamic allocation
	// with its subsequent error-checking messiness

	// Comb filters
	comb	combL[numcombs];
	comb	combR[numcombs];

	// Allpass filters
	allpass	allpassL[numallpasses];
	allpass	allpassR[numallpasses];

	// Buffers for the combs
	float	bufcombL1[combtuningL1];
	float	bufcombR1[combtuningR1];
	float	bufcombL2[combtuningL2];
	float	bufcombR2[combtuningR2];
	float	bufcombL3[combtuningL3];
	float	bufcombR3[combtuningR3];
	float	bufcombL4[combtuningL4];
	float	bufcombR4[combtuningR4];
	float	bufcombL5[combtuningL5];
	float	bufcombR5[combtuningR5];
	float	bufcombL6[combtuningL6];
	float	bufcombR6[combtuningR6];
	float	bufcombL7[combtuningL7];
	float	bufcombR7[combtuningR7];
	float	bufcombL8[combtuningL8];
	float	bufcombR8[combtuningR8];

	// Buffers for the allpasses
	float	bufallpassL1[allpasstuningL1];
	float	bufallpassR1[allpasstuningR1];
	float	bufallpassL2[allpasstuningL2];
	float	bufallpassR2[allpasstuningR2];
	float	bufallpassL3[allpasstuningL3];
	float	bufallpassR3[allpasstuningR3];
	float	bufallpassL4[allpasstuningL4];
	float	bufallpassR4[allpasstuningR4];
};

#endif//_freeverb_h_

//ends


--- NEW FILE: mt32.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001-2004 The ScummVM project
 *
 * YM2612 tone generation code written by Tomoaki Hayasaka.
 * Used under the terms of the GNU General Public License.
 * Adpated to ScummVM by Jamieson Christian.
 *
 * 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/backends/midi/mt32/mt32.cpp,v 1.1 2004/10/21 22:37:30 sev Exp $
 */

#include "backends/midi/emumidi.h"

#include "common/util.h"
#include "common/file.h"

#include "backends/midi/mt32/synth.h"

class MidiDriver_MT32 : public MidiDriver_Emulated {
private:
	CSynthMT32 *_synth;

	const char *rom_path;

protected:
	void generate_samples(int16 *buf, int len);

public:
	MidiDriver_MT32(SoundMixer *mixer, const char *path);
	virtual ~MidiDriver_MT32();

	int open();
	void close();
	void send(uint32 b);
	uint32 property(int prop, uint32 param) { return 0; }

	void setPitchBendRange(byte channel, uint range) { }
	void sysEx(byte *msg, uint16 length);

	MidiChannel *allocateChannel() { return 0; }
	MidiChannel *getPercussionChannel() { return 0; }


	// AudioStream API
	bool isStereo() const { return true; }
	int getRate() const { return 32000; }
};


////////////////////////////////////////
//
// MidiDriver_MT32
//
////////////////////////////////////////


MidiDriver_MT32::MidiDriver_MT32(SoundMixer *mixer, const char *path)
	: MidiDriver_Emulated(mixer) {
	_synth = new CSynthMT32();
	rom_path = path;
	File::addDefaultDirectory(path);
}

MidiDriver_MT32::~MidiDriver_MT32() {
	delete _synth;
}

int MidiDriver_MT32::open() {
	SynthProperties prop;

	if (_isOpen)
		return MERR_ALREADY_OPEN;
	
	MidiDriver_Emulated::open();
	
	prop.SampleRate = getRate(); // 32000;
	prop.UseReverb = true;
	prop.UseDefault = true;
	//prop.RevType = 0;
	//prop.RevTime = 5;
	//prop.RevLevel = 3;

	_synth->ClassicOpen(rom_path, prop);

	_mixer->setupPremix(this);

	return 0;
}

void MidiDriver_MT32::send(uint32 b) {
	_synth->PlayMsg(b);
}

void MidiDriver_MT32::sysEx(byte *msg, uint16 length) {
	_synth->PlaySysex(msg, length);
}

void MidiDriver_MT32::close() {
	if (!_isOpen)
		return;
	_isOpen = false;

	// Detach the premix callback handler
	_mixer->setupPremix(0);

	_synth->Close();
}

void MidiDriver_MT32::generate_samples(int16 *data, int len) {
	_synth->MT32_CallBack((Bit8u *)data, len, _mixer->getMusicVolume());
}


////////////////////////////////////////
//
// MidiDriver_MT32 factory
//
////////////////////////////////////////

MidiDriver *MidiDriver_MT32_create(SoundMixer *mixer, const char *path) {
	return new MidiDriver_MT32(mixer, path);
}

--- NEW FILE: partial.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 The ScummVM project
 * Based on Tristan's conversion of Canadacow's code
 *
 * 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/backends/midi/mt32/partial.cpp,v 1.1 2004/10/21 22:37:30 sev Exp $
 *
 */

// Implementation of the MT-32 partial class

#include "backends/midi/mt32/synth.h"
#include "backends/midi/mt32/partial.h"

INLINE void CPartialMT32::generateSamples(Bit16s * partialBuf, long length) {
	if (!isActive) return;
	if (alreadyOutputed) return;
	

 	alreadyOutputed = true;

	// Generate samples

	int r;
	int i;
	Bit32s envval, ampval, filtval;
	soundaddr *pOff = &partCache->partialOff;
	int noteval = partCache->keyedval;
	for(i=0;i<length;i++) {
		Bit32s ptemp = 0;

		if(partCache->envs[AMPENV].sustaining) {
			ampval = partCache->ampEnvCache;
		} else {
			if(partCache->envs[AMPENV].count<=0) {
				
				ampval = getAmpEnvelope(partCache,tmppoly);
				isActive = partCache->playPartial;
//TODO: check what is going on here
//				if (ampval < 0) ampval = 0;
				//printf("%d %d\n", (int)ampval, (int)isActive);
				if(!isActive) {
					tmppoly->partActive[timbreNum] = false;
					tmppoly->isActive = tmppoly->partActive[0] || tmppoly->partActive[1] || tmppoly->partActive[2] || tmppoly->partActive[3];
				}
				if(ampval>=128) ampval = 127;

				ampval = amptable[ampval];
				int tmpvel = tmppoly->vel;
				if(tcache->ampenvdir==1) tmpvel = 127-tmpvel;
				ampval = (ampval * ampveltable[tmpvel][(int)tcache->ampEnv.velosens]) >> 8;
			//if(partCache->envs[AMPENV].sustaining)
				partCache->ampEnvCache = ampval;
			} else {
				ampval = partCache->ampEnvCache;
			}
			--partCache->envs[AMPENV].count;
		}
	
		int delta = 0x10707;

		// Calculate Pitch envelope
		int lfoat = 0x1000;
		int pdep;
		if(partCache->pitchsustain) {
			// Calculate LFO position
			// LFO does not kick in completely until pitch envelope sustains
		
			if(tcache->lfodepth>0)  {
				partCache->lfopos++;

				if(partCache->lfopos>=tcache->lfoperiod) partCache->lfopos = 0;
				int lfoatm = (partCache->lfopos << 16) / tcache->lfoperiod;
				
				int lfoatr = sintable[lfoatm];

				lfoat = lfoptable[tcache->lfodepth][lfoatr];
			}
			pdep = partCache->pitchEnvCache;


		} else {
			envval = getPitchEnvelope(partCache,tmppoly);
			int pd=tcache->pitchEnv.depth;
			pdep = penvtable[pd][envval];
			if(partCache->pitchsustain) partCache->pitchEnvCache = pdep;

		}


		// Get waveform - either PCM or synthesized sawtooth or square


		if (tcache->PCMPartial) {
			// PCM partial
			
			if(!partCache->PCMDone) {
				
				int addr,len,tmppcm;
				partialTable *tPCM = &tcache->convPCM;

				if(tPCM->aggSound==-1) {
					delta = wavtabler[tPCM->pcmnum][noteval];
					addr = tPCM->addr;
					len = tPCM->len;

				} else {
					tmppcm = LoopPatterns[tPCM->aggSound][partCache->looppos];
					addr = PCM[tmppcm].addr;
					len = PCM[tmppcm].len;
					delta = looptabler[tPCM->aggSound][partCache->looppos][noteval];
				}

				if(ampval>0) {
					int ra,rb,dist;
					int taddr;
					if(delta<0x10000) {
						// Linear sound interpolation
						
						taddr = addr + pOff->pcmoffs.pcmplace;
						ra = romfile[taddr];
						rb = romfile[taddr+1];

						dist = rb-ra;
						r = (ra + ((dist * (Bit32s)(pOff->pcmoffs.pcmoffset>>8)) >>8));

					} else {
						
						//r = romfile[addr + pOff->pcmoffs.pcmplace];
						// Sound decimation
						// The right way to do it is to use a lowpass filter on the waveform before selecting
						// a point.  This is too slow.  The following appoximates this as fast as possible
						int idelta = delta >> 16;
						int ix;
						taddr = addr + pOff->pcmoffs.pcmplace;
						ra = 0;
						for(ix=0;ix<idelta;ix++) {
							ra += romfile[taddr++];
						}
						r = ra / idelta;
						


					}
				} else r = 0;

				ptemp = r;

				if ((pOff->pcmoffs.pcmplace) >= len) {
					if(tPCM->aggSound==-1) {
						if(tPCM->loop) {
							pOff->pcmabs = 0;
						} else {
							partCache->PCMDone = true;
							partCache->playPartial = false;
						}

					} else {
						partCache->looppos++;
						if(LoopPatterns[tPCM->aggSound][partCache->looppos]==-1) partCache->looppos=0;
						pOff->pcmabs = 0;
					}
					//LOG_MSG("tPCM %d loops %d done %d playPart %d", tPCM->pcmnum, tPCM->loop, partCache->PCMDone, partCache->playPartial);

				}


			}

		} else {
			// Synthesis partial
			int divis, hdivis, ofs, ofs3, toff;
			int minorplace;

			int wf = tcache->waveform ;

			divis = divtable[noteval]>>15;

			if(pOff->pcmoffs.pcmplace>=divis) pOff->pcmoffs.pcmplace = (Bit16u)(pOff->pcmoffs.pcmplace-divis);
			
			toff = pOff->pcmoffs.pcmplace;
			minorplace = pOff->pcmoffs.pcmoffset >> 14;
			
			int pa, pb;

			if(ampval>0) {

				filtval = getFiltEnvelope((Bit16s)ptemp,partCache,tmppoly);

				//LOG_MSG("Filtval: %d", filtval);
				
				if(wf==0) {
					// Square waveform.  Made by combining two pregenerated bandlimited
					// sawtooth waveforms
					// Pulse width is not yet correct
					
					hdivis = divis >> 1;
					int divmark = smalldivtable[noteval];
					//int pw = (tcache->pulsewidth * pulsemod[filtval]) >> 8;
					
					
					ofs = toff % (hdivis);

					ofs3 = toff + ((divmark*pulsetable[partCache->pulsewidth])>>16);
					ofs3 = ofs3 % (hdivis);
					
					pa = waveforms[1][noteval][(ofs<<2)+minorplace];
					pb = waveforms[0][noteval][(ofs3<<2)+minorplace];
					//ptemp = pa+pb+pulseoffset[tcache->pulsewidth];
					ptemp = (pa+pb)*4;
										
					// Non-bandlimited squarewave
					/*
					ofs = (divis*pulsetable[tcache->pulsewidth])>>8;
					if(toff < ofs) {
						ptemp = 1 * WGAMP;
					} else {
						ptemp = -1 * WGAMP;
					}*/


				} else {
					// Sawtooth.  Made by combining the full cosine and half cosine according
					// to how it looks on the MT-32.  What it really does it takes the
					// square wave and multiplies it by a full cosine
					// TODO: This area here crashes DosBox due to read overflow                     
					int offsetpos = (toff<<2)+minorplace;
					//int a = 0;
					if(toff < sawtable[noteval][partCache->pulsewidth]) {
						while(offsetpos>waveformsize[2][noteval]) {
							offsetpos-=waveformsize[2][noteval];
						}
						ptemp = waveforms[2][noteval][offsetpos];
					} else {
						while(offsetpos>waveformsize[3][noteval]) {
							offsetpos-=waveformsize[3][noteval];
						}
						ptemp = waveforms[3][noteval][offsetpos];
					}
					ptemp = ptemp *4;
					
					// ptemp = (int)(sin((double)toff / 100.0) * 100.0);
					//ptemp = pa;

					// This is the correct way
					// Seems slow to me (though bandlimited) -- doesn't seem to
					// sound any better though
					/*
					hdivis = divis >> 1;
					int divmark = smalldivtable[noteval];
					//int pw = (tcache->pulsewidth * pulsemod[filtval]) >> 8;
					
					
					ofs = toff % (hdivis);

					ofs3 = toff + ((divmark*pulsetable[tcache->pulsewidth])>>16);
					ofs3 = ofs3 % (hdivis);
					
					pa = waveforms[0][noteval][ofs];
					pb = waveforms[1][noteval][ofs3];
					ptemp = ((pa+pb) * waveforms[3][noteval][toff]) / WGAMP;
					ptemp = ptemp *4;
					*/

					

				}
				
				//Very exact filter
				//ptemp[t] = (int)iir_filter((float)ptemp[t],&partCache->history[t],filtcoeff[filtval][tcache->filtEnv.resonance]);
				if(filtval>((FILTERGRAN*15)/16)) filtval = ((FILTERGRAN*15)/16);
				ptemp = (Bit32s)(usefilter)((float)ptemp,&partCache->history[0],filtcoeff[filtval][(int)tcache->filtEnv.resonance], tcache->filtEnv.resonance);
			} else ptemp = 0;

			//ptemp[t] = Moog1(ptemp[t],&partCache->history[t],(float)filtval/8192.0,tcache->filtEnv.resonance);
			//ptemp[t] = Moog2(ptemp[t],&partCache->history[t],(float)filtval/8192.0,tcache->filtEnv.resonance);
			//ptemp[t] = simpleLowpass(ptemp[t],&partCache->history[t],(float)filtval/8192.0,tcache->filtEnv.resonance);

			// Use this to mute analogue synthesis
			// ptemp = 0;


		}
		
		// Build delta for position of next sample
                /*
		delta = (delta * tcache->fineshift)>>12;
		delta = (delta * pdep)>>12;
		delta = (delta * lfoat)>>12;
		if(tcache->useBender) delta = (delta * *tmppoly->bendptr)>>12;
                */

		// Fix delta code
		__int64 tdelta = (__int64)delta;
		tdelta = (tdelta * tcache->fineshift)>>12;
		tdelta = (tdelta * pdep)>>12;
		tdelta = (tdelta * lfoat)>>12;
		if(tcache->useBender) tdelta = (tdelta * *tmppoly->bendptr)>>12;

		// Add calculated delta to our waveform offset
		pOff->pcmabs+=(int)tdelta;

		// Put volume envelope over generated sample
		ptemp = (ptemp * ampval) >> 9;
		ptemp = (ptemp * *tmppoly->volumeptr) >> 7;
		
		partCache->envs[AMPENV].envpos++;
		partCache->envs[PITCHENV].envpos++;
		partCache->envs[FILTENV].envpos++;
	
		*partialBuf++ = (Bit16s)ptemp;
	}


}

INLINE void CPartialMT32::mixBuffers(Bit16s * buf1, Bit16s *buf2, int len) {
	// Early exit if no need to mix
	if(tibrePair==NULL) return;

#if USE_MMX == 0
	int i;
	for(i=0;i<len;i++) {
		Bit32s tmp1 = buf1[i];
		Bit32s tmp2 = buf2[i];
		tmp1 += tmp2;
		buf1[i] = (Bit16s)tmp1;
	}
#else
	len = (len>>2)+4;
#ifdef I_ASM	
	__asm {
		mov ecx, len
		mov esi, buf1
		mov edi, buf2

mixloop1:
		movq mm1, [edi]
		movq mm2, [esi]
		paddw mm1,mm2
		movq [esi],mm1
		add edi,8
		add esi,8

		dec ecx
		cmp ecx,0
		jg mixloop1
		emms
	}
#else
	atti386_mixBuffers(buf1, buf2, len);
#endif	
#endif
}

INLINE void CPartialMT32::mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len) {
#if USE_MMX != 2
	int i;
	for(i=0;i<len;i++) {
		float a, b;
		a = ((float)buf1[i]) / 8192.0;
		b = ((float)buf2[i]) / 8192.0;
		a = (a * b) + a;
		if(a>1.0) a = 1.0;
		if(a<-1.0) a = -1.0;
		buf1[i] = (Bit16s)(a * 8192.0);

		//buf1[i] = (Bit16s)(((Bit32s)buf1[i] * (Bit32s)buf2[i]) >> 10) + buf1[i];
        }
#else
	len = (len>>2)+4;
#ifdef I_ASM	
	__asm {
		mov ecx, len
		mov esi, buf1
		mov edi, buf2

mixloop2:
		movq mm1, [esi]
		movq mm2, [edi]
		movq mm3, mm1
		pmulhw mm1, mm2
		paddw mm1,mm3
		movq [esi],mm1
		add edi,8
		add esi,8

		dec ecx
		cmp ecx,0
		jg mixloop2
		emms
	}
#else
	atti386_mixBuffersRingMix(buf1, buf2, len);
#endif	
#endif
}

INLINE void CPartialMT32::mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len) {
#if USE_MMX != 2
	int i;
	for(i=0;i<len;i++) {
		float a, b;
		a = ((float)buf1[i]) / 8192.0;
		b = ((float)buf2[i]) / 8192.0;
		a *= b;
		if(a>1.0) a = 1.0;
		if(a<-1.0) a = -1.0;
		buf1[i] = (Bit16s)(a * 8192.0);
		//buf1[i] = (Bit16s)(((Bit32s)buf1[i] * (Bit32s)buf2[i]) >> 10);
	}
#else
	len = (len>>2)+4;
#ifdef I_ASM		
	__asm {
		mov ecx, len
		mov esi, buf1
		mov edi, buf2

mixloop3:
		movq mm1, [esi]
		movq mm2, [edi]
		pmulhw mm1, mm2
		movq [esi],mm1
		add edi,8
		add esi,8

		dec ecx
		cmp ecx,0
		jg mixloop3
		emms
	}
#else
	atti386_mixBuffersRing(buf1, buf2, len);
#endif	
#endif
}

INLINE void CPartialMT32::mixBuffersStereo(Bit16s *buf1, Bit16s *buf2, Bit16s *outBuf, int len) {
	int i,m;
	m=0;
	for(i=0;i<len;i++) {
		*outBuf++ = (*buf1);
		buf1++;
		*outBuf++ = (*buf2);
		buf2++;
	}

}

bool CPartialMT32::produceOutput(Bit16s * partialBuf, long length) {
	if (!isActive) return false;
	if (alreadyOutputed) return false;
	int i;

	//alreadyOutputed = true;

	memset(&pairBuffer[0],0,length*4);
	memset(&myBuffer[0],0,length*4);
	// Check for dependant partial
	if(tibrePair != NULL) {
		if ((tibrePair->ownerChan == this->ownerChan) && (!tibrePair->alreadyOutputed)) {			
			tibrePair->generateSamples(pairBuffer,length);
		}
	} else {
		if((useMix!=0) && (useMix != 3)){
			// Generate noise for parialless ring mix
			for(i=0;i<length;i++) pairBuffer[i] = smallnoise[i] << 2;
		}
	}

	generateSamples(myBuffer, length);
/*	FILE *fo = fopen("/tmp/samp.raw", "a");
	for(i = 0; i < length; i++)
		fwrite(myBuffer + i, 1, 2, fo);
	fclose(fo);
*/			
	Bit16s * p1buf, * p2buf;

	if((partNum==0) || ((partNum==1) && (tibrePair==NULL))) {
		p1buf = &myBuffer[0];
		p2buf = &pairBuffer[0];
	} else {
		p2buf = &myBuffer[0];
		p1buf = &pairBuffer[0];
	}
	
//	LOG_MSG("useMix: %d", useMix);
	
	switch(useMix) {
		case 0:
			// Standard sound mix
			mixBuffers(p1buf, p2buf, length);
			break;
		case 1:
			// Ring modulation with sound mix
			mixBuffersRingMix(p1buf, p2buf, length);
			break;
		case 2:
			// Ring modulation alone
			mixBuffersRing(p1buf, p2buf, length);
			break;
		case 3:
			// Stereo mixing.  One partial to one channel, one to another.
			mixBuffersStereo(p1buf, p2buf, partialBuf, length);
			return true;
			break;
		default:
			mixBuffers(p1buf, p2buf, length);
			break;
	}
	
	
	int  m;
	m = 0;	
	Bit16s leftvol, rightvol;
	if (!tmppoly->isRy) {
		leftvol = tmppoly->pansetptr->leftvol;
		rightvol = tmppoly->pansetptr->rightvol;
	} else {
		leftvol = (Bit16s)drumPan[tmppoly->pcmnum][0];
		rightvol = (Bit16s)drumPan[tmppoly->pcmnum][1];
	}

#if USE_MMX == 0
	for(i=0;i<length;i++) {
		partialBuf[m] = (Bit16s)(((Bit32s)p1buf[i] * (Bit32s)leftvol) >> 16);
		m++;
		partialBuf[m] = (Bit16s)(((Bit32s)p1buf[i] * (Bit32s)rightvol) >> 16);
		m++;
	}
#else
	long quadlen = (length >> 1)+2;
#ifdef I_ASM
	__asm {
		mov ecx,quadlen
		mov ax, leftvol
		shl eax,16
		mov ax, rightvol
		movd mm1, eax
		movd mm2, eax
		psllq mm1, 32
		por mm1, mm2
		mov edi, partialBuf
		mov esi, p1buf
mmxloop1:
		mov bx, [esi]
		add esi,2
		mov dx, [esi]
		add esi,2

		mov ax, dx
		shl eax, 16
		mov ax, dx
		movd mm2,eax
		psllq mm2, 32
		mov ax, bx
		shl eax, 16
		mov ax, bx
		movd mm3,eax
		por mm2,mm3

		pmulhw mm2, mm1
		movq [edi], mm2
		add edi, 8

		dec ecx
		cmp ecx,0
		jg mmxloop1
		emms
	}
#else
	atti386_PartProductOutput(quadlen, leftvol, rightvol, partialBuf, p1buf);
#endif	
#endif
	
	return true;
}

--- NEW FILE: partial.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 The ScummVM project
 * Based on Tristan's conversion of Canadacow's code
 *
 * 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/backends/midi/mt32/partial.h,v 1.1 2004/10/21 22:37:30 sev Exp $
 *
 */

#ifndef __CPARTIALMT32_H__
#define __CPARTIALMT32_H__

#include "backends/midi/mt32/structures.h"

// Class definition of MT-32 partials.  32 in all.
class CPartialMT32 {
private:
	int useMix;
	int partNum;

	int pN;




	Bit16s myBuffer[2048];
	// For temporary output of paired buffer
	Bit16s pairBuffer[2048];

	void mixBuffers(Bit16s * buf1, Bit16s * buf2, int len);
	void mixBuffersRingMix(Bit16s * buf1, Bit16s * buf2, int len);
	void mixBuffersRing(Bit16s * buf1, Bit16s * buf2, int len);
	void mixBuffersStereo(Bit16s * buf1, Bit16s * buf2, Bit16s * outBuf, int len);


public:
	patchCache *tcache;
	patchCache cachebackup[4];

	//FILE *fp;
	//FILE *fp2;

	dpoly::partialStatus *partCache;

	CPartialMT32 *tibrePair;
	bool isActive;
	bool alreadyOutputed;
	int ownerChan;
	Bit64s age;
	int timbreNum;
	dpoly *tmppoly;

	CPartialMT32(int partialNum) {

		isActive = false;		
		pN = partialNum;

		/*
		sprintf(buffer, "partial%d.raw",pN);
		fp = fopen(buffer,"wb");

		sprintf(buffer, "partial%dx.raw",pN);
		fp2 = fopen(buffer,"wb");
		*/

		
	};
	
	void startPartial(dpoly *usePoly, patchCache *useCache, dpoly::partialStatus * usePart, CPartialMT32 * pairPart, int mixType, int num, int ownChan, int timNum) {

		//LOG_MSG("Starting partial %d for %d", num, ownChan);
		tmppoly = usePoly;
		tcache = useCache;
		partCache = usePart;
		tibrePair = pairPart;
		isActive = true;
		useMix = mixType;
		partNum = num;
		age = 0;
		ownerChan = ownChan;
		alreadyOutputed = false;
		timbreNum = timNum;
		memset(usePart->history,0,sizeof(usePart->history));

	}

	void stopPartial(void) { isActive = false; }

	
	// Returns true only if data written to buffer
	// This function (unline the one below it) returns processed stereo samples
	// made from combining this single partial with its pair, if it has one.
	bool produceOutput(Bit16s * partialBuf, long length);

	// This function produces mono sample output of the specific partial
	void generateSamples(Bit16s * partialBuf, long length);

};


#endif


--- NEW FILE: structures.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 The ScummVM project
 * Based on Tristan's conversion of Canadacow's code
 *
 * 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/backends/midi/mt32/structures.h,v 1.1 2004/10/21 22:37:30 sev Exp $
 *
 */

#if !defined __MT32STRUCTURES_H__
#define __MT32STRUCTURES_H__

#include "stdafx.h"
#include "common/scummsys.h"

#if defined(_MSC_VER)
typedef unsigned __int64 Bit64u;
typedef   signed __int64 Bit64s;
#else
typedef unsigned long long Bit64u;
typedef   signed long long Bit64s;
#endif
typedef unsigned int       Bit32u;
typedef   signed int       Bit32s;
typedef unsigned short int Bit16u;
typedef   signed short int Bit16s;
typedef unsigned char      Bit8u;
typedef   signed char      Bit8s;

// The occurences of __int64 should be changed to Bit64s
#define __int64  Bit64u

#define INLINE


static inline void LOG_MSG(char *fmt, ...)
{
	va_list ap;
	
	va_start(ap, fmt);
	vfprintf(stdout, fmt, ap);
	va_end(ap);
	fprintf(stdout, "\n");
	fflush(stdout);
}

#if defined(WIN32) && !(defined(__CYGWIN__) || defined(__MINGW__))

#define ALIGN_PACKED

#else

//#define ALIGN_PACKED __attribute__ ((__packed__))
#define ALIGN_PACKED __attribute__ ((aligned (1)))

#ifdef HAVE_X86
#define eflag(value) __asm__ __volatile__("pushfl \n popfl \n" : : "a"(value))
#define cpuid_flag  (1 << 21)

static inline bool atti386_DetectCPUID()
{
	unsigned int result;
	
	/* is there a cpuid */
	result = cpuid_flag; /* set test */
	eflag(result);
	if (!(result & cpuid_flag))
		return false;
	
	result = 0; /* clear test */
	eflag(result);
	if (result & cpuid_flag)
		return false;
	
	return true;
}

static inline bool atti386_DetectSIMD()
{
	unsigned int result;
	
	if (atti386_DetectCPUID() == false)
		return false;
	
	/* check cpuid */
	__asm__ __volatile__(
			       "movl   $1, %%eax        \n" \
			       "cpuid		 	\n" \
                               "movl   %%edx, %0        \n" \
			     : "=r"(result) : : "eax", "ebx", "ecx", "edx");
		
	if (result & (1 << 25))
			return true;
	
	return false;
}

static inline bool atti386_Detect3DNow()
{
	unsigned int result;
	
	if (atti386_DetectCPUID() == false)
		return false;
		
	/* get cpuid */
	__asm__ __volatile__(
			       "movl   $0x80000001, %%eax \n" \
			       "cpuid		 	  \n" \
                               "movl   %%edx, %0          \n" \
			     : "=r"(result) : : "eax", "ebx", "ecx", "edx");
		
	if (result & 0x80000000)
			return true;
	
	return false;
}


static inline float atti386_iir_filter_sse(float *output, float *hist1_ptr, float *coef_ptr)
{
	
	__asm__  __volatile__ (
		"pushl %1                       \n" \
		"pushl %2                       \n" \
                "movss  0(%0), %%xmm1	        \n" \
                "movups 0(%1), %%xmm2	        \n" \
		"movlps 0(%2), %%xmm3	        \n" \
                "                               \n" \
		"shufps $0x44, %%xmm3, %%xmm3	\n" \
		"	       	       		\n" \
		"mulps %%xmm3, %%xmm2		\n" \
		"      	       			\n" \
		"subss  %%xmm2, %%xmm1		\n" \
		"shufps $0x39,  %%xmm2, %%xmm2	\n" \
		"subss  %%xmm2, %%xmm1		\n" \
		"				\n" \
		"movss  %%xmm1, 0(%2)	        \n" \
		"      	       			\n" \
		"shufps $0x39,  %%xmm2, %%xmm2	\n" \
		"addss  %%xmm2, %%xmm1		\n" \
		"				\n" \
		"shufps $0x39,  %%xmm2, %%xmm2	\n" \
		"addss  %%xmm2, %%xmm1		\n" \
		"				\n" \
		"movss  %%xmm3, 4(%2)	        \n" \
		"				\n" \
		"addl $16, %1			\n" \
		"addl $8, %2			\n" \
		"     	  			\n" \
		"movups 0(%1), %%xmm2	        \n" \
		"		  		\n" \
		"movlps 0(%2), %%xmm3	        \n" \
		"shufps $0x44, %%xmm3, %%xmm3	\n" \
		"	       	       		\n" \
		"mulps %%xmm3, %%xmm2		\n" \
		"      	       			\n" \
		"subss  %%xmm2, %%xmm1		\n" \
		"shufps $0x39,  %%xmm2, %%xmm2	\n" \
		"subss  %%xmm2, %%xmm1		\n" \
		"				\n" \
		"movss %%xmm1, 0(%2)		\n" \
		"      	       			\n" \
		"shufps $0x39, %%xmm2, %%xmm2	\n" \
		"addss %%xmm2, %%xmm1  		\n" \
		"      	       			\n" \
		"shufps $0x39, %%xmm2, %%xmm2	\n" \
		"addss %%xmm2, %%xmm1  		\n" \
		"      	       			\n" \
		"movss %%xmm3, 4(%2)		\n" \
		"movss %%xmm1, 0(%0)		\n" \
		"popl %2                        \n" \
		"popl %1                        \n" \
		: : "r"(output), "r"(coef_ptr), "r"(hist1_ptr)
		: "xmm1", "xmm2", "xmm3", "memory");
		
    return(*output);
}

static inline float atti386_iir_filter_3DNow(float output, float *hist1_ptr, float *coef_ptr)
{
	float tmp;
	
	__asm__  __volatile__ (
		"movq %0, %%mm1		 \n" \
		"	       		 \n" \
		"movl  %1, %%ebx	 \n" \
		"movq 0(%%ebx), %%mm2	 \n" \
		"     			 \n" \
		"movl %2, %%eax;	 \n" \
		"movq 0(%%eax), %%mm3	 \n" \
		"			 \n" \
		"pfmul %%mm3, %%mm2	 \n" \
		"pfsub %%mm2, %%mm1	 \n" \
		"	       		 \n" \
		"psrlq $32, %%mm2	 \n" \
		"pfsub %%mm2, %%mm1	 \n" \
		"      	      		 \n" \
		"movd %%mm1, %3		 \n" \
		"     	     		 \n" \
		"addl  $8, %%ebx	 \n" \
		"movq 0(%%ebx), %%mm2	 \n" \
		"movq 0(%%eax), %%mm3	 \n" \
		"     			 \n" \
		"pfmul %%mm3, %%mm2	 \n" \
		"pfadd %%mm2, %%mm1	 \n" \
		"      	      		 \n" \
		"psrlq $32, %%mm2	 \n" \
		"pfadd %%mm2, %%mm1	 \n" \
		"      	      		 \n" \
		"pushl %3		 \n" \
		"popl 0(%%eax)		 \n" \
		"     			 \n" \
		"movd %%mm3, 4(%%eax)	 \n" \
		"     	     		 \n" \
		"addl $8, %%ebx		 \n" \
		"addl $8, %%eax		 \n" \
		"     	  		 \n" \
		"movq 0(%%ebx), %%mm2	 \n" \
		"movq 0(%%eax), %%mm3	 \n" \
		"     			 \n" \
		"pfmul %%mm3, %%mm2	 \n" \
		"pfsub %%mm2, %%mm1	 \n" \
		"      	      		 \n" \
		"psrlq $32, %%mm2	 \n" \
		"pfsub %%mm2, %%mm1	 \n" \
		"      	      		 \n" \
		"movd %%mm1, %3		 \n" \
		"     	     		 \n" \
		"addl $8, %%ebx		 \n" \
		"movq 0(%%ebx), %%mm2	 \n" \
		"movq 0(%%eax), %%mm3	 \n" \
		"     			 \n" \
		"pfmul %%mm3, %%mm2	 \n" \
		"pfadd %%mm2, %%mm1	 \n" \
		"      	      		 \n" \
		"psrlq $32, %%mm2	 \n" \
		"pfadd %%mm2, %%mm1	 \n" \
		"      	      		 \n" \
		"pushl %3		 \n" \
		"popl 0(%%eax)		 \n" \
		"movd %%mm3, 4(%%eax)	 \n" \
		"     	     		 \n" \
		"movd %%mm1, %0		 \n" \
		"femms	     		 \n" \
                               : "=m"(output) : "g"(coef_ptr), "g"(hist1_ptr), "m"(tmp)
			       : "eax", "ebx", "mm1", "mm2", "mm3", "memory");
	
	return(output);
}

static inline float atti386_iir_filter_3dnow(float input,float *hist1_ptr, float *coef_ptr, int revLevel)
{
	return 0;
}

static inline void atti386_produceOutput1(int tmplen, Bit16s myvolume, Bit16s *useBuf, Bit16s *snd)
{
	__asm__ __volatile__(
				"movl %0,  %%ecx	\n" \
				"movw %1,  %%ax		\n" \
				"shll $16, %%eax	\n" \
				"movw %1,  %%ax		\n" \
				"movd %%eax, %%mm3	\n" \
				"movd %%eax, %%mm2	\n" \
				"psllq $32, %%mm3	\n" \
				"por %%mm2, %%mm3	\n" \
				"movl %2, %%esi		\n" \
				"movl %3, %%edi		\n" \
			        "1:   	  		\n" \
				"movq 0(%%esi), %%mm1	\n" \
				"movq 0(%%edi), %%mm2	\n" \
				"pmulhw %%mm3, %%mm1	\n" \
				"paddw %%mm2, %%mm1	\n" \
				"movq %%mm1, 0(%%edi)	\n" \
				" 			\n" \
				"addl $8, %%esi		\n" \
				"addl $8, %%edi		\n" \
				"     	  		\n" \
				"decl %%ecx		\n" \
				"cmpl $0, %%ecx		\n" \
				"jg   1b  		\n" \
				"emms		 	\n" \
			     : : "g"(tmplen), "g"(myvolume), "g"(useBuf), "g"(snd)
			     : "eax", "ecx", "edi", "esi", "mm1", "mm2", "mm3", "memory");
}

// FIXME: This is buggy
static inline void atti386_produceOutput2(Bit32u len, Bit16s *snd, float *sndbufl, float *sndbufr, float *multFactor)
{
	__asm__ __volatile__(
			        "movl  %4, %%ecx		\n" \
				"shrl  $1, %%ecx		\n" \
				"addl  $4, %%ecx		\n" \
				"pushl %%ecx			\n" \
				"     				\n" \
				"movl %0, %%esi			\n" \
				"movups 0(%%esi), %%xmm1	\n" \
				" 		  		\n" \
				"movl %1, %%esi			\n" \
				"movl %2, %%edi			\n" \
				"1:   	  			\n" \
				"xorl %%eax, %%eax		\n" \
				"movw 0(%1), %%ax		\n" \
				"cwde 	    			\n" \
				"incl %1			\n" \
				"incl %1			\n" \
				"movd  %%eax, %%mm1		\n" \
				"psrlq $32, %%mm1		\n" \
				"movw 0(%1), %%ax		\n" \
				"incl %1    			\n" \
				"incl %1			\n" \
				"movd %%eax, %%mm2		\n" \
				"por %%mm2, %%mm1		\n" \
				"    	    			\n" \
				"decl %%ecx			\n" \
				"jnz 1b				\n" \
				"    				\n" \
				"popl %%ecx			\n" \
				"movl %1, %%esi			\n" \
				"movl %3, %%edi			\n" \
				"incl %%esi			\n" \
				"2:   				\n" \
				"decl %%ecx			\n" \
				"jnz 2b				\n" \
			     : : "g"(multFactor), "r"(snd), "g"(sndbufl), "g"(sndbufr), "g"(len)
			     : "eax", "ecx", "edi", "esi", "mm1", "mm2", "xmm1", "memory");
}

static inline void atti386_mixBuffers(Bit16s * buf1, Bit16s *buf2, int len)
{
	__asm__ __volatile__(
			     "movl %0, %%ecx       \n" \
			     "movl %1, %%esi       \n" \
			     "movl %2, %%edi       \n" \
			     "1:                   \n" \
			     "movq 0(%%edi), %%mm1 \n" \
			     "movq 0(%%esi), %%mm2 \n" \
			     "paddw %%mm2, %%mm1   \n" \
			     "movq %%mm1, 0(%%esi) \n" \
			     "addl $8, %%edi       \n" \
			     "addl $8, %%esi       \n" \
			     "decl %%ecx           \n" \
			     "cmpl $0, %%ecx       \n" \
			     "jg   1b              \n" \
			     "emms                 \n" \
			     : : "g"(len), "g"(buf1), "g"(buf2)
			     : "ecx", "edi", "esi", "mm1", "mm2", "memory");
}

static inline void atti386_mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len)
{		
	__asm__ __volatile__(
			     "movl %0, %%ecx       \n" \
			     "movl %1, %%esi       \n" \
			     "movl %2, %%edi       \n" \
			     "1:                   \n" \
			     "movq 0(%%esi), %%mm1 \n" \
			     "movq 0(%%edi), %%mm2 \n" \
			     "movq %%mm1, %%mm3    \n" \
			     "pmulhw %%mm2, %%mm1  \n" \
			     "paddw %%mm3, %%mm1   \n" \
			     "movq %%mm1, 0(%%esi) \n" \
			     "addl $8, %%edi       \n" \
			     "addl $8, %%esi       \n" \
			     "decl %%ecx           \n" \
			     "cmpl $0, %%ecx       \n" \
			     "jg   1b              \n" \
			     "emms                 \n" \
			     : : "g"(len), "g"(buf1), "g"(buf2)
			     : "ecx", "edi", "esi", "mm1", "mm2", "mm3", "memory");	
}

static inline void atti386_mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len)
{
	__asm__ __volatile__(
			     "movl %0, %%ecx       \n" \
			     "movl %1, %%esi       \n" \
			     "movl %2, %%edi       \n" \
			     "1:                   \n" \
			     "movq 0(%%esi), %%mm1 \n" \
			     "movq 0(%%edi), %%mm2 \n" \
			     "pmulhw %%mm2, %%mm1  \n" \
			     "movq %%mm1, 0(%%esi) \n" \
			     "addl $8, %%edi       \n" \
			     "addl $8, %%esi       \n" \
			     "decl %%ecx           \n" \
			     "cmpl $0, %%ecx       \n" \
			     "jg   1b              \n" \
			     "emms                 \n" \
			     : : "g"(len), "g"(buf1), "g"(buf2)
			     : "ecx", "edi", "esi", "mm1", "mm2", "memory");
}

static inline void atti386_PartProductOutput(int quadlen, Bit16s leftvol, Bit16s rightvol,
					     Bit16s *partialBuf, Bit16s *p1buf)
{
	__asm__ __volatile__(
			     "movl %0, %%ecx       \n"  \
			     "movw %1, %%ax        \n"  \
			     "shll $16, %%eax      \n"  \
			     "movw %2, %%ax        \n"  \
			     "movd %%eax, %%mm1    \n"  \
			     "movd %%eax, %%mm2    \n"  \
			     "psllq $32, %%mm1     \n"  \
			     "por  %%mm2, %%mm1    \n"  \
			     "movl %3, %%edi       \n"  \
			     "movl %4, %%esi       \n"  \
			     "1:                   \n"  \
			     "movw 0(%%esi), %%bx  \n"  \
			     "addl $2, %%esi       \n"  \
			     "movw 0(%%esi), %%dx  \n"  \
			     "addl $2, %%esi       \n"  \
			     ""                         \
			     "movw %%dx, %%ax      \n"  \
			     "shll $16, %%eax      \n"  \
			     "movw %%dx, %%ax      \n"  \
			     "movd %%eax, %%mm2    \n"  \
			     "psllq $32, %%mm2     \n"  \
			     "movw %%bx, %%ax      \n"  \
			     "shll $16, %%eax      \n"  \
			     "movw %%bx, %%ax      \n"  \
			     "movd %%eax, %%mm3    \n"  \
			     "por  %%mm3, %%mm2    \n"  \
			     ""    	     	      	\
			     "pmulhw %%mm1, %%mm2  \n"  \
			     "movq %%mm2, 0(%%edi) \n"  \
			     "addl $8, %%edi	   \n"  \
			     ""    	  	      	\
			     "decl %%ecx	   \n"  \
			     "cmpl $0, %%ecx	   \n"  \
			     "jg 1b	  	   \n"  \
			     "emms                 \n"  \
			     :  :"g"(quadlen), "g"(leftvol), "g"(rightvol), "g"(partialBuf), "g"(p1buf)
			     : "eax", "ebx", "ecx", "edx", "edi", "esi", "mm1", "mm2", "mm3", "memory");	
}
#endif

#endif

extern bool enabled3DNow;
extern bool enabledSSE;

#pragma pack(1)
struct timbreParam {
	struct commonParam {
		char name[10];
		char pstruct12;  // 1&2  0-12 (1-13)
		char pstruct34;  // #3&4  0-12 (1-13)
		char pmute;  // 0-15 (0000-1111)
		char nosustain; // 0-1(Normal, No sustain)
	} ALIGN_PACKED common;

	struct partialParam {
		struct wgParam {
			char coarse;  // 0-96 (C1,C#1-C9)
			char fine;  // 0-100 (-50 - +50)
			char keyfollow;  // 0-16 (-1,-1/2,0,1,1/8,1/4,3/8,1/2,5/8,3/4,7/8,1,5/4,3/2,2.s1,s2)
			char bender;  // 0,1 (ON/OFF)
			char waveform; //  0-1 (SQU/SAW)
			char pcmwave; // 0-127 (1-128)
			char pulsewid; // 0-100
			char pwvelo; // 0-14 (-7 - +7)
		} ALIGN_PACKED wg;

		struct envParam {
			char depth; // 0-10
			char sensitivity; // 1-100
			char timekeyfollow; // 0-4
			char time[4]; // 1-100
			char level[5]; // 1-100 (-50 - +50)
		} ALIGN_PACKED env;
		
		struct lfoParam {
			char rate; // 0-100
			char depth; // 0-100
			char modsense; // 0-100
		} ALIGN_PACKED lfo;

		struct tvfParam {
			char cutoff; // 0-100
			char resonance; // 0-30
			char keyfollow; // 0-16 (-1,-1/2,1/4,0,1,1/8,1/4,3/8,1/2,5/8,3/2,7/8,1,5/4,3/2,2,s1,s2)
			char biaspoint; // 0-127 (<1A-<7C >1A-7C)
			char biaslevel; // 0-14 (-7 - +7)
			char envdepth; // 0-100
			char envsense; // 0-100
			char envdkf; // DEPTH KEY FOLL0W 0-4
			char envtkf; // TIME KEY FOLLOW 0-4
			char envtime[5]; // 1-100
			char envlevel[4]; // 1-100
		} ALIGN_PACKED tvf;
		
		struct tvaParam {
			char level; // 0-100
			char velosens; // 0-100
			char biaspoint1; // 0-127 (<1A-<7C >1A-7C)
			char biaslevel1; // 0-12 (-12 - 0)
			char biaspoint2; // 0-127 (<1A-<7C >1A-7C)
			char biaslevel2; // 0-12 (-12 - 0)
			char envtkf; // TIME KEY FOLLOW 0-4
			char envvkf; // VELOS KEY FOLL0W 0-4
			char envtime[5]; // 1-100
			char envlevel[4]; // 1-100
		} ALIGN_PACKED tva;
			
	} ALIGN_PACKED partial[4];
	//char dummy[20];
} ALIGN_PACKED;

struct memParams {
	struct patchTemp {
		char timbreGroup; // TIMBRE GROUP  0-3 (group A, group B, Memory, Rhythm)
		char timbreNum; // TIMBRE NUMBER 0-63
		char keyShift; // KEY SHIFT 0-48 (-24 - +24)
		char fineTune; // FINE TUNE 0-100 (-50 - +50)
		char benderRange; // BENDER RANGE 0-24
		char assignMode;  // ASSIGN MODE 0-3 (POLY1, POLY2, POLY3, POLY4)
		char reverbSwitch;  // REVERB SWITCH 0-1 (OFF,ON)
		char dummy; // (DUMMY)
		char outlevel; // OUTPUT LEVEL 0-100
		char panpot; // PANPOT 0-14 (R-L)
		char dummyv[6];
	} ALIGN_PACKED tmpSettings[8];
	struct ryhTemp {
		char timbre; // TIMBRE  0-94 (M1-M64,R1-30,OFF)
		char outlevel; // OUTPUT LEVEL 0-100
		char panpot; // PANPOT 0-14 (R-L)
		char reverbSwitch;  // REVERB SWITCH 0-1 (OFF,ON)
	} ALIGN_PACKED rhySettings[64];

	timbreParam timTemp[8];

	struct patchArea {
		char timbreGroup; // TIMBRE GROUP  0-3 (group A, group B, Memory, Rhythm)
		char timbreNum; // TIMBRE NUMBER 0-63
		char keyShift; // KEY SHIFT 0-48 (-24 - +24)
		char fineTune; // FINE TUNE 0-100 (-50 - +50)
		char benderRange; // BENDER RANGE 0-24
		char assignMode;  // ASSIGN MODE 0-3 (POLY1, POLY2, POLY3, POLY4)
		char reverbSwitch;  // REVERB SWITCH 0-1 (OFF,ON)
		char dummy; // (DUMMY)
	} ALIGN_PACKED pSettings[128];
	timbreParam patch[192];
	struct systemArea {
		char masterTune; // MASTER TUNE 0-127 432.1-457.6Hz
		char reverbMode; // REVERB MODE 0-3 (room, hall, plate, tap delay)
		char reverbTime; // REVERB TIME 0-7 (1-8)
		char reverbLevel; // REVERB LEVEL 0-7 (1-8)
		char reserveSettings[9]; // PARTIAL RESERVE (PART 1) 0-32
		char chanAssign[9]; // MIDI CHANNEL (PART1) 0-16 (1-16,OFF)
		char masterVol; // MASTER VOLUME 0-100
	} ALIGN_PACKED system;

} ALIGN_PACKED;

struct memBanks {
	char pTemp[8][sizeof(memParams::patchTemp)];
	char rTemp[64][sizeof(memParams::ryhTemp)];
	char tTemp[8][sizeof(timbreParam)];
	char patchmemory[128][sizeof(memParams::patchArea)];
	char patchbanks[128][sizeof(timbreParam)];
	char timbrebanks[64][sizeof(timbreParam)];
	char systemBank[sizeof(memParams::systemArea)];
} ALIGN_PACKED;

struct memAbsolute {
	char mt32memory[sizeof(memBanks)];
} ALIGN_PACKED;

#pragma pack()

struct partialFormat {
	Bit32u addr;
	Bit16u len;
	bool loop;
	float tune;
	Bit32s ampval;
};

struct partialTable {
	Bit32u addr;
	Bit32u len;
	Bit32u pcmnum;
	Bit32s ampval;
	bool loop;
	Bit32s aggSound; // This variable is for the last 9 PCM samples, which are actually loop combinations
};



union soundaddr {
	Bit32u pcmabs;
	struct offsets {
#if defined(SCUMM_LITTLE_ENDIAN)
		Bit16u pcmoffset;
		Bit16u pcmplace;
#else
		Bit16u pcmplace;
		Bit16u pcmoffset;
#endif
	} pcmoffs;
};


struct volset {
	Bit16s leftvol;
	Bit16s rightvol;
	Bit16s leftvol2;
	Bit16s rightvol2;
};

struct patchCache {
	int rawPCM;
	partialTable convPCM;

	bool playPartial;
	bool usePartial;
	bool PCMPartial;
	char waveform;
	int pulsewidth;
	int pwsens;
	int pitchshift;
	int fineshift;
	bool sustain;

	int lfodepth;
	int lforate;
	Bit32u lfoperiod;
	int modsense;

	int keydir;
	int pitchkeyfollow;
	int pitchkeydir;

	int filtkeyfollow;

	int tvfbias;
	int tvfblevel;
	int tvfdir;

	int ampbias[2];
	int ampblevel[2];
	int ampdir[2];

	int ampdepth;
	int ampenvdir;
	int amplevel;
	int tvfdepth;

	int prevsample;

	bool useBender;

	timbreParam::partialParam::envParam pitchEnv;
	timbreParam::partialParam::tvaParam ampEnv;
	timbreParam::partialParam::tvfParam filtEnv;

	Bit32s ampsustain;
	Bit32s pitchsustain;
	Bit32s filtsustain;

	Bit32u partCount;

	Bit8u padding[64]; //Used to pad the patch cache to 4096 bytes.  This replaces an imul with a shl 12

};

struct dpoly {
	bool isPlaying;
	bool isDecay;
	bool isActive;

	bool partActive[4];

	bool isRy;
	Bit32u *bendptr;
	Bit32u drumbend;
	Bit32s *volumeptr;
	volset *pansetptr;

	int pcmnum;
	int freq;
	int freqnum;
	int vel;

	Bit32u partCount;

	soundaddr pcmoff;
	Bit32u pcmdelta;


	struct partialStatus {
		// Note played on keyboard
		int noteval;
		// Keyfollowed note values
		int keyedval;

		// Keyfollowed filter values
		int realval;
		int filtval;
		// Keyfollowed filter w/o table
		int filtnoval;
		int pulsewidth;

		struct envstatus {
			Bit32s envpos;
			Bit32s envstat;
			Bit32s envbase;
			Bit32s envdist;
			Bit32s envsize;

			bool sustaining;
			bool decaying;
			bool notdecayed;
			Bit32u decay;
			Bit32s prevlevel;

			Bit32s counter;
			Bit32s count;

		} envs[4];

		Bit32u lfopos;
		soundaddr partialOff;
		soundaddr wgOff;

		Bit32u ampEnvCache;
		Bit32u pitchEnvCache;

		bool isDecayed;
		bool PCMDone;

		float history[32];

		float pastfilt;
		bool pitchsustain;
		bool playPartial;
		bool usePartial;

		int looppos;
		int partNum;

		patchCache *tcache;

		void * myPart;



	} pStatus[4];


	int chan;

	int origpat;
	int drumnum;
	
	int age;

	bool pedalhold;
	bool firstsamp;

	Bit32u P1Mix;
	Bit32u P2Mix;
	bool sustain;
};

#endif

--- NEW FILE: synth.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 The ScummVM project
 * Based on Tristan's conversion of Canadacow's code
 *
 * 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/backends/midi/mt32/synth.cpp,v 1.1 2004/10/21 22:37:30 sev Exp $
[...4525 lines suppressed...]
	if(samplepos>SETRATE*5) {
		samplepos = 0;
		int partUse[9];
		memset(partUse,0,sizeof(partUse));
		for(i=0;i<MAXPARTIALS;i++) {
			if(partTable[i]->isActive) partUse[partTable[i]->ownerChan]++;
		}
		//LOG_MSG("C1: %d C2: %d C3: %d C4 %d", partUse[0], partUse[1], partUse[2], partUse[3]);
		//LOG_MSG("C5: %d C6: %d C7: %d C8 %d", partUse[4], partUse[5], partUse[6], partUse[7]);
		//LOG_MSG("Rythmn: %d", partUse[8]);

	}

#endif


#endif


}

--- NEW FILE: synth.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 The ScummVM project
 * Based on Tristan's conversion of Canadacow's code
 *
 * 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/backends/midi/mt32/synth.h,v 1.1 2004/10/21 22:37:30 sev Exp $
 *
 */

#if !defined __CSYNTHMT32_H__
#define __CSYNTHMT32_H__

#ifdef HAVE_X86
#if defined(_MSC_VER)
#define USE_MMX 2
#define I_ASM
#else
#define USE_MMX 0
#undef I_ASM
#endif
#else
#define USE_MMX 0
#endif

extern const char *rom_path;

#define AMPENV 0
#define FILTENV 1
#define PITCHENV 2

// Filter setting
#define FILTER_FLOAT 1
#define FILTER_64BIT 0
#define FILTER_INT 0

#define FILTERGRAN 512

// Amplitude of waveform generator
#define WGAMP (7168)
//#define WGAMP (8192)

#include "backends/midi/mt32/structures.h"
#include "sound/mixer.h"

// Function that detects the availablity of SSE SIMD instructions
// On non-MSVC compilers it automatically returns FALSE as inline assembly is required
bool DetectSIMD();
// Function that detects the availablity of 3DNow instructions
// On non-MSVC compilers it automatically returns FALSE as inline assembly is required
bool Detect3DNow();

struct SynthProperties {
	// Sample rate to use in mixing
	int SampleRate;
	// Flag to activate reverb.  True = use reverb, False = no reverb
	bool UseReverb;
	// Flag True to use software set reverb settings, Flag False to set reverb settings in
	// following parameters
	bool UseDefault;
	// When not using the default settings, this specifies one of the 4 reverb types
	// 1 = Room 2 = Hall 3 = Plate 4 = Tap
	int RevType;
	// This specifies the delay time, from 0-7 (not sure of the actual MT-32's measurement)
	int RevTime;
	// This specifies the reverb level, from 0-7 (not sure of the actual MT-32's measurement)
	int RevLevel;
};

#ifndef BOOL
	#define BOOL bool
#endif
#ifndef TRUE
	#define TRUE true
#endif
#ifndef FALSE
	#define FALSE false
#endif

// This is the specification of the Callback routine used when calling the RecalcWaveforms
// function
typedef void (*recalcStatusCallback)(int percDone);

// This external function recreates the base waveform file (waveforms.raw) using a specifed
// sampling rate.  The callback routine provides interactivity to let the user know what
// percentage is complete in regenerating the waveforms.  When a NULL pointer is used as the
// callback routine, no status is reported.
BOOL RecalcWaveforms(char * baseDir, int sampRate, recalcStatusCallback callBack);

typedef float (*iir_filter_type)(float input,float *hist1_ptr, float *coef_ptr, int revLevel);
extern iir_filter_type usefilter;

extern partialFormat PCM[54];
extern Bit16s romfile[262656];
extern Bit32s divtable[256];
extern Bit32s smalldivtable[256];
extern Bit32u wavtabler[64][256];
extern Bit32u looptabler[16][16][256];	
extern Bit16s sintable[65536];
extern Bit32s penvtable[16][128];		
extern Bit32s pulsetable[101];
extern Bit32s pulseoffset[101];
extern Bit32s sawtable[128][128];
extern float filtcoeff[FILTERGRAN][32][16];	
extern Bit32u lfoptable[101][128];
extern Bit32s ampveltable[128][64];
extern Bit32s amptable[129];
extern Bit16s smallnoise[441];
extern Bit32s samplepos;
extern Bit16s* waveforms[4][256];
extern Bit32u waveformsize[4][256];
extern Bit8s LoopPatterns[16][16];
extern int drumPan[30][2];
extern float ResonFactor[32];
extern float ResonInv[32];

extern Bit32s getPitchEnvelope(dpoly::partialStatus *pStat, dpoly *poly);
extern Bit32s getAmpEnvelope(dpoly::partialStatus *pStat, dpoly *poly);
extern Bit32s getFiltEnvelope(Bit16s wg, dpoly::partialStatus *pStat, dpoly *poly);

class CSynthMT32  {
private:

	unsigned char initmode;
	bool isOpen;
	SynthProperties myProp;
	
	bool InitTables(const char * baseDir);

public:
	CSynthMT32() : isOpen(false) {};

	// Used to initialized the MT-32.  The baseDir parameter points to the location in the
	// filesystem where the ROM and data files are located.  The second parameter specifies
	// properties for the synthesizer, as outlined in the structure above.
	// Returns TRUE if initialization was sucessful, otherwise returns FALSE.
	bool ClassicOpen(const char *baseDir, SynthProperties useProp);

	// Closes the MT-32 and deallocates any memory used by the synthesizer
	void Close(void);

	// Sends a 4-byte MIDI message to the MT-32 for immediate playback
	void PlayMsg(Bit32u msg);

	// Sends a string of Sysex commands to the MT-32 for immediate interpretation
        void PlaySysex(Bit8u * sysex, Bit32u len);
        
        // Save the system state to a sysex file specified by filename 
        int DumpSysex(char *filename);
   
	// This callback routine is used to have the MT-32 generate samples to the specified
	// output stream.  The length is in whole samples, not bytes. (I.E. in 16-bit stereo,
	// one sample is 4 bytes)
	void MT32_CallBack(Bit8u * stream, Bit32u len, int volume);

};

#endif





More information about the Scummvm-git-logs mailing list