[Scummvm-cvs-logs] SF.net SVN: scummvm:[45682] scummvm/trunk/engines/sci/sfx

waltervn at users.sourceforge.net waltervn at users.sourceforge.net
Thu Nov 5 02:35:43 CET 2009


Revision: 45682
          http://scummvm.svn.sourceforge.net/scummvm/?rev=45682&view=rev
Author:   waltervn
Date:     2009-11-05 01:35:43 +0000 (Thu, 05 Nov 2009)

Log Message:
-----------
SCI: Converted FreeSCI Amiga sound driver. Some cleanup.

Modified Paths:
--------------
    scummvm/trunk/engines/sci/sfx/core.cpp
    scummvm/trunk/engines/sci/sfx/sci_midi.h
    scummvm/trunk/engines/sci/sfx/softseq/adlib.cpp
    scummvm/trunk/engines/sci/sfx/softseq/amiga.cpp

Removed Paths:
-------------
    scummvm/trunk/engines/sci/sfx/softseq/adlib.h

Modified: scummvm/trunk/engines/sci/sfx/core.cpp
===================================================================
--- scummvm/trunk/engines/sci/sfx/core.cpp	2009-11-05 00:41:32 UTC (rev 45681)
+++ scummvm/trunk/engines/sci/sfx/core.cpp	2009-11-05 01:35:43 UTC (rev 45682)
@@ -32,7 +32,6 @@
 #include "sci/sfx/sci_midi.h"
 
 #include "sci/sfx/softseq/pcjr.h"
-#include "sci/sfx/softseq/adlib.h"
 
 #include "common/system.h"
 #include "common/timer.h"
@@ -229,7 +228,11 @@
 
 	switch (musicDriver) {
 	case MD_ADLIB:
-		_mididrv = new MidiPlayer_Adlib();
+		// FIXME: There's no Amiga sound option, so we hook it up to Adlib
+		if (((SciEngine *)g_engine)->getPlatform() == Common::kPlatformAmiga)
+			_mididrv = MidiPlayer_Amiga_create();
+		else
+			_mididrv = MidiPlayer_Adlib_create();
 		break;
 	case MD_PCJR:
 		_mididrv = new MidiPlayer_PCJr();

Modified: scummvm/trunk/engines/sci/sfx/sci_midi.h
===================================================================
--- scummvm/trunk/engines/sci/sfx/sci_midi.h	2009-11-05 00:41:32 UTC (rev 45681)
+++ scummvm/trunk/engines/sci/sfx/sci_midi.h	2009-11-05 01:35:43 UTC (rev 45682)
@@ -98,6 +98,9 @@
 	}
 };
 
+extern MidiPlayer *MidiPlayer_Adlib_create();
+extern MidiPlayer *MidiPlayer_Amiga_create();
+
 } // End of namespace Sci
 
 #endif // SCI_SFX_MIDI_H

Modified: scummvm/trunk/engines/sci/sfx/softseq/adlib.cpp
===================================================================
--- scummvm/trunk/engines/sci/sfx/softseq/adlib.cpp	2009-11-05 00:41:32 UTC (rev 45681)
+++ scummvm/trunk/engines/sci/sfx/softseq/adlib.cpp	2009-11-05 01:35:43 UTC (rev 45682)
@@ -27,9 +27,10 @@
 #include "sci/sfx/iterator.h"
 
 #include "sound/fmopl.h"
+#include "sound/softsynth/emumidi.h"
 
 #include "sci/resource.h"
-#include "sci/sfx/softseq/adlib.h"
+#include "sci/sfx/sci_midi.h"
 
 namespace Sci {
 
@@ -42,6 +43,134 @@
 // FIXME: We don't seem to be sending the polyphony init data, so disable this for now
 #define ADLIB_DISABLE_VOICE_MAPPING
 
+class MidiDriver_Adlib : public MidiDriver_Emulated {
+public:
+	enum {
+		kVoices = 9,
+		kRhythmKeys = 62
+	};
+
+	MidiDriver_Adlib(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15), _rhythmKeyMap(0), _opl(0) { }
+	virtual ~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);
+	bool loadResource(const byte *data, uint size);
+	virtual uint32 property(int prop, uint32 param);
+
+private:
+	enum ChannelID {
+		kLeftChannel = 1,
+		kRightChannel = 2
+	};
+
+	struct AdlibOperator {
+		bool amplitudeMod;
+		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)
+	};
+
+	struct AdlibModulator {
+		byte feedback;			// (0-7)
+		bool algorithm;
+	};
+
+	struct AdlibPatch {
+		AdlibOperator op[2];
+		AdlibModulator mod;
+	};
+
+	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
+		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
+		int 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) { }
+	};
+
+	bool _stereo;
+	bool _isSCI0;
+	OPL::OPL *_opl;
+	bool _playSwitch;
+	int _masterVolume;
+	Channel _channels[MIDI_CHANNELS];
+	AdlibVoice _voices[kVoices];
+	byte *_rhythmKeyMap;
+	Common::Array<AdlibPatch> _patches;
+
+	void loadInstrument(const byte *ins);
+	void voiceOn(int voice, int note, int velocity);
+	void voiceOff(int voice);
+	void setPatch(int voice, int patch);
+	void setNote(int voice, int note, bool key);
+	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);
+	void noteOn(int channel, int note, int velocity);
+	void noteOff(int channel, int note);
+	int findVoice(int channel);
+	void voiceMapping(int channel, int voices);
+	void assignVoices(int channel, int voices);
+	void releaseVoices(int channel, int voices);
+	void donateVoices();
+	int findVoiceBasic(int channel);
+	void setVelocityReg(int regOffset, int velocity, int kbScaleLevel, int pan);
+	int calcVelocity(int voice, int op);
+};
+
+class MidiPlayer_Adlib : public MidiPlayer {
+public:
+	MidiPlayer_Adlib() { _driver = new MidiDriver_Adlib(g_system->getMixer()); }
+	int open(ResourceManager *resMan);
+	int getPlayMask() const { return 0x04; }
+	int getPolyphony() const { return MidiDriver_Adlib::kVoices; }
+	bool hasRhythmChannel() const { return false; }
+	void setVolume(byte volume) { static_cast<MidiDriver_Adlib *>(_driver)->setVolume(volume); }
+	void playSwitch(bool play) { static_cast<MidiDriver_Adlib *>(_driver)->playSwitch(play); }
+	void loadInstrument(int idx, byte *data);
+};
+
 static const byte registerOffset[MidiDriver_Adlib::kVoices] = {
 	0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12
 };
@@ -679,4 +808,8 @@
 	return static_cast<MidiDriver_Adlib *>(_driver)->open(getSciVersion() <= SCI_VERSION_0_LATE);
 }
 
+MidiPlayer *MidiPlayer_Adlib_create() {
+	return new MidiPlayer_Adlib();
+}
+
 } // End of namespace Sci

Deleted: scummvm/trunk/engines/sci/sfx/softseq/adlib.h
===================================================================
--- scummvm/trunk/engines/sci/sfx/softseq/adlib.h	2009-11-05 00:41:32 UTC (rev 45681)
+++ scummvm/trunk/engines/sci/sfx/softseq/adlib.h	2009-11-05 01:35:43 UTC (rev 45682)
@@ -1,160 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "sci/sfx/sci_midi.h"
-#include "sound/fmopl.h"
-
-namespace Sci {
-
-class MidiDriver_Adlib : public MidiDriver_Emulated {
-public:
-	enum {
-		kVoices = 9,
-		kRhythmKeys = 62
-	};
-
-	MidiDriver_Adlib(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15), _rhythmKeyMap(0), _opl(0) { }
-	virtual ~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);
-	bool loadResource(const byte *data, uint size);
-	uint32 property(int prop, uint32 param);
-
-private:
-	enum ChannelID {
-		kLeftChannel = 1,
-		kRightChannel = 2
-	};
-
-	struct AdlibOperator {
-		bool amplitudeMod;
-		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)
-	};
-
-	struct AdlibModulator {
-		byte feedback;			// (0-7)
-		bool algorithm;
-	};
-
-	struct AdlibPatch {
-		AdlibOperator op[2];
-		AdlibModulator mod;
-	};
-
-	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
-		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
-		int 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) { }
-	};
-
-	bool _stereo;
-	bool _isSCI0;
-	OPL::OPL *_opl;
-	bool _playSwitch;
-	int _masterVolume;
-	Channel _channels[MIDI_CHANNELS];
-	AdlibVoice _voices[kVoices];
-	byte *_rhythmKeyMap;
-	Common::Array<AdlibPatch> _patches;
-
-	void loadInstrument(const byte *ins);
-	void voiceOn(int voice, int note, int velocity);
-	void voiceOff(int voice);
-	void setPatch(int voice, int patch);
-	void setNote(int voice, int note, bool key);
-	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);
-	void noteOn(int channel, int note, int velocity);
-	void noteOff(int channel, int note);
-	int findVoice(int channel);
-	void voiceMapping(int channel, int voices);
-	void assignVoices(int channel, int voices);
-	void releaseVoices(int channel, int voices);
-	void donateVoices();
-	int findVoiceBasic(int channel);
-	void setVelocityReg(int regOffset, int velocity, int kbScaleLevel, int pan);
-	int calcVelocity(int voice, int op);
-};
-
-class MidiPlayer_Adlib : public MidiPlayer {
-public:
-	MidiPlayer_Adlib() { _driver = new MidiDriver_Adlib(g_system->getMixer()); }
-	int open(ResourceManager *resMan);
-	int getPlayMask() const { return 0x04; }
-	int getPolyphony() const { return MidiDriver_Adlib::kVoices; }
-	bool hasRhythmChannel() const { return false; }
-	void setVolume(byte volume) { static_cast<MidiDriver_Adlib *>(_driver)->setVolume(volume); }
-	void playSwitch(bool play) { static_cast<MidiDriver_Adlib *>(_driver)->playSwitch(play); }
-	void loadInstrument(int idx, byte *data);
-};
-
-} // End of namespace Sci
-

Modified: scummvm/trunk/engines/sci/sfx/softseq/amiga.cpp
===================================================================
--- scummvm/trunk/engines/sci/sfx/softseq/amiga.cpp	2009-11-05 00:41:32 UTC (rev 45681)
+++ scummvm/trunk/engines/sci/sfx/softseq/amiga.cpp	2009-11-05 01:35:43 UTC (rev 45682)
@@ -25,93 +25,19 @@
 
 #include "sci/sfx/softseq.h"
 
+#include "sound/softsynth/emumidi.h"
+#include "sci/sfx/sci_midi.h"
+
 #include "common/file.h"
 #include "common/frac.h"
 #include "common/util.h"
 
 namespace Sci {
 
-#define FREQUENCY 44100
-#define CHANNELS_NR 10
-#define HW_CHANNELS_NR 16
-
-/* Samplerate of the instrument bank */
-#define BASE_FREQ 20000
-
-/* Instrument looping flag */
-#define MODE_LOOP 1 << 0
-/* Instrument pitch changes flag */
-#define MODE_PITCH 1 << 1
-
-#define PAN_LEFT 91
-#define PAN_RIGHT 164
-
 /* #define DEBUG */
 
-struct envelope_t {
-	/* Phase period length in samples */
-	int length;
-	/* Velocity delta per period */
-	int delta;
-	/* Target velocity */
-	int target;
-};
-
-/* Fast decay envelope */
-static envelope_t env_decay = {FREQUENCY / (32 * 64), 1, 0};
-
-struct instrument_t {
-	char name[30];
-	int mode;
-	/* Size of non-looping part in bytes */
-	int size;
-	/* Starting offset and size of loop in bytes */
-	int loop_size;
-	/* Transpose value in semitones */
-	int transpose;
-	/* Envelope */
-	envelope_t envelope[4];
-	int8 *samples;
-	int8 *loop;
-};
-
-struct bank_t {
-	char name[30];
-	int size;
-	instrument_t *instruments[256];
-};
-
-struct channel_t {
-	int instrument;
-	int note;
-	int note_velocity;
-	int velocity;
-	int envelope;
-	/* Number of samples till next envelope event */
-	int envelope_samples;
-	int decay;
-	int looping;
-	int hw_channel;
-	frac_t offset;
-	frac_t rate;
-};
-
-struct hw_channel_t {
-	int instrument;
-	int volume;
-	int pan;
-};
-
-/* Instrument bank */
-static bank_t bank;
-/* Internal channels */
-static channel_t channels[CHANNELS_NR];
-/* External channels */
-static hw_channel_t hw_channels[HW_CHANNELS_NR];
-/* Overall volume */
-static int volume = 127;
-
-/* Frequencies for every note */
+// Frequencies for every note
+// FIXME Store only one octave
 static const int freq_table[] = {
 	58, 62, 65, 69, 73, 78, 82, 87,
 	92, 98, 104, 110, 117, 124, 131, 139,
@@ -131,7 +57,110 @@
 	59932, 63496, 67271, 71271, 75509, 80000, 84757, 89796
 };
 
-static void set_envelope(channel_t *channel, envelope_t *envelope, int phase) {
+class MidiDriver_Amiga : public MidiDriver_Emulated {
+public:
+	enum {
+		kVoices = 4
+	};
+
+	MidiDriver_Amiga(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer), _playSwitch(true), _masterVolume(15) { }
+	virtual ~MidiDriver_Amiga() { }
+
+	// MidiDriver
+	int open();
+	void close();
+	void send(uint32 b);
+	MidiChannel *allocateChannel() { return NULL; }
+	MidiChannel *getPercussionChannel() { return NULL; }
+
+	// AudioStream
+	bool isStereo() const { return true; }
+	int getRate() const { return _mixer->getOutputRate(); }
+
+	// MidiDriver_Emulated
+	void generateSamples(int16 *buf, int len);
+
+	void setVolume(byte volume);
+	void playSwitch(bool play);
+	virtual uint32 property(int prop, uint32 param);
+
+private:
+	enum {
+		kModeLoop = 1 << 0, // Instrument looping flag
+		kModePitch = 1 << 1 // Instrument pitch changes flag
+	};
+
+	enum {
+		kChannels = 10,
+		kBaseFreq = 20000, // Samplerate of the instrument bank
+		kPanLeft = 91,
+		kPanRight = 164
+	};
+
+	struct Channel {
+		int instrument;
+		int volume;
+		int pan;
+	};
+
+	struct Envelope {
+		int length; // Phase period length in samples
+		int delta; // Velocity delta per period
+		int target; // Target velocity
+	};
+
+	struct Voice {
+		int instrument;
+		int note;
+		int note_velocity;
+		int velocity;
+		int envelope;
+		int envelope_samples; // Number of samples till next envelope event
+		int decay;
+		int looping;
+		int hw_channel;
+		frac_t offset;
+		frac_t rate;
+	};
+
+	struct Instrument {
+		char name[30];
+		int mode;
+		int size; // Size of non-looping part in bytes
+		int loop_size; // Starting offset and size of loop in bytes
+		int transpose; // Transpose value in semitones
+		Envelope envelope[4]; // Envelope
+		int8 *samples;
+		int8 *loop;
+	};
+
+	struct Bank {
+		char name[30];
+		uint size;
+		Instrument *instruments[256];
+	};
+
+	bool _playSwitch;
+	int _masterVolume;
+	int _frequency;
+	Envelope _envDecay;
+	Bank _bank; // Instrument bank
+
+	Channel _channels[MIDI_CHANNELS];
+	/* Internal channels */
+	Voice _voices[kChannels];
+
+	void setEnvelope(Voice *channel, Envelope *envelope, int phase);
+	int interpolate(int8 *samples, frac_t offset);
+	void playInstrument(int16 *dest, Voice *channel, int count);
+	void changeInstrument(int channel, int instrument);
+	void stopChannel(int ch);
+	void stopNote(int ch, int note);
+	void startNote(int ch, int note, int velocity);
+	Instrument *readInstrument(Common::File &file, int *id);
+};
+
+void MidiDriver_Amiga::setEnvelope(Voice *channel, Envelope *envelope, int phase) {
 	channel->envelope = phase;
 	channel->envelope_samples = envelope[phase].length;
 
@@ -141,17 +170,17 @@
 		channel->velocity = envelope[phase - 1].target;
 }
 
-static inline int interpolate(int8 *samples, frac_t offset) {
+int MidiDriver_Amiga::interpolate(int8 *samples, frac_t offset) {
 	int x = fracToInt(offset);
 	int diff = (samples[x + 1] - samples[x]) << 8;
 
 	return (samples[x] << 8) + fracToInt(diff * (offset & FRAC_LO_MASK));
 }
 
-static void play_instrument(int16 *dest, channel_t *channel, int count) {
+void MidiDriver_Amiga::playInstrument(int16 *dest, Voice *channel, int count) {
 	int index = 0;
-	int vol = hw_channels[channel->hw_channel].volume;
-	instrument_t *instrument = bank.instruments[channel->instrument];
+	int vol = _channels[channel->hw_channel].volume;
+	Instrument *instrument = _bank.instruments[channel->instrument];
 
 	while (1) {
 		/* Available source samples until end of segment */
@@ -193,11 +222,11 @@
 			channel->envelope_samples -= amount;
 
 		if (channel->envelope_samples == 0) {
-			envelope_t *envelope;
+			Envelope *envelope;
 			int delta, target, velocity;
 
 			if (channel->decay)
-				envelope = &env_decay;
+				envelope = &_envDecay;
 			else
 				envelope = &instrument->envelope[channel->envelope];
 
@@ -218,7 +247,7 @@
 					case 0:
 					case 2:
 						/* Go to next phase */
-						set_envelope(channel, instrument->envelope, channel->envelope + 1);
+						setEnvelope(channel, instrument->envelope, channel->envelope + 1);
 						break;
 					case 1:
 					case 3:
@@ -237,7 +266,7 @@
 			break;
 
 		if (fracToInt(channel->offset) >= seg_end) {
-			if (instrument->mode & MODE_LOOP) {
+			if (instrument->mode & kModeLoop) {
 				/* Loop the samples */
 				channel->offset -= intToFrac(seg_end);
 				channel->looping = 1;
@@ -250,79 +279,79 @@
 	}
 }
 
-static void change_instrument(int channel, int instrument) {
+void MidiDriver_Amiga::changeInstrument(int channel, int instrument) {
 #ifdef DEBUG
-	if (bank.instruments[instrument])
-		printf("[sfx:seq:amiga] Setting channel %i to \"%s\" (%i)\n", channel, bank.instruments[instrument]->name, instrument);
+	if (_bank.instruments[instrument])
+		printf("[sfx:seq:amiga] Setting channel %i to \"%s\" (%i)\n", channel, _bank.instruments[instrument]->name, instrument);
 	else
 		warning("[sfx:seq:amiga] instrument %i does not exist (channel %i)", instrument, channel);
 #endif
-	hw_channels[channel].instrument = instrument;
+	_channels[channel].instrument = instrument;
 }
 
-static void stop_channel(int ch) {
+void MidiDriver_Amiga::stopChannel(int ch) {
 	int i;
 
 	/* Start decay phase for note on this hw channel, if any */
-	for (i = 0; i < CHANNELS_NR; i++)
-		if (channels[i].note != -1 && channels[i].hw_channel == ch && !channels[i].decay) {
+	for (i = 0; i < kChannels; i++)
+		if (_voices[i].note != -1 && _voices[i].hw_channel == ch && !_voices[i].decay) {
 			/* Trigger fast decay envelope */
-			channels[i].decay = 1;
-			channels[i].envelope_samples = env_decay.length;
+			_voices[i].decay = 1;
+			_voices[i].envelope_samples = _envDecay.length;
 			break;
 		}
 }
 
-static void stop_note(int ch, int note) {
+void MidiDriver_Amiga::stopNote(int ch, int note) {
 	int channel;
-	instrument_t *instrument;
+	Instrument *instrument;
 
-	for (channel = 0; channel < CHANNELS_NR; channel++)
-		if (channels[channel].note == note && channels[channel].hw_channel == ch && !channels[channel].decay)
+	for (channel = 0; channel < kChannels; channel++)
+		if (_voices[channel].note == note && _voices[channel].hw_channel == ch && !_voices[channel].decay)
 			break;
 
-	if (channel == CHANNELS_NR) {
+	if (channel == kChannels) {
 #ifdef DEBUG
 		warning("[sfx:seq:amiga] cannot stop note %i on channel %i", note, ch);
 #endif
 		return;
 	}
 
-	instrument = bank.instruments[channels[channel].instrument];
+	instrument = _bank.instruments[_voices[channel].instrument];
 
 	/* Start the envelope phases for note-off if looping is on and envelope is enabled */
-	if ((instrument->mode & MODE_LOOP) && (instrument->envelope[0].length != 0))
-		set_envelope(&channels[channel], instrument->envelope, 2);
+	if ((instrument->mode & kModeLoop) && (instrument->envelope[0].length != 0))
+		setEnvelope(&_voices[channel], instrument->envelope, 2);
 }
 
-static void start_note(int ch, int note, int velocity) {
-	instrument_t *instrument;
+void MidiDriver_Amiga::startNote(int ch, int note, int velocity) {
+	Instrument *instrument;
 	int channel;
 
-	if (hw_channels[ch].instrument < 0 || hw_channels[ch].instrument > 255) {
-		warning("[sfx:seq:amiga] invalid instrument %i on channel %i", hw_channels[ch].instrument, ch);
+	if (_channels[ch].instrument < 0 || _channels[ch].instrument > 255) {
+		warning("[sfx:seq:amiga] invalid instrument %i on channel %i", _channels[ch].instrument, ch);
 		return;
 	}
 
-	instrument = bank.instruments[hw_channels[ch].instrument];
+	instrument = _bank.instruments[_channels[ch].instrument];
 
 	if (!instrument) {
-		warning("[sfx:seq:amiga] instrument %i does not exist", hw_channels[ch].instrument);
+		warning("[sfx:seq:amiga] instrument %i does not exist", _channels[ch].instrument);
 		return;
 	}
 
-	for (channel = 0; channel < CHANNELS_NR; channel++)
-		if (channels[channel].note == -1)
+	for (channel = 0; channel < kChannels; channel++)
+		if (_voices[channel].note == -1)
 			break;
 
-	if (channel == CHANNELS_NR) {
+	if (channel == kChannels) {
 		warning("[sfx:seq:amiga] could not find a free channel");
 		return;
 	}
 
-	stop_channel(ch);
+	stopChannel(ch);
 
-	if (instrument->mode & MODE_PITCH) {
+	if (instrument->mode & kModePitch) {
 		int fnote = note + instrument->transpose;
 
 		if (fnote < 0 || fnote > 127) {
@@ -331,40 +360,32 @@
 		}
 
 		/* Compute rate for note */
-		channels[channel].rate = doubleToFrac(freq_table[fnote] / (double) FREQUENCY);
+		_voices[channel].rate = doubleToFrac(freq_table[fnote] / (double) _frequency);
 	} else
-		channels[channel].rate = doubleToFrac(BASE_FREQ / (double) FREQUENCY);
+		_voices[channel].rate = doubleToFrac(kBaseFreq / (double) _frequency);
 
-	channels[channel].instrument = hw_channels[ch].instrument;
-	channels[channel].note = note;
-	channels[channel].note_velocity = velocity;
+	_voices[channel].instrument = _channels[ch].instrument;
+	_voices[channel].note = note;
+	_voices[channel].note_velocity = velocity;
 
-	if ((instrument->mode & MODE_LOOP) && (instrument->envelope[0].length != 0))
-		set_envelope(&channels[channel], instrument->envelope, 0);
+	if ((instrument->mode & kModeLoop) && (instrument->envelope[0].length != 0))
+		setEnvelope(&_voices[channel], instrument->envelope, 0);
 	else {
-		channels[channel].velocity = 64;
-		channels[channel].envelope_samples = -1;
+		_voices[channel].velocity = 64;
+		_voices[channel].envelope_samples = -1;
 	}
 
-	channels[channel].offset = 0;
-	channels[channel].hw_channel = ch;
-	channels[channel].decay = 0;
-	channels[channel].looping = 0;
+	_voices[channel].offset = 0;
+	_voices[channel].hw_channel = ch;
+	_voices[channel].decay = 0;
+	_voices[channel].looping = 0;
 }
 
-static int16 read_int16(byte *data) {
-	return (data[0] << 8) | data[1];
-}
-
-static int32 read_int32(byte *data) {
-	return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
-}
-
-static instrument_t *read_instrument(Common::File &file, int *id) {
-	instrument_t *instrument;
+MidiDriver_Amiga::Instrument *MidiDriver_Amiga::readInstrument(Common::File &file, int *id) {
+	Instrument *instrument;
 	byte header[61];
 	int size;
-	int seg_size[3];
+	int16 seg_size[3];
 	int loop_offset;
 	int i;
 
@@ -373,11 +394,11 @@
 		return NULL;
 	}
 
-	instrument = (instrument_t *) malloc(sizeof(instrument_t));
+	instrument = new Instrument;
 
-	seg_size[0] = read_int16(header + 35) * 2;
-	seg_size[1] = read_int16(header + 41) * 2;
-	seg_size[2] = read_int16(header + 47) * 2;
+	seg_size[0] = READ_BE_UINT16(header + 35) * 2;
+	seg_size[1] = READ_BE_UINT16(header + 41) * 2;
+	seg_size[2] = READ_BE_UINT16(header + 47) * 2;
 
 	instrument->mode = header[33];
 	instrument->transpose = (int8) header[34];
@@ -387,17 +408,17 @@
 		if (length == 0 && i > 0)
 			length = 256;
 
-		instrument->envelope[i].length = length * FREQUENCY / 60;
-		instrument->envelope[i].delta = (int8) header[53 + i];
+		instrument->envelope[i].length = length * _frequency / 60;
+		instrument->envelope[i].delta = (int8)header[53 + i];
 		instrument->envelope[i].target = header[57 + i];
 	}
 	/* Final target must be 0 */
 	instrument->envelope[3].target = 0;
 
-	loop_offset = read_int32(header + 37) & ~1;
+	loop_offset = READ_BE_UINT32(header + 37) & ~1;
 	size = seg_size[0] + seg_size[1] + seg_size[2];
 
-	*id = read_int16(header);
+	*id = READ_BE_UINT16(header);
 
 	strncpy(instrument->name, (char *) header + 2, 29);
 	instrument->name[29] = 0;
@@ -405,8 +426,8 @@
 	printf("[sfx:seq:amiga] Reading instrument %i: \"%s\" (%i bytes)\n",
 	          *id, instrument->name, size);
 	printf("                Mode: %02x\n", instrument->mode);
-	printf("                Looping: %s\n", instrument->mode & MODE_LOOP ? "on" : "off");
-	printf("                Pitch changes: %s\n", instrument->mode & MODE_PITCH ? "on" : "off");
+	printf("                Looping: %s\n", instrument->mode & kModeLoop ? "on" : "off");
+	printf("                Pitch changes: %s\n", instrument->mode & kModePitch ? "on" : "off");
 	printf("                Segment sizes: %i %i %i\n", seg_size[0], seg_size[1], seg_size[2]);
 	printf("                Segment offsets: 0 %i %i\n", loop_offset, read_int32(header + 43));
 #endif
@@ -418,7 +439,7 @@
 		return NULL;
 	}
 
-	if (instrument->mode & MODE_LOOP) {
+	if (instrument->mode & kModeLoop) {
 		if (loop_offset + seg_size[1] > size) {
 #ifdef DEBUG
 			warning("[sfx:seq:amiga] looping samples extend %i bytes past end of sample block",
@@ -443,6 +464,7 @@
 		instrument->samples[instrument->size] = instrument->loop[0];
 		instrument->loop[instrument->loop_size] = instrument->loop[0];
 	} else {
+		instrument->loop = NULL;
 		instrument->size = size;
 		instrument->samples[instrument->size] = 0;
 	}
@@ -450,14 +472,26 @@
 	return instrument;
 }
 
-static Common::Error ami_set_option(sfx_softseq_t *self, const char *name, const char *value) {
-	return Common::kUnknownError;
+uint32 MidiDriver_Amiga::property(int prop, uint32 param) {
+	switch(prop) {
+	case MIDI_PROP_MASTER_VOLUME:
+		if (param != 0xffff)
+			_masterVolume = param;
+		return _masterVolume;
+	default:
+		break;
+	}
+	return 0;
 }
 
-static Common::Error ami_init(sfx_softseq_t *self, byte *patch, int patch_len, byte *patch2, int patch2_len) {
+int MidiDriver_Amiga::open() {
+	_frequency = _mixer->getOutputRate();
+	_envDecay.length = _frequency / (32 * 64);
+	_envDecay.delta = 1;
+	_envDecay.target = 0;
+
 	Common::File file;
 	byte header[40];
-	int i;
 
 	if (!file.open("bank.001")) {
 		warning("[sfx:seq:amiga] file bank.001 not found");
@@ -469,29 +503,29 @@
 		return Common::kUnknownError;
 	}
 
-	for (i = 0; i < 256; i++)
-		bank.instruments[i] = NULL;
+	for (uint i = 0; i < 256; i++)
+		_bank.instruments[i] = NULL;
 
-	for (i = 0; i < CHANNELS_NR; i++) {
-		channels[i].note = -1;
+	for (uint i = 0; i < kChannels; i++) {
+		_voices[i].note = -1;
 	}
 
-	for (i = 0; i < HW_CHANNELS_NR; i++) {
-		hw_channels[i].instrument = -1;
-		hw_channels[i].volume = 127;
-		hw_channels[i].pan = (i % 4 == 0 || i % 4 == 3 ? PAN_LEFT : PAN_RIGHT);
+	for (uint i = 0; i < MIDI_CHANNELS; i++) {
+		_channels[i].instrument = -1;
+		_channels[i].volume = 127;
+		_channels[i].pan = (i % 4 == 0 || i % 4 == 3 ? kPanLeft : kPanRight);
 	}
 
-	bank.size = read_int16(header + 38);
-	strncpy(bank.name, (char *) header + 8, 29);
-	bank.name[29] = 0;
+	_bank.size = READ_BE_UINT16(header + 38);
+	strncpy(_bank.name, (char *) header + 8, 29);
+	_bank.name[29] = 0;
 #ifdef DEBUG
-	printf("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", bank.size, bank.name);
+	printf("[sfx:seq:amiga] Reading %i instruments from bank \"%s\"\n", _bank.size, _bank.name);
 #endif
 
-	for (i = 0; i < bank.size; i++) {
+	for (uint i = 0; i < _bank.size; i++) {
 		int id;
-		instrument_t *instrument = read_instrument(file, &id);
+		Instrument *instrument = readInstrument(file, &id);
 
 		if (!instrument) {
 			warning("[sfx:seq:amiga] failed to read bank.001");
@@ -503,124 +537,131 @@
 			return Common::kUnknownError;
 		}
 
-		bank.instruments[id] = instrument;
+		_bank.instruments[id] = instrument;
 	}
 
+	MidiDriver_Emulated::open();
+
+	_mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, false);
+
 	return Common::kNoError;
 }
 
-static void ami_exit(sfx_softseq_t *self) {
-	int i;
+void MidiDriver_Amiga::close() {
+	_mixer->stopHandle(_mixerSoundHandle);
 
-	for (i = 0; i < bank.size; i++) {
-		if (bank.instruments[i]) {
-			free(bank.instruments[i]->samples);
-			free(bank.instruments[i]);
+	for (uint i = 0; i < _bank.size; i++) {
+		if (_bank.instruments[i]) {
+			if (_bank.instruments[i]->loop)
+				free(_bank.instruments[i]->loop);
+			free(_bank.instruments[i]->samples);
+			delete _bank.instruments[i];
 		}
 	}
 }
 
-static void ami_event(sfx_softseq_t *self, byte command, int argc, byte *argv) {
-	int channel, oper;
+void MidiDriver_Amiga::playSwitch(bool play) {
+	_playSwitch = play;
+}
 
-	channel = command & 0x0f;
-	oper = command & 0xf0;
+void MidiDriver_Amiga::setVolume(byte volume_) {
+	_masterVolume = volume_;
+}
 
-	if (channel >= HW_CHANNELS_NR) {
-#ifdef DEBUG
-		warning("[sfx:seq:amiga] received event for non-existing channel %i", channel);
-#endif
-		return;
-	}
+void MidiDriver_Amiga::send(uint32 b) {
+	byte command = b & 0xf0;
+	byte channel = b & 0xf;
+	byte op1 = (b >> 8) & 0xff;
+	byte op2 = (b >> 16) & 0xff;
 
-	switch (oper) {
+	switch (command) {
 	case 0x90:
-		if (argv[1] > 0)
-			start_note(channel, argv[0], argv[1]);
+		if (op2 > 0)
+			startNote(channel, op1, op2);
 		else
-			stop_note(channel, argv[0]);
+			stopNote(channel, op1);
 		break;
 	case 0xb0:
-		switch (argv[0]) {
+		switch (op1) {
 		case 0x07:
-			hw_channels[channel].volume = argv[1];
+			_channels[channel].volume = op2;
 			break;
 		case 0x0a:
 #ifdef DEBUG
-			warning("[sfx:seq:amiga] ignoring pan 0x%02x event for channel %i", argv[1], channel);
+			warning("[sfx:seq:amiga] ignoring pan 0x%02x event for channel %i", op2, channel);
 #endif
 			break;
 		case 0x7b:
-			stop_channel(channel);
+			stopChannel(channel);
 			break;
 		default:
-			warning("[sfx:seq:amiga] unknown control event 0x%02x", argv[0]);
+			warning("[sfx:seq:amiga] unknown control event 0x%02x", op1);
 		}
 		break;
 	case 0xc0:
-		change_instrument(channel, argv[0]);
+		changeInstrument(channel, op1);
 		break;
 	default:
 		warning("[sfx:seq:amiga] unknown event %02x", command);
 	}
 }
 
-void ami_poll(sfx_softseq_t *self, byte *dest, int len) {
-	int i, j;
-	int16 *buf = (int16 *) dest;
-	// FIXME: memleak
-	int16 *buffers = (int16*)malloc(len * 2 * CHANNELS_NR);
+void MidiDriver_Amiga::generateSamples(int16 *data, int len) {
+	if (len == 0)
+		return;
 
-	memset(buffers, 0, len * 2 * CHANNELS_NR);
-	memset(dest, 0, len * 4);
+	int16 *buffers = (int16*)malloc(len * 2 * kChannels);
 
+	memset(buffers, 0, len * 2 * kChannels);
+
 	/* Generate samples for all notes */
-	for (i = 0; i < CHANNELS_NR; i++)
-		if (channels[i].note >= 0)
-			play_instrument(buffers + i * len, &channels[i], len);
+	for (int i = 0; i < kChannels; i++)
+		if (_voices[i].note >= 0)
+			playInstrument(buffers + i * len, &_voices[i], len);
 
-	for (j = 0; j < len; j++) {
-		int mixedl = 0, mixedr = 0;
+	if (isStereo()) {
+		for (int j = 0; j < len; j++) {
+			int mixedl = 0, mixedr = 0;
 
-		/* Mix and pan */
-		for (i = 0; i < CHANNELS_NR; i++) {
-			mixedl += buffers[i * len + j] * (256 - hw_channels[channels[i].hw_channel].pan);
-			mixedr += buffers[i * len + j] * hw_channels[channels[i].hw_channel].pan;
+			/* Mix and pan */
+			for (int i = 0; i < kChannels; i++) {
+				mixedl += buffers[i * len + j] * (256 - _channels[_voices[i].hw_channel].pan);
+				mixedr += buffers[i * len + j] * _channels[_voices[i].hw_channel].pan;
+			}
+
+			/* Adjust volume */
+			data[2 * j] = mixedl * _masterVolume >> 13;
+			data[2 * j + 1] = mixedr * _masterVolume >> 13;
 		}
+	} else {
+		for (int j = 0; j < len; j++) {
+			int mixed = 0;
 
-		/* Adjust volume */
-		buf[2 * j] = mixedl * volume >> 16;
-		buf[2 * j + 1] = mixedr * volume >> 16;
+			/* Mix */
+			for (int i = 0; i < kChannels; i++)
+				mixed += buffers[i * len + j];
+
+			/* Adjust volume */
+			data[j] = mixed * _masterVolume >> 6;
+		}
 	}
-}
 
-void ami_volume(sfx_softseq_t *self, int new_volume) {
-	volume = new_volume;
+	free(buffers);
 }
 
-void ami_allstop(sfx_softseq_t *self) {
-	int i;
-	for (i = 0; i < HW_CHANNELS_NR; i++)
-		stop_channel(i);
+class MidiPlayer_Amiga : public MidiPlayer {
+public:
+	MidiPlayer_Amiga() { _driver = new MidiDriver_Amiga(g_system->getMixer()); }
+	int getPlayMask() const { return 0x40; }
+	int getPolyphony() const { return MidiDriver_Amiga::kVoices; }
+	bool hasRhythmChannel() const { return false; }
+	void setVolume(byte volume) { static_cast<MidiDriver_Amiga *>(_driver)->setVolume(volume); }
+	void playSwitch(bool play) { static_cast<MidiDriver_Amiga *>(_driver)->playSwitch(play); }
+	void loadInstrument(int idx, byte *data);
+};
+
+MidiPlayer *MidiPlayer_Amiga_create() {
+	return new MidiPlayer_Amiga();
 }
 
-sfx_softseq_t sfx_softseq_amiga = {
-	"amiga",
-	"0.1",
-	ami_set_option,
-	ami_init,
-	ami_exit,
-	ami_volume,
-	ami_event,
-	ami_poll,
-	ami_allstop,
-	NULL,
-	SFX_SEQ_PATCHFILE_NONE,
-	SFX_SEQ_PATCHFILE_NONE,
-	0x40,
-	0, /* No rhythm channel (9) */
-	HW_CHANNELS_NR, /* # of voices */
-	{FREQUENCY, SFX_PCM_STEREO_LR, SFX_PCM_FORMAT_S16_NATIVE}
-};
-
 } // End of namespace Sci


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list