diff options
| -rw-r--r-- | engines/sci/sfx/player/player.cpp | 11 | ||||
| -rw-r--r-- | engines/sci/sfx/softseq/adlib.cpp | 94 | ||||
| -rw-r--r-- | engines/sci/sfx/softseq/adlib.h | 98 | 
3 files changed, 116 insertions, 87 deletions
| diff --git a/engines/sci/sfx/player/player.cpp b/engines/sci/sfx/player/player.cpp index 90d99c8092..e2ad9e5213 100644 --- a/engines/sci/sfx/player/player.cpp +++ b/engines/sci/sfx/player/player.cpp @@ -156,8 +156,12 @@ static int player_add_iterator(SongIterator *it, uint32 start_time) {  	SIMSG_SEND(it, SIMSG_SET_PLAYMASK(mididrv->getPlayMask()));  	SIMSG_SEND(it, SIMSG_SET_RHYTHM(mididrv->hasRhythmChannel())); -	current_time = Audio::Timestamp(g_system->getMillis(), 1000000 / tempo); -	wakeup_time = Audio::Timestamp(start_time, SFX_TICKS_PER_SEC); +	if (play_it == NULL) { +		// Resync with clock +		current_time = Audio::Timestamp(g_system->getMillis(), 1000000 / tempo); +		wakeup_time = Audio::Timestamp(start_time, SFX_TICKS_PER_SEC); +	} +  	play_it = sfx_iterator_combine(play_it, it);  	play_it_done = 0;  	mutex->unlock(); @@ -171,9 +175,12 @@ static int player_fade_out(void) {  }  static int player_stop(void) { +	debug(3, "Player: Stopping song iterator %p", (void *)play_it);  	mutex->lock();  	delete play_it;  	play_it = NULL; +	for (int i = 0; i < MIDI_CHANNELS; i++) +		static_cast<MidiDriver *>(mididrv)->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0);  	mutex->unlock();  	return SFX_OK; diff --git a/engines/sci/sfx/softseq/adlib.cpp b/engines/sci/sfx/softseq/adlib.cpp index d12b4356cc..3481eaa7ad 100644 --- a/engines/sci/sfx/softseq/adlib.cpp +++ b/engines/sci/sfx/softseq/adlib.cpp @@ -41,7 +41,6 @@ namespace Sci {  // FIXME: We don't seem to be sending the polyphony init data, so disable this for now  #define ADLIB_DISABLE_VOICE_MAPPING -#define ADLIB_SCI1  static const byte registerOffset[MidiDriver_Adlib::kVoices] = {  	0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12 @@ -75,11 +74,14 @@ static const int ym3812_note[13] = {  	0x2ae  }; -int MidiDriver_Adlib::open() { +int MidiDriver_Adlib::open(bool isSCI0) {  	int rate = _mixer->getOutputRate();  	_stereo = STEREO; +	debug(3, "ADLIB: Starting driver in %s mode", (isSCI0 ? "SCI0" : "SCI1")); +	_isSCI0 = isSCI0; +  	for (int i = 0; i < (isStereo() ? 2 : 1); i++) {  		_fmopl[i] = makeAdlibOPL(rate); @@ -153,6 +155,11 @@ void MidiDriver_Adlib::send(uint32 b) {  			voiceMapping(channel, op2);  #endif  			break; +		case 0x4e: +			// FIXME: this flag should be set to 0 when a new song is started +			debug(3, "ADLIB: Setting velocity control flag for channel %i to %i", channel, op2); +			_channels[channel].enableVelocity = op2; +			break;  		case SCI_MIDI_CHANNEL_NOTES_OFF:  			for (int i = 0; i < kVoices; i++)  				if ((_voices[i].channel == channel) && (_voices[i].note != -1)) @@ -481,57 +488,66 @@ void MidiDriver_Adlib::setNote(int voice, int note, bool key) {  	setRegister(0xA0 + voice, fre & 0xff);  	setRegister(0xB0 + voice, (key << 5) | (oct << 2) | (fre >> 8)); -// FIXME -#ifdef ADLIB_SCI1 -	int velocity = _channels[_voices[voice].channel].volume + 1; -	velocity = velocity * (velocityMap1[_voices[voice].velocity] + 1) / 64; -	velocity = velocity * (_masterVolume + 1) / 16; -	if (--velocity < 0) -		velocity = 0; -#else -	int velocity = _masterVolume + 3; -	if (velocity > 15) -		velocity = 15; -	velocity *= 4; -#endif -	if (!_playSwitch) -		velocity = 0; - -	setVelocity(voice, velocity); +	setVelocity(voice);  } -void MidiDriver_Adlib::setVelocity(int voice, int velocity) { +void MidiDriver_Adlib::setVelocity(int voice) {  	AdlibPatch &patch = _patches[_voices[voice].patch];  	int pan = _channels[_voices[voice].channel].pan; -	setVelocityReg(registerOffset[voice] + 3, velocity, pan, patch.op[1]); +	setVelocityReg(registerOffset[voice] + 3, calcVelocity(voice, 1), patch.op[1].kbScaleLevel, pan);  	// In AM mode we need to set the level for both operators  	if (_patches[_voices[voice].patch].mod.algorithm == 1) -		setVelocityReg(registerOffset[voice], velocity, pan, patch.op[0]); +		setVelocityReg(registerOffset[voice], calcVelocity(voice, 0), patch.op[0].kbScaleLevel, pan);  } -void MidiDriver_Adlib::setVelocityReg(int regOffset, int velocity, int pan, AdlibOperator &op) { -// FIXME -#ifdef ADLIB_SCI1 -	int vel = (velocityMap2[velocity] * (63 - op.totalLevel) / 63); -#else -	int vel = (velocity / 4 * ((63 - op.totalLevel) / 15)); -#endif +int MidiDriver_Adlib::calcVelocity(int voice, int op) { +	if (_isSCI0) { +		int velocity = _masterVolume; + +		if ((velocity > 0) && (velocity < 13)) +			velocity += 3; + +		int insVelocity; +		if (_channels[_voices[voice].channel].enableVelocity) +			insVelocity = _voices[voice].velocity; +		else +			insVelocity = 63 - _patches[_voices[voice].patch].op[op].totalLevel; + +		// Note: Later SCI0 has a static table that is close to this formula, but not exactly the same. +		// Early SCI0 does (velocity * (insVelocity / 15)) +		return velocity * insVelocity / 15; +	} else { +		AdlibOperator &oper = _patches[_voices[voice].patch].op[op]; +		int velocity = _channels[_voices[voice].channel].volume + 1; +		velocity = velocity * (velocityMap1[_voices[voice].velocity] + 1) / 64; +		velocity = velocity * (_masterVolume + 1) / 16; + +		if (--velocity < 0) +			velocity = 0; + +		return velocityMap2[velocity] * (63 - oper.totalLevel) / 63; +	} +} + +void MidiDriver_Adlib::setVelocityReg(int regOffset, int velocity, int kbScaleLevel, int pan) { +	if (!_playSwitch) +		velocity = 0;  	if (isStereo()) { -		int velLeft = vel; -		int velRight = vel; +		int velLeft = velocity; +		int velRight = velocity;  		if (pan > 0x40)  			velLeft = velLeft * (0x7f - pan) / 0x3f;  		else if (pan < 0x40)  			velRight = velRight * pan / 0x40; -		setRegister(0x40 + regOffset, (op.kbScaleLevel << 6) | (63 - velLeft), kLeftChannel); -		setRegister(0x40 + regOffset, (op.kbScaleLevel << 6) | (63 - velRight), kRightChannel); +		setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velLeft), kLeftChannel); +		setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velRight), kRightChannel);  	} else { -		setRegister(0x40 + regOffset, (op.kbScaleLevel << 6) | (63 - vel)); +		setRegister(0x40 + regOffset, (kbScaleLevel << 6) | (63 - velocity));  	}  } @@ -575,6 +591,8 @@ void MidiDriver_Adlib::playSwitch(bool play) {  }  int MidiPlayer_Adlib::open(ResourceManager *resmgr) { +	assert(resmgr != NULL); +  	// Load up the patch.003 file, parse out the instruments  	Resource *res = resmgr->findResource(kResourceTypePatch, 3, 0); @@ -583,19 +601,19 @@ int MidiPlayer_Adlib::open(ResourceManager *resmgr) {  		return -1;  	} -	if (res->size < 1344) { -		error("ADLIB: Expected patch.003 of at least %d bytes, got %d", 1344, res->size); +	if ((res->size != 1344) && (res->size != 2690)) { +		error("ADLIB: Unsupported patch format (%i bytes)", res->size);  		return -1;  	}  	for (int i = 0; i < 48; i++)  		_driver->sysEx(res->data + (28 * i), 28); -	if (res->size > 1344) +	if (res->size == 2690)  		for (int i = 48; i < 96; i++)  			_driver->sysEx(res->data + 2 + (28 * i), 28); -	return _driver->open(); +	return static_cast<MidiDriver_Adlib *>(_driver)->open(resmgr->_sciVersion == SCI_VERSION_0);  }  } // End of namespace Sci diff --git a/engines/sci/sfx/softseq/adlib.h b/engines/sci/sfx/softseq/adlib.h index 836a92ef07..a1128e6a96 100644 --- a/engines/sci/sfx/softseq/adlib.h +++ b/engines/sci/sfx/softseq/adlib.h @@ -34,6 +34,27 @@ public:  		kVoices = 9  	}; +	MidiDriver_Adlib(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15) { } +	~MidiDriver_Adlib() { } + +	// MidiDriver +	int open(bool isSCI0); +	void close(); +	void send(uint32 b); +	MidiChannel *allocateChannel() { return NULL; } +	MidiChannel *getPercussionChannel() { return NULL; } + +	// AudioStream +	bool isStereo() const { return _stereo; } +	int getRate() const { return _mixer->getOutputRate(); } + +	// MidiDriver_Emulated +	void generateSamples(int16 *buf, int len); + +	void setVolume(byte volume); +	void playSwitch(bool play); + +private:  	enum ChannelID {  		kLeftChannel = 1,  		kRightChannel = 2 @@ -44,18 +65,18 @@ public:  		bool vibrato;  		bool envelopeType;  		bool kbScaleRate; -		byte frequencyMult;	// (0-15) -		byte kbScaleLevel;	// (0-3) -		byte totalLevel;	// (0-63, 0=max, 63=min) -		byte attackRate;	// (0-15) -		byte decayRate;		// (0-15) -		byte sustainLevel;	// (0-15) -		byte releaseRate;	// (0-15) -		byte waveForm;		// (0-3) +		byte frequencyMult;		// (0-15) +		byte kbScaleLevel;		// (0-3) +		byte totalLevel;		// (0-63, 0=max, 63=min) +		byte attackRate;		// (0-15) +		byte decayRate;			// (0-15) +		byte sustainLevel;		// (0-15) +		byte releaseRate;		// (0-15) +		byte waveForm;			// (0-3)  	};  	struct AdlibModulator { -		byte feedback;		// (0-7) +		byte feedback;			// (0-7)  		bool algorithm;  	}; @@ -65,50 +86,32 @@ public:  	};  	struct Channel { -		uint8 patch;		// Patch setting -		uint8 volume;		// Channel volume (0-63) -		uint8 pan;			// Pan setting (0-127, 64 is center) -		uint8 holdPedal;	// Hold pedal setting (0 to 63 is off, 127 to 64 is on) -		uint8 extraVoices;	// The number of additional voices this channel optimally needs -		uint16 pitchWheel;	// Pitch wheel setting (0-16383, 8192 is center) -		uint8 lastVoice;	// Last voice used for this MIDI channel - -		Channel() : patch(0), volume(63), pan(64), holdPedal(0), extraVoices(0), pitchWheel(8192), lastVoice(0) { } +		uint8 patch;			// Patch setting +		uint8 volume;			// Channel volume (0-63) +		uint8 pan;				// Pan setting (0-127, 64 is center) +		uint8 holdPedal;		// Hold pedal setting (0 to 63 is off, 127 to 64 is on) +		uint8 extraVoices;		// The number of additional voices this channel optimally needs +		uint16 pitchWheel;		// Pitch wheel setting (0-16383, 8192 is center) +		uint8 lastVoice;		// Last voice used for this MIDI channel +		bool enableVelocity;	// Enable velocity control (SCI0) + +		Channel() : patch(0), volume(63), pan(64), holdPedal(0), extraVoices(0), +					pitchWheel(8192), lastVoice(0), enableVelocity(false) { }  	};  	struct AdlibVoice { -		int8 channel;		// MIDI channel that this voice is assigned to or -1 -		int8 note;			// Currently playing MIDI note or -1 -		int8 patch;			// Currently playing patch or -1 -		uint8 velocity;		// Note velocity -		bool isSustained;	// Flag indicating a note that is being sustained by the hold pedal -		uint16 age;			// Age of the current note +		int8 channel;			// MIDI channel that this voice is assigned to or -1 +		int8 note;				// Currently playing MIDI note or -1 +		int8 patch;				// Currently playing patch or -1 +		uint8 velocity;			// Note velocity +		bool isSustained;		// Flag indicating a note that is being sustained by the hold pedal +		uint16 age;				// Age of the current note  		AdlibVoice() : channel(-1), note(-1), patch(-1), velocity(0), isSustained(false), age(0) { }  	}; -	MidiDriver_Adlib(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15) { } -	~MidiDriver_Adlib() { } - -	// MidiDriver -	int open(); -	void close(); -	void send(uint32 b); -	MidiChannel *allocateChannel() { return NULL; } -	MidiChannel *getPercussionChannel() { return NULL; } - -	// AudioStream -	bool isStereo() const { return _stereo; } -	int getRate() const { return _mixer->getOutputRate(); } - -	// MidiDriver_Emulated -	void generateSamples(int16 *buf, int len); - -	void setVolume(byte volume); -	void playSwitch(bool play); - -private:  	bool _stereo; +	bool _isSCI0;  	FM_OPL *_fmopl[2];  	bool _playSwitch;  	int _masterVolume; @@ -122,7 +125,7 @@ private:  	void voiceOff(int voice);  	void setPatch(int voice, int patch);  	void setNote(int voice, int note, bool key); -	void setVelocity(int voice, int velocity); +	void setVelocity(int voice);  	void setOperator(int oper, AdlibOperator &op);  	void setRegister(int reg, int value, int channels = kLeftChannel | kRightChannel);  	void renewNotes(int channel, bool key); @@ -134,7 +137,8 @@ private:  	void releaseVoices(int channel, int voices);  	void donateVoices();  	int findVoiceBasic(int channel); -	void setVelocityReg(int regOffset, int velocity, int pan, AdlibOperator &op); +	void setVelocityReg(int regOffset, int velocity, int kbScaleLevel, int pan); +	int calcVelocity(int voice, int op);  };  class MidiPlayer_Adlib : public MidiPlayer { | 
