[Scummvm-cvs-logs] SF.net SVN: scummvm:[42186] scummvm/branches/gsoc2009-mods

nolange at users.sourceforge.net nolange at users.sourceforge.net
Mon Jul 6 19:37:55 CEST 2009


Revision: 42186
          http://scummvm.svn.sourceforge.net/scummvm/?rev=42186&view=rev
Author:   nolange
Date:     2009-07-06 17:37:54 +0000 (Mon, 06 Jul 2009)

Log Message:
-----------
Implemented a few commands
Partially implemented queued Events and some related commands

Modified Paths:
--------------
    scummvm/branches/gsoc2009-mods/sound/mods/maxtrax.cpp
    scummvm/branches/gsoc2009-mods/sound/mods/maxtrax.h
    scummvm/branches/gsoc2009-mods/tfmx/mxtxplayer.cpp

Modified: scummvm/branches/gsoc2009-mods/sound/mods/maxtrax.cpp
===================================================================
--- scummvm/branches/gsoc2009-mods/sound/mods/maxtrax.cpp	2009-07-06 17:29:44 UTC (rev 42185)
+++ scummvm/branches/gsoc2009-mods/sound/mods/maxtrax.cpp	2009-07-06 17:37:54 UTC (rev 42186)
@@ -34,7 +34,23 @@
 namespace Audio {
 
 MaxTrax::MaxTrax(int rate, bool stereo)
-	: Paula(stereo, rate, rate/50), _patch(), _scores(), _numScores(), _microtonal() {
+	: Paula(stereo, rate, rate/50), _playerCtx(), _voiceCtx(), _patch(), _channelCtx(), _scores(), _numScores(), _microtonal() {
+		_playerCtx.maxScoreNum = 128;
+		_playerCtx.vBlankFreq = 50;
+		_playerCtx.frameUnit = (uint16)((1000 * (1<<8)) /  _playerCtx.vBlankFreq);
+		_playerCtx.scoreIndex = -1;
+		// glob_CurrentScore = _scoreptr;
+		_playerCtx.volume = 0x64;
+
+		_playerCtx.tempoTime = 0;
+
+		uint32 uinqueId = 0;
+		byte flags = 0;
+
+		uint32 colorClock = kPalSystemClock / 2;
+
+		// init extraChannel
+		// extraChannel. chan_Number = 16, chan_Flags = chan_VoicesActive = 0
 }
 
 MaxTrax::~MaxTrax() {
@@ -44,11 +60,263 @@
 }
 
 void MaxTrax::interrupt() {
+	// a5 - maxtraxm a4 . globaldata
+
+	// test for changes in shared struct and make changes
+	// specifically all used channels get marked altered
+
+	_playerCtx.ticks += _playerCtx.tickUnit;
+	const int32 millis = _playerCtx.ticks >> 8; // d4
+	for (int i = 0; i < ARRAYSIZE(_voiceCtx); ++i) {
+		VoiceContext &voice = _voiceCtx[i]; // a3
+		if (!voice.channel || voice.stopEventCommand >= 0x80)
+			continue;
+		const int channelNo = voice.stopEventParameter;
+		voice.stopEventTime -= (channelNo < kNumChannels) ? _playerCtx.tickUnit : _playerCtx.frameUnit;
+		if (voice.stopEventTime <= 0) {
+			noteOff(_channelCtx[channelNo], voice.stopEventCommand);
+			voice.stopEventCommand = 0xFF;
+		}
+	}
+
+	if (_playerCtx.musicPlaying) {
+		Event *curEvent = _playerCtx.nextEvent;
+		int32 eventTime = _playerCtx.nextEventTime;
+		for (; eventTime <= millis; eventTime += (++curEvent)->startTime) {
+			const byte cmd = curEvent->command;
+			const byte data = curEvent->parameter;
+			const uint16 stopTime = curEvent->stopTime;
+			ChannelContext &channel = _channelCtx[data & 0x0F];
+
+			outPutEvent(*curEvent);
+
+			if (cmd < 0x80) {
+				_playerCtx.addedNote = false;
+				const uint16 vol = (data & 0xF0) >> 1;
+
+				const int8 voiceIndex = noteOn(channel, cmd, vol, kPriorityScore);
+				if (voiceIndex >= 0) {
+					VoiceContext &voice = _voiceCtx[voiceIndex];
+					voice.stopEventCommand = cmd;
+					voice.stopEventParameter = data & 0x0F;
+					voice.stopEventTime = (eventTime + stopTime - millis) << 8;
+				}
+			} else {
+				switch (cmd) {
+				case 0x80:	// TEMPO
+					if ((_playerCtx.tickUnit >> 8) > stopTime) {
+						setTempo(data << 4);
+						_playerCtx.tempoTime = 0;
+					} else {
+						_playerCtx.tempoStart = _playerCtx.tempo;
+						_playerCtx.tempoDelta = (data << 4) - _playerCtx.tempoStart;
+						_playerCtx.tempoTime  = (stopTime << 8);
+						_playerCtx.tempoTicks = 0;
+					}
+					break;
+/*				case 0xA0:	// SPECIAL
+					break;
+				case 0xB0:	// CONTROL
+					// TODO: controlChange((byte)stopTime, (byte)(stopTime >> 8))
+					break;
+*/				case 0xC0:	// PROGRAM
+					channel.patch = &_patch[stopTime & (kNumPatches - 1)];
+					break;
+				case 0xE0:	// BEND
+					channel.pitchBend = ((stopTime & 0x7F00) >> 1) | (stopTime & 0x7f);
+					channel.pitchReal = ((int32)(channel.pitchBendRange << 8) * (channel.pitchBend - (64 << 7))) / (64 << 7);
+					channel.flags |= ChannelContext::kFlagAltered;
+					break;
+				case 0xFF:	// END
+					if (_playerCtx.musicLoop) {
+						// event -1 as it gets increased at the end of the loop
+						curEvent = _scores[_playerCtx.scoreIndex].events - 1;
+						_playerCtx.ticks = 0;
+						eventTime = 0;
+					} else
+						_playerCtx.musicPlaying = false;
+					break;
+				default:
+					debug("Unhandled Command");
+					outPutEvent(*curEvent);
+				}
+			}
+		}
+		_playerCtx.nextEvent = curEvent;
+		_playerCtx.nextEventTime = eventTime;
+
+		// tempoEffect
+		if (_playerCtx.tempoTime) {
+			_playerCtx.tempoTicks += _playerCtx.tickUnit;
+			uint16 newTempo;
+			if (_playerCtx.tempoTicks < _playerCtx.tempoTime) {
+				const uint16 delta = (_playerCtx.tempoTicks * _playerCtx.tempoDelta) / _playerCtx.tempoTime;
+				newTempo = delta;
+			} else {
+				_playerCtx.tempoTime = 0;
+				newTempo = _playerCtx.tempoDelta;
+			}
+			setTempo(_playerCtx.tempoStart + newTempo);
+		}
+
+		// envelopes
+
+	}
+
 }
 
 void MaxTrax::stopMusic() {
 }
 
+bool MaxTrax::doSong(int songIndex, int advance) {
+	if (songIndex < 0 || songIndex >= _numScores)
+		return false;
+	Paula::pausePlay(true);
+	_playerCtx.musicPlaying = false;
+	_playerCtx.musicLoop = false;
+
+	setTempo(_playerCtx.tempoInitial);
+	_playerCtx.nextEvent = _scores[songIndex].events;
+	_playerCtx.scoreIndex = songIndex;
+
+	_playerCtx.musicPlaying = true;
+	Paula::startPaula();
+}
+
+void MaxTrax::killVoice(byte num) {
+	VoiceContext &voice = _voiceCtx[num];
+	--(voice.channel->voicesActive);
+	voice.channel = 0;
+	voice.status = VoiceContext::kStatusFree;
+	voice.flags = 0;
+	voice.priority = 0;
+	voice.uinqueId = 0;
+
+	// "stop" voice, set period to 1, vol to 0
+	Paula::disableChannel(0);
+	Paula::setChannelPeriod(num, 1);
+	Paula::setChannelVolume(num, 0);
+}
+
+int8 MaxTrax::noteOn(ChannelContext &channel, const byte note, uint16 volume, uint16 pri) {
+	if (channel.microtonal >= 0)
+		_microtonal[note % 127] = channel.microtonal;
+	if (!volume)
+		return -1;
+
+	Patch &patch = *channel.patch;
+	if (!patch.samplePtr)
+		return -1;
+	int8 voiceNum = -1;
+	if ((channel.flags & ChannelContext::kFlagMono) != 0  && channel.voicesActive) {
+		for (voiceNum = ARRAYSIZE(_voiceCtx) - 1; voiceNum >= 0 && _voiceCtx[voiceNum].channel != &channel; --voiceNum)
+			;
+		if (voiceNum < 0)
+			return -1;
+
+		VoiceContext &voice = _voiceCtx[voiceNum];
+		if (voice.status >= VoiceContext::kStatusSustain && (channel.flags & ChannelContext::kFlagPortamento) != 0) {
+			// reset previous porta
+			if ((voice.flags & VoiceContext::kFlagPortamento) != 0)
+				voice.baseNote = voice.endNote;
+			voice.portaTicks = 0;
+			voice.flags |= VoiceContext::kFlagPortamento;
+			voice.endNote = channel.lastNote = note;
+			voice.noteVolume = (_playerCtx.handleVolume) ? volume + 1 : 128;
+			goto endFunction;
+		}
+	} else {
+		// TODO:
+		// pickvoice based on channel.isRightChannel
+		// return if no channel found
+		voiceNum = (channel.flags & ChannelContext::kFlagRightChannel) != 0 ? 0 : 1;
+	}
+	assert(voiceNum >= 0 && voiceNum < ARRAYSIZE(_voiceCtx));
+
+	VoiceContext &voice = _voiceCtx[voiceNum];
+	voice.flags = 0;
+	if (voice.channel) {
+		killVoice(voiceNum);
+		voice.flags |= VoiceContext::kFlagStolen;
+	}
+	voice.channel = &channel;
+	voice.patch = &patch;
+	voice.baseNote = note;
+
+	// calc note period
+	voice.priority = (byte)pri;
+	voice.status = VoiceContext::kStatusStart;
+
+	voice.noteVolume = (_playerCtx.handleVolume) ? volume + 1 : 128;
+
+	// ifeq HAS_FULLCHANVOL macro
+	if (channel.volume < 128)
+		voice.noteVolume = (voice.noteVolume * channel.volume) >> 7;
+
+	voice.baseVolume = 0;
+	voice.lastTicks = 0;
+
+	uint16 period = voice.lastPeriod;
+	if (!period)
+		period = 1000;
+
+	int useOctave = 0;
+	// get samplestart for the given octave
+	const int8 *samplePtr = patch.samplePtr + (patch.sampleTotalLen << useOctave) - patch.sampleTotalLen;
+	if (patch.sampleAttackLen) {
+		Paula::setChannelSampleStart(voiceNum, samplePtr);
+		Paula::setChannelSampleLen(voiceNum, patch.sampleAttackLen << useOctave);
+		Paula::setChannelPeriod(voiceNum, period);
+		Paula::setChannelVolume(voiceNum, 0);
+
+		Paula::enableChannel(voiceNum);
+		// wait  for dma-clear
+	}
+
+	if (patch.sampleTotalLen > patch.sampleAttackLen) {
+		Paula::setChannelSampleStart(voiceNum, samplePtr + patch.sampleAttackLen);
+		Paula::setChannelSampleLen(voiceNum, (patch.sampleTotalLen - patch.sampleAttackLen) << useOctave);
+		if (!patch.sampleAttackLen) {
+			// need to enable channel
+			Paula::setChannelPeriod(voiceNum, period);
+			Paula::setChannelVolume(voiceNum, 0);
+
+			Paula::enableChannel(voiceNum);
+		}
+		// another pointless wait for DMA-Clear???
+	}
+
+	channel.voicesActive++;
+	if (&channel < &_channelCtx[kNumChannels]) {
+		const byte flagsSet = ChannelContext::kFlagMono | ChannelContext::kFlagPortamento;
+		if ((channel.flags & flagsSet) == flagsSet && channel.lastNote < 0x80 && channel.lastNote != voice.baseNote) {
+			voice.portaTicks = 0;
+			voice.endNote = voice.baseNote;
+			voice.baseNote = channel.lastNote;
+			voice.flags |= VoiceContext::kFlagPortamento;
+		}
+		if ((channel.flags & ChannelContext::kFlagPortamento) != 0)
+			channel.lastNote = note;
+	}
+endFunction:
+	_playerCtx.addedNote = true;
+	_playerCtx.lastVoice = voiceNum;
+	return voiceNum;
+}
+
+void MaxTrax::noteOff(ChannelContext &channel, const byte note) {
+	VoiceContext &voice = _voiceCtx[_playerCtx.lastVoice];
+	if (channel.voicesActive && voice.channel == &channel && voice.status != VoiceContext::kStatusRelease) {
+		const byte refNote = ((voice.flags & VoiceContext::kFlagPortamento) != 0) ? voice.endNote : voice.baseNote;
+		if (refNote == note) {
+			if ((channel.flags & ChannelContext::kFlagDamper) != 0)
+				voice.flags |= VoiceContext::kFlagDamper;
+			else
+				voice.status = VoiceContext::kStatusRelease;
+		}
+	}
+}
+
 void MaxTrax::freeScores() {
 	if (_scores) {
 		for (int i = 0; i < _numScores; ++i)
@@ -82,7 +350,7 @@
 		warning("Maxtrax: File is not a Maxtrax Module");
 		return false;
 	}
-	_playerCtx.tempo = musicData.readUint16BE();
+	_playerCtx.tempoInitial = musicData.readUint16BE();
 	const uint16 flags = musicData.readUint16BE();
 	_playerCtx.filterOn = (flags & 1) != 0;
 	_playerCtx.handleVolume = (flags & 2) != 0;
@@ -99,8 +367,7 @@
 	const uint16 scoresInFile = musicData.readUint16BE();
 
 	if (loadScores) {
-		const uint16 scoremax = 128; // some variable which is set upon initialisation of player
-		const uint16 tempScores = MIN(scoresInFile, scoremax);
+		const uint16 tempScores = MIN(scoresInFile, _playerCtx.maxScoreNum);
 		debug("#Scores: %d, loading # of scores: %d", scoresInFile, tempScores);
 		Score *curScore =_scores = new Score[tempScores];
 		
@@ -142,10 +409,11 @@
 			curPatch.tune = musicData.readUint16BE();
 			curPatch.volume = musicData.readUint16BE();
 			curPatch.sampleOctaves = musicData.readUint16BE();
-			curPatch.sampleAttack = musicData.readUint32BE();
-			curPatch.sampleSustain = musicData.readUint32BE();
+			curPatch.sampleAttackLen = musicData.readUint32BE();
+			const uint32 sustainLen = musicData.readUint32BE();
+			curPatch.sampleTotalLen = curPatch.sampleAttackLen + sustainLen;
 			// each octave the number of samples doubles.
-			const uint32 totalSamples = (curPatch.sampleAttack + curPatch.sampleSustain) * ((1 << curPatch.sampleOctaves) - 1);
+			const uint32 totalSamples = curPatch.sampleTotalLen * ((1 << curPatch.sampleOctaves) - 1);
 			curPatch.attackLen = musicData.readUint16BE();
 			curPatch.releaseLen = musicData.readUint16BE();
 			const uint32 totalEnvs = curPatch.attackLen + curPatch.releaseLen;

Modified: scummvm/branches/gsoc2009-mods/sound/mods/maxtrax.h
===================================================================
--- scummvm/branches/gsoc2009-mods/sound/mods/maxtrax.h	2009-07-06 17:29:44 UTC (rev 42185)
+++ scummvm/branches/gsoc2009-mods/sound/mods/maxtrax.h	2009-07-06 17:37:54 UTC (rev 42186)
@@ -41,13 +41,42 @@
 private:
 public:
 
-	uint16	_microtonal[128];
+	enum { kNumPatches = 64, kNumVoices = 4, kNumChannels = 16, kNumExtraChannels = 1 };
+	enum { kPriorityScore, kPriorityNote, kPrioritySound };
+	int16	_microtonal[128];
+	struct Event;
 
 	struct PlayerContext {
+		uint16	vBlankFreq;
+		int32	ticks;
+		int32	tickUnit;
+		uint16	frameUnit;
+
+		uint16	maxScoreNum;
 		uint16	tempo;
+		uint16	tempoInitial;
+		uint16	tempoStart;
+		int16	tempoDelta;
+		int32	tempoTime;
+		int32	tempoTicks;
+
+		byte	volume;
+
 		bool	filterOn;
 		bool	handleVolume;
+		bool	musicPlaying;
+		bool	musicLoop;
 
+		int		scoreIndex;
+		Event	*nextEvent;
+		int32	nextEventTime;
+
+
+
+		bool	addedNote;
+		byte	lastVoice;
+		byte	voicesActive;
+
 	} _playerCtx;
 
 	struct Envelope {
@@ -66,10 +95,10 @@
 
 		// this was the SampleData struct in the assembler source
 		int8	*samplePtr;
-		uint32	sampleAttack;
-		uint32	sampleSustain;
+		uint32	sampleTotalLen;
+		uint32	sampleAttackLen;
 		uint16	sampleOctaves;
-	} _patch[64];
+	} _patch[kNumPatches];
 
 	struct Event {
 		uint16	startTime;
@@ -85,14 +114,106 @@
 
 	int _numScores;
 
+	struct ChannelContext {
+		Patch	*patch;
+		uint16	regParamNumber;
 
+		uint16	modulation;
+		uint16	modulationTime;
 
+		int16	microtonal;
+
+		uint16	portamento;
+
+		int16	pitchBend;
+		int16	pitchReal;
+		int8	pitchBendRange;
+
+		uint8	volume;
+		uint8	voicesActive;
+//		uint8	number;
+
+		enum {
+			kFlagRightChannel = 1 << 0,
+			kFlagPortamento = 1 << 1,
+			kFlagDamper = 1 << 2,
+			kFlagMono = 1 << 3,
+			kFlagMicrotonal = 1 << 4,
+			kFlagModVolume = 1 << 5,
+			kFlagAltered = 1 << 6
+		};
+		byte	flags;
+
+		uint8	lastNote;
+		uint8	program;
+
+	} _channelCtx[kNumChannels + kNumExtraChannels];
+
+	struct VoiceContext {
+		ChannelContext *channel;
+		Patch	*patch;
+		Envelope *envelope;
+		uint32	uinqueId;
+		uint32	lastTicks;
+		uint32	tocksLeft;
+		uint32	portaTicks;
+		uint32	incrVolume;
+		uint32	periodOffset;
+		/*ifne FASTSOUND
+			APTR	voice_CurFastIOB			; current fast iob playing
+			APTR	voice_NextFastIOB			; next fast iob to play
+			APTR	voice_FastBuffer			; pointer to buffer area
+		endc*/
+		uint16	envelopeLeft;
+		uint16	noteVolume;
+		uint16	baseVolume;
+		uint16	lastPeriod;
+		byte	baseNote;
+		byte	endNote;
+		byte	number;
+		byte	link;
+		byte	priority;
+		enum {
+			kStatusFree,
+			kStatusHalt,
+			kStatusDecay,
+			kStatusRelease,
+			kStatusSustain,
+			kStatusAttack,
+			kStatusStart
+		};
+		byte	status;
+		enum {
+			kFlagStolen = 1 << 0,
+			kFlagPortamento = 1 << 1,
+			kFlagDamper = 1 << 2,
+			kFlagBlocked = 1 << 3,
+			kFlagRecalc = 1 << 4
+		};
+		byte	flags;
+		byte	lastVolume;
+
+		int32	stopEventTime;
+		byte	stopEventCommand;
+		byte	stopEventParameter;
+	} _voiceCtx[kNumVoices];
+
 	bool load(Common::SeekableReadStream &musicData, bool loadScores = true, bool loadSamples = true);
+	bool doSong(int songIndex, int advance = 0);
 
 	void stopMusic();
 	void freePatches();
 	void freeScores();
 
+	int8 noteOn(ChannelContext &channel, byte note, uint16 volume, uint16 pri);
+	void noteOff(ChannelContext &channel, byte note);
+	void killVoice(byte num);
+
+	void setTempo(const uint16 tempo) {
+		_playerCtx.tickUnit = (int32)(((uint32)(tempo & 0xFFF0) << 8) / (uint16)(5 * _playerCtx.vBlankFreq));
+		// (tempo >> 4) * ((12 * 16) << 8) / (12 * 5 * _playerCtx.vBlankFreq);
+	}
+
 	static void outPutEvent(const Event &ev, int num = -1) {
 		struct {
 			byte cmd;

Modified: scummvm/branches/gsoc2009-mods/tfmx/mxtxplayer.cpp
===================================================================
--- scummvm/branches/gsoc2009-mods/tfmx/mxtxplayer.cpp	2009-07-06 17:29:44 UTC (rev 42185)
+++ scummvm/branches/gsoc2009-mods/tfmx/mxtxplayer.cpp	2009-07-06 17:37:54 UTC (rev 42186)
@@ -30,7 +30,7 @@
 
 	Audio::MaxTrax *mxtxPlay = new Audio::MaxTrax(44100, true);
 
-	if (!strcmp(mdatName, smplName)) {	
+	if (strcmp(mdatName, smplName)) {	
 		SeekableReadStream *sampleIn = sampleNode.createReadStream();
 		if (0 == sampleIn) {
 			debug("Couldnt load file %s", smplName);
@@ -73,6 +73,11 @@
 			if (i + 1 < argc) {
 				param = atoi(argv[++i]);
 				debug( "play Song %02X", param);
+
+				player->doSong(0);
+
+				//player->noteOn(player->_channelCtx[0], 43, 64, 0);
+
 				
 				hasCmd = true;
 			}
@@ -83,6 +88,7 @@
 	}
 
 	if (!hasCmd) {
+
 	}
 
 	int maxsecs = 10 * 60;


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