[Scummvm-cvs-logs] SF.net SVN: scummvm:[33653] scummvm/branches/gsoc2008-tfmx

marwanhilmi at users.sourceforge.net marwanhilmi at users.sourceforge.net
Wed Aug 6 06:16:45 CEST 2008


Revision: 33653
          http://scummvm.svn.sourceforge.net/scummvm/?rev=33653&view=rev
Author:   marwanhilmi
Date:     2008-08-06 04:16:45 +0000 (Wed, 06 Aug 2008)

Log Message:
-----------
Overhauled track update cycle so that it works properly with timing system.
Redesigned structures/variables. 
Added separate loadPattern & loadMacro functions.
Added testMacro function to playback individual macros/notes for testing.

Modified Paths:
--------------
    scummvm/branches/gsoc2008-tfmx/base/main.cpp
    scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.cpp
    scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.h

Modified: scummvm/branches/gsoc2008-tfmx/base/main.cpp
===================================================================
--- scummvm/branches/gsoc2008-tfmx/base/main.cpp	2008-08-06 01:48:46 UTC (rev 33652)
+++ scummvm/branches/gsoc2008-tfmx/base/main.cpp	2008-08-06 04:16:45 UTC (rev 33653)
@@ -291,19 +291,20 @@
 	// the command line params) was read.
 	system.initBackend();
 	
+	//Tfmx test creation.
 	Audio::SoundHandle _handle;
 	Audio::Tfmx _aTfmx;
 	_aTfmx.load();
-	
+	_aTfmx.loadSamples();
+	//_aTfmx.playSong(0);
+	//_aTfmx.testMacro(9);
 
-
 	system.getMixer()->playInputStream( Audio::Mixer::kMusicSoundType, &_handle, &_aTfmx );
 	system.delayMillis( 999999 );
-	
+	//Tfmx test end.
 
 
 /*
-
 	// Unless a game was specified, show the launcher dialog
 	if (0 == ConfMan.getActiveDomain()) {
 		launcherDialog(system);

Modified: scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.cpp
===================================================================
--- scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.cpp	2008-08-06 01:48:46 UTC (rev 33652)
+++ scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.cpp	2008-08-06 04:16:45 UTC (rev 33653)
@@ -38,9 +38,7 @@
 
 Tfmx::Tfmx(bool stereo, int rate, int interruptFreq)
 	: Paula(stereo, rate, interruptFreq) {
-	//blank now
-}
-
+} 
 Tfmx::~Tfmx() {
 	if (_data)
 		delete[] _data;
@@ -49,58 +47,53 @@
 	if (_sampleData)
 		delete[] _sampleData;
 }
+void Tfmx::playSong(uint8 songNumber){
+	if (loadSong(songNumber)) {
+		startPaula();
+		warning("PAULA STARTED.");
+		warning("Playing Song # %d.",songNumber);
+	}
+}
+void Tfmx::stop() {
+	warning("PAULA STOPPED.");
+	stopPaula();
+}
 void Tfmx::loadSamples() {
-	// FIXME: temporary loader - just creates seekablereadstream from c:\mk.smpl
+	//FIXME:: temporary loader - just creates seekablereadstream from c:\mk.smpl
 	Common::SeekableReadStream *stream = NULL;
 	Common::File myfile;
 	myfile.addDefaultDirectory("C:");
 	myfile.open("mk.smpl");
 	stream = myfile.readStream(myfile.size());
 	myfile.close();
-	//FIXME: end temporary loader. normally the seekablereadstream will be function parameter
+	//FIXME:: end temporary loader. normally the seekablereadstream will be function parameter
 
 	_sampleSize = stream->size();
-	_sampleDataU = new uint8[_sampleSize];
+	_sampleData = new int8[_sampleSize];
 	stream->seek(0);
-	stream->read(_sampleDataU, _sampleSize);
-
-	for (uint32 i = 0; i < _sampleSize; i++) {
-		_sampleDataU[i] ^= 0x80;
-	}
-	
-	_sampleData = new int8[_sampleSize];
-	for (uint32 i = 0; i < _sampleSize; i++) {
-		_sampleData[i] = _sampleDataU[i];
-	}
+	stream->read(_sampleData, _sampleSize);
 }
 
-bool Tfmx::loadSamples(Common::SeekableReadStream &stream) {
-	//TODO: Setup loading from input stream
-	return true;
-}
-
 void Tfmx::load() {
-	// FIXME: temporary loader - just creates seekablereadstream from c:\mk.mdat
+	//FIXME:: temporary loader - just creates seekablereadstream from c:\mk.mdat
 	Common::SeekableReadStream *stream = NULL;
 	Common::File myfile;
 	myfile.addDefaultDirectory("C:");
 	myfile.open("mk.mdat");
 	stream = myfile.readStream(myfile.size());
 	myfile.close();
-	//FIXME: end temporary loader. normally the seekablereadstream will be function parameter
+	//FIXME:: end temporary loader. normally the seekablereadstream will be function parameter
 
 	_dataSize = stream->size();
 	_data = new uint8[_dataSize];
 	stream->seek(0);
 	stream->read(_data, _dataSize);
 
+	//TODO:: should implement a check here to read header and ensure TFMXness
 	Common::MemoryReadStream dataStream(_data, _dataSize);
-	//should implement a check here to read header and ensure TFMXness
-
 	dataStream.seek(256);
-	// TODO: should be able to put in one loop??
-	//will also later to modify to dynamically scale arrays for smaller TFMX files
-	//in the case of Monkey Island, it uses 22/32 songs, and 128/128 for patterns/macros
+	//TODO:: Will later modify to dynamically scale arrays for smaller TFMX files
+	//In the case of Monkey Island, it uses 22/32 songs, and 128/128 for patterns/macros
 	for (int i = 0; i < 32; i++) {
 		_songs[i].startPosition = dataStream.readUint16BE();
 	}
@@ -134,83 +127,76 @@
 	for (int i = 0; i < 128; i++) {
 		_macroPointers[i] = dataStream.readUint32BE();
 	}
-	
-	//test
-	loadSamples();
-	playSong(0);
 }
-bool Tfmx::load(Common::SeekableReadStream &stream) {
-	//TODO: Setup loading from input stream
-	return true;
-}
-bool Tfmx::play() {
-	return true;
-}
-void Tfmx::playSong(uint8 songNumber) {
-/* TODO:: Take the role of old readTrackstep function
-Looks up songNumber, then initialize 8-track table.
-Then starts PAULA.
-Then each interrupt, updateTracks() is called and track data is reloaded.
-*/
+
+bool Tfmx::loadSong(uint8 songNumber) {
 	if(songNumber >= 32) {
-		//TODO:: Error. Not a valid index. Maybe index songs from 1-32 rather than 0-31.
+		error("Invalid Song Number.");
+		return false;
 	}
 
-//Read trackstep start/end boundaries of song songNumber
-//Read number of trackstep blocks and lines
 	uint32 startPosition;
 	uint32 endPosition;
 	int32 numBlocks;
-	int32 numLines;
 	startPosition = (_songs[songNumber].startPosition * 16) + _trackTableOffset;
 	endPosition = (_songs[songNumber].endPosition * 16) + _trackTableOffset + 16;
 	numBlocks = (endPosition - startPosition) / 2;
-	numLines = numBlocks / 8;
 
-//Make dataStream MemoryReadStream from _data
-//Make trackSubStream SubReadStream from dataStream bounded by start/end positions
 	Common::MemoryReadStream dataStream(_data, _dataSize);
 	Common::SeekableSubReadStream trackSubStream(&dataStream, startPosition, endPosition);
 
-//Load trackSubStream into _trackData[] array
-	_trackData = new uint16[numBlocks];
+	_trackLength = numBlocks;
 	_trackCount = 0;
-	_trackLength = numBlocks;
-	_tempo = _songs[songNumber].tempoValue; //TODO:: Need to setup for the case when tempoValue < 15
+	_trackData = new uint16[_trackLength];
+	_tempo = _songs[songNumber].tempoValue; 
 	for (int i = 0; i < numBlocks; i++) {
 		_trackData[i] = trackSubStream.readUint16BE();
 	}
 
-//Initialize 8 tracks and get ready for update
-	for (int i = 0; i < 8; i++) { 
-			_tracks[i].data = 0;
-			_tracks[i].updateFlag = true; 
-			_tracks[i].activeFlag = true;
-			_tracks[i].pattern.data = 0;
-			_tracks[i].pattern.number = 0;
-			_tracks[i].pattern.transpose = 0;
-			_tracks[i].pattern.wait = 0;
-			_tracks[i].pattern.newFlag = true;
-			_tracks[i].pattern.jumpFlag = false;
-			_tracks[i].pattern.returnFlag = false;
-			_tracks[i].pattern.count = 0;
-			_tracks[i].pattern.offset = 0;
+	//INITIALIZE TRACKS
+	for (int track = 0; track < 8; track++) { 
+		_trackAdvance = true;
+		_trackEnd = false;
+		_macroTest = false;
 
-			_tracks[i].sample.length = 0;
-			_tracks[i].sample.offset = 0;
-			_tracks[i].sample.onFlag = true;
+		//initialize Track objects
+		_tracks[track].data = 0;
+		_tracks[track].trackOn = true;
+		_tracks[track].patternOn = false;
+		_tracks[track].macroOn = false;
+		_tracks[track].patternNumber = 0xFF; //obviously impossible pattern number
 
-			_tracks[i].macro.data = 0;
-			_tracks[i].macro.count = 0;
-			_tracks[i].macro.newFlag = true;
-			
+		//initialize Pattern objects
+		_tracks[track].activePattern.data = 0;
+		_tracks[track].activePattern.patternCount = 0;
+		_tracks[track].activePattern.patternLength = 0;
+		_tracks[track].activePattern.patternWait = 0;
+		_tracks[track].activePattern.patternTranspose = 0;
+		_tracks[track].activePattern.newPattern = false;
+
+		//initialize Macro objects
+		_tracks[track].activeMacro.data = 0;
+		_tracks[track].activeMacro.macroCount = 0;
+		_tracks[track].activeMacro.macroLength = 0;
+		_tracks[track].activeMacro.macroWait = 0;
+		_tracks[track].activeMacro.noteNumber = 0;
+		_tracks[track].activeMacro.notePeriod = 0;
+		_tracks[track].activeMacro.noteVolume = 0;
+		_tracks[track].activeMacro.noteChannel = 0;
+		_tracks[track].activeMacro.noteType = 0;
+		_tracks[track].activeMacro.noteWait = 0;
 	}
 
-	for (int i = 0; i < 4; i++) {
-		_channels[i].period = 0;
-		_channels[i].volume = 0;
+	//INITIALIZE CHANNELS
+	for (int channel = 0; channel < 4; channel++) {
+		_channels[channel].period = 0;
+		_channels[channel].volume = 0;
+		_channels[channel].sampleOffset = 0;
+		_channels[channel].sampleLength = 0;
+	    _channels[channel].sampleOn = false;
 	}
 
+	//SET INTERRUPT FREQUENCY
 	if (_tempo >= 0x10) {
 	setInterruptFreq( (int)( getRate() / (_tempo * 0.4)));
 	}
@@ -218,31 +204,33 @@
 	setInterruptFreq( (int)( getRate() / (1 / _tempo * 24)));
 	}
 
-	startPaula();
-	// and trigger updateTrackstep() cycle, called at each interrupt
-
-/*//Test loop. Update and dump to console i times.
-	for(int i = 0; i < 4; i++) {
-	updateTrackstep();
-	dumpTracks();
-	}
-*/
+	//setInterruptFreq( (int)( getRate() / 10) );
+	return true;
 }
 void Tfmx::updateTrackstep() {
+	//If _trackEnd, stop Paula and terminate update.
+	if (_trackEnd) {
+		stop();
+		return;
+	}
 
-	for (int i = 0; i < 8; i++) {
-		if (_tracks[i].updateFlag && _trackCount <= _trackLength) {
-			_tracks[i].updateFlag = false;
-			_tracks[i].activeFlag = true;
-			_tracks[i].data = _trackData[_trackCount];
-		}
-		_trackCount++;
+	//Load in line of trackstep commands.
+	for (int track = 0; track < 8; track++) {
+			_tracks[track].trackOn = true;
+			_tracks[track].data = _trackData[_trackCount];
+			_trackCount++;
 	}
 
+	//check if you reached the last trackstep block
+	if (_trackCount >= _trackLength) {
+		_trackEnd = true;
+	}
+
+	//proccess trackstep commands
 	if (_tracks[0].data == 61438) { //you have a line of trackstep commands
 		switch (_tracks[1].data) {
 		case 0: // EFFE0000 Stops player.
-			stopPlayer();
+			stop();
 			break;
 		case 1: //EFFE0001: NOT USED IN MI.
 			//Plays a selection.
@@ -262,103 +250,87 @@
 		case 4: //EFFE0004 Volume slide
 			//uint16 volumeDivisor = tracks[2];    
 			//uint16 volumeTarget = tracks[3];     
-			volumeSlide(); //TODO: will accept volumeDivisor & volumeTarget as parameters
+			//volumeSlide(); //TODO: will accept volumeDivisor & volumeTarget as parameters
 			break;
 		default: //Non-existant command
 			//TODO: error
 			break;
-		} // end switch _tracks[1].data
-
-		for (int i = 0; i < 8; i++) {
-			_tracks[i].updateFlag = true;
-		} // end for updateFlag = true loop
+		} // end switch 
 	} // end if track[].data = command
 
 	else { //each tracks[].data is 16 bits; first 8 bits is pattern number, second 8 bits is transpose number
-		for (int i = 0; i < 8; i++) {
-			if (_tracks[i].data == 65280) {    //kill track command
-				_tracks[i].activeFlag = false; 
-				_tracks[i].updateFlag = true; 
+		for (int track = 0; track < 8; track++) {
+			
+			if (_tracks[track].data == 0xFF00) {    //kill track command
+				_tracks[track].trackOn = false; 
 			}
 				
-			if (_tracks[i].activeFlag) {
-				if (_tracks[i].pattern.newFlag) {
-					_tracks[i].pattern.number = _tracks[i].data >> 8;
-					_tracks[i].pattern.transpose = _tracks[i].data & 0x00FF;
-
-					if (_tracks[i].pattern.jumpFlag) {
-						_tracks[i].pattern.number = _tracks[i].pattern.saveNumber1;
-						_tracks[i].pattern.transpose = 0;
-					}
-
-					if (_tracks[i].pattern.returnFlag) {
-						_tracks[i].pattern.number = _tracks[i].pattern.saveNumber2;
-						_tracks[i].pattern.transpose = 0;
-					}
-				}
-				if (_tracks[i].pattern.wait == 0) {
-				updatePattern(i);			
-				}
-				else {
-					_tracks[i].pattern.wait--;
-				}
+			if (_tracks[track].trackOn) {	
+				_tracks[track].patternNumber = _tracks[track].data >> 8;
+				_tracks[track].activePattern.patternTranspose = _tracks[track].data & 0x00FF;
+				_tracks[track].patternOn = true;
+				loadPattern( track, (_tracks[track].data >> 8) );
 			}
-		}//end pattern loop
+		}
 	}//end else
 }
-void Tfmx::updatePattern(uint8 trackNumber) {
-//IF it is a NEW pattern being loaded, then initialize pattern.data[] table
-	if (_tracks[trackNumber].pattern.newFlag) { 
-		_tracks[trackNumber].pattern.newFlag = false;
-		uint32 startPosition;
-		uint32 endPosition;
-		int32 numCommands;		//number of longword pattern commands or notes
-		startPosition = _patternPointers[_tracks[trackNumber].pattern.number] + _tracks[trackNumber].pattern.offset;
-		endPosition = _patternPointers[_tracks[trackNumber].pattern.number + 1];
-		numCommands = (endPosition - startPosition) / 4;
-		_tracks[trackNumber].pattern.offset = 0;
-		_tracks[trackNumber].pattern.count = 0;
-		_tracks[trackNumber].pattern.length = numCommands;
+void Tfmx::loadPattern(uint8 trackNumber, uint8 patternNumber) {
+	uint32 startPosition;
+	uint32 endPosition;
+	int32 numCommands;		
+	startPosition = _patternPointers[patternNumber]; //+ _tracks[trackNumber].pattern.offset;
+	endPosition = _patternPointers[patternNumber + 1];
+	numCommands = (endPosition - startPosition) / 4;
+	//_tracks[trackNumber].activePattern.offset = 0;
+	_tracks[trackNumber].activePattern.patternCount = 0;
+	_tracks[trackNumber].activePattern.patternLength = numCommands;
 
-		Common::MemoryReadStream dataStream(_data, _dataSize);
-		Common::SeekableSubReadStream patternSubStream(&dataStream, startPosition, endPosition);
+	Common::MemoryReadStream dataStream(_data, _dataSize);
+	Common::SeekableSubReadStream patternSubStream(&dataStream, startPosition, endPosition);
 
-		_tracks[trackNumber].pattern.data = new uint32[numCommands];
-		for (int i = 0; i < numCommands; i++) {
-			_tracks[trackNumber].pattern.data[i] = patternSubStream.readUint32BE();
-		}
+	_tracks[trackNumber].activePattern.data = new uint32[numCommands];
+	for (int i = 0; i < numCommands; i++) {
+		_tracks[trackNumber].activePattern.data[i] = patternSubStream.readUint32BE();
 	}
-	//MASKING for uint32 pattern data
-	uint8 byte1 = *(_tracks[trackNumber].pattern.data) & 0xFF000000 >> 24;
-	uint8 byte2 = *(_tracks[trackNumber].pattern.data) & 0x00FF0000 >> 16;
-	uint8 byte3 = *(_tracks[trackNumber].pattern.data) & 0x0000FF00 >> 8;
-	uint8 byte4 = *(_tracks[trackNumber].pattern.data) & 0x000000FF;
-	uint16 bytes34 = *(_tracks[trackNumber].pattern.data) & 0x0000FFFF;
+}
+void Tfmx::updatePattern(uint8 trackNumber) {
+	if (_tracks[trackNumber].activePattern.patternWait != 0) {
+		_tracks[trackNumber].activePattern.patternWait--;
+		return;
+	}
 
+	uint8 byte1 = ( *(_tracks[trackNumber].activePattern.data) & 0xFF000000 ) >> 24;
+	uint8 byte2 = ( *(_tracks[trackNumber].activePattern.data) & 0x00FF0000 ) >> 16;
+	uint8 byte3 = ( *(_tracks[trackNumber].activePattern.data) & 0x0000FF00 ) >> 8;
+	uint8 byte4 = ( *(_tracks[trackNumber].activePattern.data) & 0x000000FF );
+	uint16 bytes34 = ( *(_tracks[trackNumber].activePattern.data) & 0x0000FFFF );
+
 	if (byte1 >= 0xF0) {
 		switch (byte1) {
 		case 0xF0: //end pattern + advance track
 			//end pattern? also needs to know the track this is playing on
-			_tracks[trackNumber].updateFlag = true; 
-			_tracks[trackNumber].pattern.newFlag = true;
+			_tracks[trackNumber].patternOn = false; 
+			//_trackAdvance = true;
 			break;
 		case 0xF1: //repeat block/loop
 			break;
 		case 0xF2: //pattern jump
 			//offset of byte34
+			/*
 			_tracks[trackNumber].pattern.saveNumber1 = byte2;
 			_tracks[trackNumber].pattern.offset = bytes34;
 			_tracks[trackNumber].pattern.jumpFlag = true;
 			_tracks[trackNumber].pattern.newFlag = true;
-			
+			*/
 			break;
 		case 0xF3:
 			//waits byte2 + 1 jiffies
-			//_tracks[trackNumber].pattern.wait = byte2 + 1;
+			_tracks[trackNumber].activePattern.patternWait = (byte2 + 1);
 			break;
 		case 0xF4: //kills track until new pointer is loaded
 			//need to know track this pattern is on, then needs to stop reading proceeding cmds
-			_tracks[trackNumber].activeFlag = false;
+			_tracks[trackNumber].patternOn = false; 
+			_tracks[trackNumber].trackOn = false;
 			break;
 		case 0xF5: //Key up
 			break;
@@ -367,15 +339,19 @@
 		case 0xF7: //Envelope
 			break;
 		case 0xF8: //same as 0xF2 except it saves current pattern address for return
+			/*
 			_tracks[trackNumber].pattern.saveNumber1 = byte2;
 			_tracks[trackNumber].pattern.saveNumber2 = _tracks[trackNumber].pattern.number;
 			_tracks[trackNumber].pattern.offset = (_tracks[trackNumber].pattern.count) * 32;
 			_tracks[trackNumber].pattern.jumpFlag = true;
 			_tracks[trackNumber].pattern.newFlag = true;
+			*/
 			break;
 		case 0xF9: //return to saved address ; ie reload oldPattern
+			/*
 			_tracks[trackNumber].pattern.returnFlag = true;
 			_tracks[trackNumber].pattern.newFlag = true;		
+			*/
 			break;
 		case 0xFA: //master volume slide
 			break;
@@ -387,7 +363,8 @@
 			//locks the channel specified in byte2 for bytes34 ticks
 			break;
 		case 0xFE: //disable track, same as F4 apparently
-			_tracks[trackNumber].activeFlag = false;
+			_tracks[trackNumber].patternOn = false; 
+			_tracks[trackNumber].trackOn = false;
 			break;
 		case 0xFF: //Do nothing - advance pattern pointer
 			break;
@@ -395,93 +372,106 @@
 			//invalid cmd
 			break;
 		} // end switch
-	} // end if data = command
+	} 
 	
 	else { 
-		_tracks[trackNumber].pattern.note.noteNumber = byte1;
-		_tracks[trackNumber].pattern.note.macroNumber = byte2;
-		_tracks[trackNumber].pattern.note.channelNumber = (byte3 & 0xF0) >> 4;
-		_tracks[trackNumber].pattern.note.volume = (byte3 & 0x0F);
-		_tracks[trackNumber].pattern.note.wait = byte4; //should set pattern wait to this	
-		updateNote(trackNumber);
-		doMacros(trackNumber);
-	}
+		if (!_tracks[trackNumber].macroOn) {
+			_tracks[trackNumber].macroNumber = byte2;
+			loadMacro( trackNumber, (_tracks[trackNumber].macroNumber) );
+			_tracks[trackNumber].macroOn = true; //set to false again when macro terminates
+			_tracks[trackNumber].activeMacro.noteNumber = byte1;
+			_tracks[trackNumber].activeMacro.noteVolume = (byte3 & 0xF0) >> 4;
+			_tracks[trackNumber].activeMacro.noteChannel = (byte3 & 0x0F);
+			_tracks[trackNumber].activeMacro.noteWait = byte4; 	
+			_tracks[trackNumber].activeMacro.notePeriod = periods[_tracks[trackNumber].activeMacro.noteNumber & 0x3F];
+		}
 
-	_tracks[trackNumber].pattern.data++;
-	_tracks[trackNumber].pattern.count++;
+		else {
+			while (_tracks[trackNumber].activeMacro.macroWait == 0 && (_tracks[trackNumber].macroOn == true) ) {
+				doMacro(trackNumber);
+			}
+		}
 
-	if (_tracks[trackNumber].pattern.count == _tracks[trackNumber].pattern.length) {
-		_tracks[trackNumber].pattern.newFlag = true;
+		if (_tracks[trackNumber].activeMacro.macroWait != 0) {
+		_tracks[trackNumber].activeMacro.macroWait--;
+		}
+	}//END ELSE
+
+	//ADVANCE PATTERN COUNT, INCREASE COUNT
+	//IF MACRO IS ON, WAIT TO ADVANCE
+	if (!_tracks[trackNumber].macroOn) {
+		_tracks[trackNumber].activePattern.data++;
+		_tracks[trackNumber].activePattern.patternCount++;
 	}
+	//IF THE END IS REACHED, TURN PATTERN OFF
+	if (_tracks[trackNumber].activePattern.patternCount == _tracks[trackNumber].activePattern.patternLength) {
+		_tracks[trackNumber].patternOn = false;
+	}
 }
-
-void Tfmx::updateNote(uint8 trackNumber) {
-	//TODO: Should determine the type of note (3 kinds) so it can apply effects
-	//00 & 01 : detune
-	//10 : wait
-	//11 : portamento
-	
-	//quick solution
-	_channels[_tracks[trackNumber].pattern.note.channelNumber].period = periods[_tracks[trackNumber].pattern.note.noteNumber & 0x3F];
-	_channels[_tracks[trackNumber].pattern.note.channelNumber].volume = _tracks[trackNumber].pattern.note.volume;
-}
-void Tfmx::doMacros(uint8 trackNumber) {
-	if (_tracks[trackNumber].macro.newFlag) {
+void Tfmx::loadMacro(uint8 trackNumber, uint8 macroNumber){
 	uint32 startPosition;
 	uint32 endPosition;
-	int32 numCommands;		//number of longword pattern commands or notes
-	startPosition = _macroPointers[_tracks[trackNumber].pattern.note.macroNumber]; // -> might need this for jump commands: + _tracks[trackNumber].pattern.note.macroOffset;
-	endPosition = _macroPointers[_tracks[trackNumber].pattern.note.macroNumber + 1];
-	numCommands = (endPosition - startPosition) / 4; //long word commands also - so 4 per line
-	_tracks[trackNumber].macro.newFlag = false;
-	_tracks[trackNumber].macro.length = numCommands;
-	_tracks[trackNumber].macro.count = 0;
+	int32 numCommands;		
+	startPosition = _macroPointers[macroNumber]; //TODO:: Need to add offset for jump commands
+	endPosition = _macroPointers[macroNumber + 1];
+	numCommands = (endPosition - startPosition) / 4; 
 
+	_tracks[trackNumber].activeMacro.macroCount = 0;
+	_tracks[trackNumber].activeMacro.macroLength = numCommands;
+
 	Common::MemoryReadStream dataStream(_data, _dataSize);
 	Common::SeekableSubReadStream macroSubStream(&dataStream, startPosition, endPosition);
 
-	_tracks[trackNumber].macro.data = new uint32[numCommands];
+	_tracks[trackNumber].activeMacro.data = new uint32[numCommands];
 	for (int i = 0; i < numCommands; i++) {
-		_tracks[trackNumber].macro.data[i] = macroSubStream.readUint32BE();
+		_tracks[trackNumber].activeMacro.data[i] = macroSubStream.readUint32BE();
 	}
-	}
+}
+void Tfmx::doMacro(uint8 trackNumber) {
+	uint8 byte1 = ( *(_tracks[trackNumber].activeMacro.data) ) >> 24;
+	uint8 byte2 = ( *(_tracks[trackNumber].activeMacro.data) & 0x00FF0000 ) >> 16;
+	uint8 byte3 = ( *(_tracks[trackNumber].activeMacro.data) & 0x0000FF00 ) >> 8;
+	uint8 byte4 = ( *(_tracks[trackNumber].activeMacro.data) & 0x000000FF );
+	uint8 myChannel = _tracks[trackNumber].activeMacro.noteChannel;
 	
-	//MASKING for uint32 pattern data 
-	//First byte is OPCODE
-	//TODO: Might only need to read OPCODE initially and then use other masks as needed in each case
-	uint8 byte1 = *(_tracks[trackNumber].macro.data) >> 24;
-	uint8 byte2 = *(_tracks[trackNumber].macro.data) & 0x00FF0000 >> 16;
-	uint8 byte3 = *(_tracks[trackNumber].macro.data) & 0x0000FF00 >> 8;
-	uint8 byte4 = *(_tracks[trackNumber].macro.data) & 0x000000FF;
-	//TODO: IMPORTANT CASES TO SETUP FOR SAMPLE LOADING
-	//00 : DMA Reset
-	//01 : DMA Start
-	//02 : Sample Offset
-	//03 : Sample Length
-	//04 : Wait
-	//07 : End Macro
-	//13 : DMA Off
-
 	switch (byte1) {
-	case 0x00: //DMAoff reset
-		_tracks[trackNumber].sample.onFlag = false;
-		_tracks[trackNumber].sample.offset = 0;
-		_tracks[trackNumber].sample.length = 0;
+	case 0x00: //DMAoff reset + CLEARS EFFECTS
+		_channels[myChannel].sampleOn = false;
+		_channels[myChannel].sampleOffset = 0;
+		_channels[myChannel].sampleLength = 0;
 		break;
 	case 0x01:
-		_tracks[trackNumber].sample.onFlag = true;
+		_channels[myChannel].sampleOn = true;
+		/*
+		setChannelPeriod(myChannel,_channels[myChannel].period);
+		setChannelVolume(myChannel,_channels[myChannel].volume);
+		setChannelData(myChannel, _sampleData + _channels[myChannel].sampleOffset, 0, _channels[myChannel].sampleLength, 0);
+		*/
+		//_tracks[trackNumber].activeMacro.macroWait = 1;
 		break;
 	case 0x02: //set sample offset
-		_tracks[trackNumber].sample.offset = *(_tracks[trackNumber].macro.data) & 0x00FFFFFF;
+		_channels[myChannel].sampleOffset = *(_tracks[trackNumber].activeMacro.data) & 0x00FFFFFF;
 		break;
 	case 0x03: //set sample length
-		_tracks[trackNumber].sample.length = ( *(_tracks[trackNumber].macro.data) & 0x0000FFFF ) * 2;
+		_channels[myChannel].sampleLength = ( *(_tracks[trackNumber].activeMacro.data) & 0x0000FFFF ) * 2;
 		break;
+	case 0x04: //wait
+		if ( (*(_tracks[trackNumber].activeMacro.data) & 0x0000FFFF) == 0 ) {
+			_tracks[trackNumber].activeMacro.macroWait = 1;
+		}
+		else {
+			_tracks[trackNumber].activeMacro.macroWait = ( *(_tracks[trackNumber].activeMacro.data) & 0x0000FFFF );
+		}
+		break;
 	case 0x07:
-		_tracks[trackNumber].macro.newFlag = true;
+		_channels[myChannel].sampleOn = false; 
+		_tracks[trackNumber].macroOn = false;
 		break;
+	case 0x13: //DMA OFF BUT DOESNT CLEAR EFFECTS
+		_channels[myChannel].sampleOn = false;
+		break;
 	case 0x0D: //add volume to channel;.
-		if (byte3 != 0xFE) {
+		/*if (byte3 != 0xFE) {
 			uint8 channelNumber = _tracks[trackNumber].pattern.note.channelNumber;
 			_channels[channelNumber].volume = (_tracks[trackNumber].pattern.note.volume * 3) + byte4;
 
@@ -490,52 +480,91 @@
 			}
 			break;
 		}
+		*/
 		break;
 	case 0x0E: //set volume
-		if (byte3 != 0xFE) {
+		/*if (byte3 != 0xFE) {
 			uint8 channelNumber = _tracks[trackNumber].pattern.note.channelNumber;
 			_channels[channelNumber].volume = byte4;
 			break;
 		}
+		*/
 		break;
-
-
+	default:
+		break;
 	}//end switch
 
-	_tracks[trackNumber].macro.count++;
-	_tracks[trackNumber].macro.data++;
+	_channels[myChannel].period = _tracks[trackNumber].activeMacro.notePeriod;
+	_channels[myChannel].volume = _tracks[trackNumber].activeMacro.noteVolume;
+	_channels[myChannel].volume = 0x40;
 
-	if (_tracks[trackNumber].macro.count == _tracks[trackNumber].macro.length) {
-		_tracks[trackNumber].macro.newFlag = true;
+	_tracks[trackNumber].activeMacro.data++;
+	_tracks[trackNumber].activeMacro.macroCount++;
+	
+	if (_tracks[trackNumber].activeMacro.macroCount == _tracks[trackNumber].activeMacro.macroLength) {
+		_tracks[trackNumber].macroOn = false;
+		//_channels[myChannel].sampleOn = false;
 	}
 }
+void Tfmx::testMacro(uint8 macroNumber) {
+	_macroTest = true;
+	loadMacro(0, macroNumber);
+	_tracks[0].macroOn = true; //set to false again when macro terminates
+	_tracks[0].activeMacro.noteNumber = 0x1E;  //middle C
+	_tracks[0].activeMacro.noteVolume = 0x0F;
+	_tracks[0].activeMacro.noteChannel = 0;
+	_tracks[0].activeMacro.noteWait = 0; 
+	_tracks[0].activeMacro.notePeriod = periods[0x1E & 0x3F];
+}
 void Tfmx::interrupt(void) {
+	if (!_macroTest) { //Would be the normal case unless macro testing is on.
 
-	updateTrackstep(); 
+		if (_trackAdvance) {
+			updateTrackstep();
+		}
 
-	for (int i = 0; i < 4; i++)
-	{
-		setChannelPeriod(i,_channels[i].period);
-		setChannelVolume(i,_channels[i].volume);
-		if (_tracks[i].sample.onFlag) {
-			setChannelData(i, _sampleData + _tracks[i].sample.offset, 0, _tracks[i].sample.length, 0);
+		//CYCLE THROUGH THE 8 TRACKS TO FIND WHICH PATTERNS ARE ON AND THEN UPDATE
+		//WILL SKIP UPDATES FOR A WAIT
+		for (int track = 0; track < 8; track++) {
+			if (_tracks[track].patternOn && _tracks[track].trackOn) {
+					updatePattern(track);
+			}
+		}
+
+		for (int i = 0; i < 4; i++)
+		{
+			setChannelPeriod(i,_channels[i].period);
+			setChannelVolume(i,_channels[i].volume);
+			if (_channels[i].sampleOn) {
+				setChannelData(i, _sampleData + _channels[i].sampleOffset, 0, _channels[i].sampleLength, 0);
+			}	
+		}
+		
+		//CHECK IF PATTERNS ARE ON: IF SO, TRACK ADVANCE IS FALSE
+		for (int track = 0; track < 8; track++) {
+			if (_tracks[track].patternOn) {
+				_trackAdvance = false;
+				break;
+			}
+			else {
+				_trackAdvance = true;
+			}
+		}
+
+	}//IF MACRO TEST = FALSE
+
+	else { //MACRO TEST IS ON
+		while (_tracks[0].activeMacro.macroWait == 0 && (_tracks[0].macroOn == true) ) {
+					doMacro(0);
+		}//END WHILE
+		setChannelPeriod(0,_channels[0].period);
+		setChannelVolume(0,_channels[0].volume);
+		if (_channels[0].sampleOn) {
+			setChannelData(0, _sampleData + _channels[0].sampleOffset, 0, _channels[0].sampleLength, 0);
 		}	
-	}
-}
-void Tfmx::stopPlayer() {
-	for(int i = 0; i < 8; i++) {
-	_tracks[i].activeFlag = false;
-	}
-	stopPaula();
-}
-void Tfmx::dumpTracks() {
-	for (int i = 0; i < 8; i++) {
-		warning("TRACK # %d", i);
-		warning("Data::: %X", _tracks[i].data);
 
-		if(_tracks[i].pattern.data)  {
-		warning("PATTERN # %X", _tracks[i].pattern.number);
-		warning("Data::: %X", *(_tracks[i].pattern.data - 1) );
+		if (_tracks[0].activeMacro.macroWait != 0) {
+		_tracks[0].activeMacro.macroWait--;
 		}
 	}
 }
@@ -543,6 +572,8 @@
 	//Safe to ignore for now
 }
 void Tfmx::volumeSlide() {
+	//Safe to ignore for now
 }
+
 } // End of namespace Audio
 

Modified: scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.h
===================================================================
--- scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.h	2008-08-06 01:48:46 UTC (rev 33652)
+++ scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.h	2008-08-06 04:16:45 UTC (rev 33653)
@@ -34,29 +34,32 @@
 
 class Tfmx : public Paula {
 public:
-		//constructor with appropiate default values and initialization
+		//TODO:: Ctor + Dtor might need some repair/cleanup
 		Tfmx(bool stereo = false, int rate = 44100, int interruptFreq = 0);
 		~Tfmx();
-
-		//temporary loader function, will be moved to one below
+	
+		//TODO:: Will change to bool load(Common::SeekableReadStream &stream) 
+		//TODO:: Will change to bool loadSamples(Common::SeekableReadStream &stream)
 		void load();
 		void loadSamples();
 
-		//load function loads file from stream, performs checks, initializes some variables
-		bool load(Common::SeekableReadStream &stream);
-		bool loadSamples(Common::SeekableReadStream &stream);
-
-		//generic function to start playback
-		//will likely change to playSong(uint8 songNumber)
-		bool play();
+		//After the TFMX file is loaded, you chose which song to playback.
+		//The song will end automatically or when you call stop().
+		void playSong(uint8 songNumber);
+		void stop();
 		
+		//DEBUGGING FUNCTION:: Temporary function to test individual macros for playback
+		void testMacro(uint8 macroNumber);
+	
 protected:
+		//DEBUGGING::
+		bool _macroTest;
+	
 		//uint8 stream for whole MDAT file
 		uint8 *_data;      
 		uint32 _dataSize; 
 
-		//uint8 stream for sample data from SMPL file
-		uint8 *_sampleDataU;
+		//uint8 stream for whole SMPL file
 		int8 *_sampleData;
 		uint32 _sampleSize;
 
@@ -65,17 +68,18 @@
 		uint32 _patternTableOffset;
 		uint32 _macroTableOffset;
 
-		//addresses of patterns and macros in MDAT file
+		//addresses of patterns and macros from MDAT file
 		uint32 _patternPointers[128];
 		uint32 _macroPointers[128];  
 
 		//uint16 stream for current song trackstep
-		//need count and length to keep running tally
 		uint16 *_trackData;
 		uint32 _trackCount;
 		uint32 _trackLength;
+		bool _trackAdvance;
+		bool _trackEnd;
 		uint16 _tempo; //current value for tempo
-
+		
 		//note table
 		static const uint16 periods[]; 
 
@@ -86,95 +90,78 @@
 			uint16 tempoValue;
 		}_songs[32];
 		
-		//Note structure
-		//Will eliminate after revision and read these properties directly 
-		//into Macro structure and Channel structure
-		struct Note {
-			uint8 noteNumber;
-			uint8 macroNumber;
-			uint8 channelNumber;
-			uint8 volume;
-			uint8 wait;
-			uint8 type; //3 types of notes
-		};
-
-		//Pattern structure; contains note
+		//Pattern structure
 		struct Pattern {
 			uint32 *data;
-			uint8 number;
-			uint8 transpose;
-			uint32 count;
-			bool newFlag;
-			bool jumpFlag;
-			bool returnFlag;
-			Note note;
-			uint8 wait;
-			uint16 offset;
-			uint8 saveNumber1;
-			uint8 saveNumber2;
-			uint32 length;
+			uint32 patternCount;
+			uint32 patternLength;
+			uint8 patternWait;
+			uint8 patternTranspose;
+			bool newPattern;
+		//	bool patternEnd;
+		//	uint16 offset;
+		//	uint8 saveNumber1;
+		//	uint8 saveNumber2;
+		//	bool jumpFlag;
+		//	bool returnFlag;
 		//	bool loopFlag;
 		//	uint16 loopCount;
 		};
 
-		//Macro structure for macro data; very similiar to pattern data
+		//Macro structure
 		struct Macro {
 			uint32 *data;
-			uint32 count;
-			uint32 length;
-			bool newFlag;
-			//uint8 number;
-			//will need some other properties here
+			uint32 macroCount;
+			uint32 macroLength;
+			uint16 macroWait; //internal wait
+			//external note stuff here
+			uint8 noteNumber;
+			uint8 notePeriod;
+			uint8 noteVolume;
+			uint8 noteChannel;
+			uint8 noteType;
+			uint8 noteWait;  //external wait
 		};
 
-		//Sample structure; initialized by macro commands
-		struct Sample {
-			//int8 *data;
-			uint32 offset; //offset into sample file
-			uint32 length; //length of sample /number of bytes
-			bool onFlag;
-		};
-
-		//Track structure; contains pattern
-		//Setup as 8-track array, each track gets updated on interrupt
+		//Track structure
 		struct Track {
 			uint16 data;
-			bool updateFlag;
-			bool activeFlag;
-			Pattern pattern;
-			Macro macro;
-			Sample sample;
+			bool trackOn;
+			bool patternOn;
+			bool macroOn;
+			uint8 patternNumber;
+			uint8 macroNumber;
+			Pattern activePattern;
+			Macro activeMacro;
 		//	uint16 volume;
 		//	bool loopFlag;
 		//	uint16 loopCount;
 		}_tracks[8];
 		
 		//Channel structure
-		//TODO: Need to setup the nessecary information in channel to pass to PAULA via interrupt()
 		struct Channel {
 			uint8 period;
 			int8 volume;
+			uint32 sampleOffset;
+			uint32 sampleLength;
+			bool sampleOn;
 		}_channels[4];
 
-		//functions used in playback (in order by relationship)
-		void playSong(uint8 songNumber);
+		//PAULA Interrupt override
+		virtual void interrupt(void);
+
+		bool loadSong(uint8 songNumber);
 		void updateTrackstep();
+		void loadPattern(uint8 trackNumber, uint8 patternNumber);
 		void updatePattern(uint8 trackNumber);
-		void updateNote(uint8 trackNumber);
-		void doMacros(uint8 trackNumber);
+		void loadMacro(uint8 trackNumber, uint8 macroNumber);
+		void doMacro(uint8 trackNumber);
 		
-		//trackstep functions
-		void stopPlayer();
+		//Trackstep functions
 		void setTempo();
 		void volumeSlide();
 
-		//PAULA Interrupt override
-		virtual void interrupt(void);
+};//End of Tfmx class
+} //End of namespace Audio
 
-		//Debugging function to dump information to console
-		void dumpTracks();
-
-};//End of TFMX class
-} // End of namespace Audio
-
 #endif


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