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

marwanhilmi at users.sourceforge.net marwanhilmi at users.sourceforge.net
Thu Jul 10 01:53:28 CEST 2008


Revision: 32981
          http://scummvm.svn.sourceforge.net/scummvm/?rev=32981&view=rev
Author:   marwanhilmi
Date:     2008-07-09 16:53:28 -0700 (Wed, 09 Jul 2008)

Log Message:
-----------
Restructured track and pattern handling to update() system which will be called on interrupt.
Adding support for more pattern commands. Reads note data in but does not yet process them.

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

Modified: scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.cpp
===================================================================
--- scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.cpp	2008-07-09 23:47:29 UTC (rev 32980)
+++ scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.cpp	2008-07-09 23:53:28 UTC (rev 32981)
@@ -44,6 +44,8 @@
 Tfmx::~Tfmx() {
 	if (_data)
 		delete[] _data;
+	if (_trackData)
+		delete[] _trackData;
 }
 
 void Tfmx::load() {
@@ -102,11 +104,8 @@
 		_macroPointers[i] = dataStream.readUint32BE();
 	}
 	
-	//trackstep read test
-	//readTrackstep( 0 );
-
-	//pattern read test
-	readPattern(0);
+	//test
+	//playSong(0);
 }
 bool Tfmx::load(Common::SeekableReadStream &stream) {
 	return true;
@@ -114,188 +113,276 @@
 bool Tfmx::play() {
 	return true;
 }
-void Tfmx::loadSongs() {
-}
-void Tfmx::readTrackstep(uint8 songNumber) {
-	if (songNumber >= 32) {
-		//TODO: error, not a valid index
+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.
+*/
+	if(songNumber >= 32) {
+		//TODO:: Error. Not a valid index. Maybe index songs from 1-32 rather than 0-31.
 	}
 
-	uint32 startPosition;   //offset into file from start for trackstart
-	uint32 endPosition;     //offset into file from start for trackend
-	int32 numCommands;		//number of 1 word track commands or patterns
-	int32 numSteps;         //number of lines in track
+//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;
-	//the file specifies the start position of the last line, so you need to add 16
-	//to get to the actual position where the track ends
 	endPosition = (_songs[songNumber].endPosition * 16) + _trackTableOffset + 16;
-	numCommands = (endPosition - startPosition) / 2;
-	numSteps = numCommands / 8;
+	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);
 
-	for (int i = 0; i < numSteps; i++) { //reads trackstep line by line
-		                                 //updates the _tracks[] array through each pass
-	
-		for(int i = 0; i < 8; i++) { //load current line in _tracks[] , can maybe implement checks here to update track or not?
-			if (!_tracks[i].updateFlag) {
-			_tracks[i].data = trackSubStream.readUint16BE();
-			_tracks[i].patternNumber = 0;
-			_tracks[i].patternTranspose = 0;
-			_tracks[i].updateFlag = false; 
+//Load trackSubStream into _trackData[] array
+	_trackData = new uint16[numBlocks];
+	_trackCount = 0;
+	_trackLength = numBlocks;
+	_tempo = _songs[songNumber].tempoValue; //TODO:: Need to setup for the case when tempoValue < 15
+	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;
+			
+	}
 
-		if (_tracks[0].data == 61438) { //you have a line of trackstep commands
-			switch (_tracks[1].data) {
-			case 0: // EFFE0000 Stop player
-				stopPlayer();
-				break;
-			case 1: //EFFE0001 Play a selection
-				//uint16 selectionPosition = tracks[i+2]; 
-				//uint16 selectionLoops = tracks[i+3];    
-				playSelection(); //TODO: will accept selectionPosition & selectionLoops as parameters
-				break;
-			case 2: //EFFE002 Set the tempo
-				//uint16 tempoDivisor = tracks[i+2];    
-				//uint16 tempoBPM = tracks[i+3];        
-				setTempo(); //TODO: will accept tempoDivisor & tempoBPM as parameters
-				break;
-			case 3: //EFFE0003 Function??? Not used in MI. Flagged as multimode/7 channel setting in other players
-				break;
-			case 4: //EFFE0004 Volume slide
-				//uint16 volumeDivisor = tracks[i+2];    
-				//uint16 volumeTarget = tracks[i+3];     
-				volumeSlide(); //TODO: will accept volumeDivisor & volumeTarget as parameters
-				break;
-			default: //Non-existant command
-				//TODO: error
-				break;
-			}		
-		} else { //you have a line of patterns, readPattern()
-			//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 channel command
-					_tracks[i].activeFlag = false; //should also kill channel
-				}
-				
-				if (_tracks[i].activeFlag) {
-				_tracks[i].patternNumber = _tracks[i].data >> 8;
-				_tracks[i].patternTranspose = _tracks[i].data & 0x00FF;
-				//readPattern(_tracks[i].patternNumber); //this should modify settings on track or channel as needed
-				}
-			}//end pattern loop
-		}//end else
+	//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();
 	}
+*/
 }
-void Tfmx::readPattern(uint8 patternNumber) {
-	//TODO: setup lookup routine which reads pattern number and then finds corresponding address
-	//maybe a stream containing the pattern should be created in same way it was done in readTrackstep()
+void Tfmx::updateTrackstep() {
 
-	uint32 startPosition;
-	uint32 endPosition;
-	int32 numCommands;		//number of longword pattern commands or notes
-	startPosition = _patternPointers[patternNumber];
-	endPosition = _patternPointers[patternNumber + 1];
-	numCommands = (endPosition - startPosition) / 4;
+	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++;
+	}
 
-	Common::MemoryReadStream dataStream(_data, _dataSize);
-	Common::SeekableSubReadStream patternSubStream(&dataStream, startPosition, endPosition);
+	if (_tracks[0].data == 61438) { //you have a line of trackstep commands
+		switch (_tracks[1].data) {
+		case 0: // EFFE0000 Stops player.
+			stopPlayer();
+			break;
+		case 1: //EFFE0001: NOT USED IN MI.
+			//Plays a selection.
+			//uint16 selectionPosition = tracks[2]; 
+			//uint16 selectionLoops = tracks[3];    
+			break;
+		case 2: //EFFE002 Set the tempo
+			//MI uses this command but it seems broken - it sets both parameters to 0 only. 
+			//Might be safe to ignore for now and just use tempo set in header.
+			//uint16 tempoDivisor = tracks[2];    
+			//uint16 tempoBPM = tracks[3];        
+			setTempo(); //TODO: will accept tempoDivisor & tempoBPM as parameters
+			break;
+		case 3: //EFFE0003: NOT USED IN MI. 
+			//Purpose not clear. Flagged as multimode/7 channel setting in other players.
+			break;
+		case 4: //EFFE0004 Volume slide
+			//uint16 volumeDivisor = tracks[2];    
+			//uint16 volumeTarget = tracks[3];     
+			volumeSlide(); //TODO: will accept volumeDivisor & volumeTarget as parameters
+			break;
+		default: //Non-existant command
+			//TODO: error
+			break;
+		} // end switch _tracks[1].data
 
-	uint32 *pattern;
-	pattern = new uint32[numCommands];
-	for (int i = 0; i < numCommands; i++) {
-		pattern[i] = patternSubStream.readUint32BE();
-	}
-	//pattern[] should now have each command or note ready for processing
+		for (int i = 0; i < 8; i++) {
+			_tracks[i].updateFlag = true;
+		} // end for updateFlag = true loop
+	} // end if track[].data = command
 
-	//TODO: read pattern[] and determine if it is a command or note.
-	// Commands will be processed as nessecary. 
-	// Notes will be read as note structures and then passes to a seperate function for processing.
+	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; 
+			}
+				
+			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;
 
-	//Can potentially change this loop to stop when it finds the pattern end flag
-	for (int i = 0; i < numCommands; i++) {
-		//masks to isolate each byte of each pattern - temporary method. likely only first one is needed
-		uint8 byte1 = (pattern[i] & 0xFF000000) >> 24;
-		uint8 byte2 = (pattern[i] & 0x00FF0000) >> 16;
-		uint8 byte3 = (pattern[i] & 0x0000FF00) >> 8;
-		uint8 byte4 = (pattern[i] & 0x000000FF);
-		uint16 bytes34 = (pattern[i] & 0x0000FFFF);
-		
-		if (byte1 >= 0xF0) {
-			//you have a command. do something
-			//quick test to dump commands to terminal
-			warning("Command #: %X", i+1);
-			warning("Byte 1: %X", byte1);
+					if (_tracks[i].pattern.jumpFlag) {
+						_tracks[i].pattern.number = _tracks[i].pattern.saveNumber1;
+						_tracks[i].pattern.transpose = 0;
+					}
 
-			switch (byte1) {
-				case 0xF0: //end pattern + advance track
-					//end pattern? also needs to know the track this is playing on
-					//_tracks[i].updateFlag = true; 
-					break;
-				case 0xF1: //repeat block/loop
-					break;
-				case 0xF2: //pattern jump
-					//readPattern(byte2) at offset in bytes34
-					break;
-				case 0xF3:
-					//waits byte2 + 1 jiffies
-					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[i].activeFlag = false;
-					break;
-				case 0xF5: //Key up
-					break;
-				case 0xF6: //Vibrato
-					break;
-				case 0xF7: //Envelope
-					break;
-				case 0xF8: //same as 0xF2 except it saves current pattern address for return
-					break;
-				case 0xF9: //return to saved address
-					break;
-				case 0xFA: //master volume slide
-					break;
-				case 0xFB: 
-					break;
-				case 0xFC: //Portamento
-					break;
-				case 0xFD: //Channel lock
-					//locks the channel specified in byte2 for bytes34 ticks
-					break;
-				case 0xFE: //disable track, same as F4 apparently
-					break;
-				case 0xFF: //Do nothing - advance pattern pointer
-					break;
-				default:
-					//invalid cmd
-					break;
+					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--;
+				}
 			}
-		} else { //you have a note
-			//readnote
+		}//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;
+
+		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();
 		}
 	}
+	//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;
+
+	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;
+			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;
+			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;
+			break;
+		case 0xF5: //Key up
+			break;
+		case 0xF6: //Vibrato
+			break;
+		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;
+		case 0xFB: 
+			break;
+		case 0xFC: //Portamento
+			break;
+		case 0xFD: //Channel lock
+			//locks the channel specified in byte2 for bytes34 ticks
+			break;
+		case 0xFE: //disable track, same as F4 apparently
+			_tracks[trackNumber].activeFlag = false;
+			break;
+		case 0xFF: //Do nothing - advance pattern pointer
+			break;
+		default:
+			//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();
+	}
+
+	_tracks[trackNumber].pattern.data++;
+	_tracks[trackNumber].pattern.count++;
 }
-void Tfmx::readNote(Note _aNote) {
+
+void Tfmx::updateNote(uint8 trackNumber) {
 }
-void Tfmx::readMacro(int _macroNumber) {
+void Tfmx::doMacros(uint8 trackNumber) {
 }
 void Tfmx::stopPlayer() {
+	for(int i = 0; i < 8; i++) {
+	_tracks[i].activeFlag = false;
+	}
 	stopPaula();
 }
-void Tfmx::playSelection() {
-}
 void Tfmx::setTempo() {
 }
 void Tfmx::volumeSlide() {
 }
 void Tfmx::interrupt() {
 }
+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) );
+		}
+	}
+}
 
 } // End of namespace Audio
 

Modified: scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.h
===================================================================
--- scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.h	2008-07-09 23:47:29 UTC (rev 32980)
+++ scummvm/branches/gsoc2008-tfmx/sound/mods/tfmx.h	2008-07-09 23:53:28 UTC (rev 32981)
@@ -44,73 +44,106 @@
 		bool load(Common::SeekableReadStream &stream);
 		
 		//generic function to start playback
+		//will likely change to playSong(uint8 songNumber)
 		bool play();
 		
 protected:
-		uint8 *_data;      //buffer
-		uint32 _dataSize; //buffer size
+		//uint8 stream for whole MDAT file
+		uint8 *_data;      
+		uint32 _dataSize; 
 
+		//addresses of tables in MDAT file
 		uint32 _trackTableOffset;
 		uint32 _patternTableOffset;
 		uint32 _macroTableOffset;
 
+		//addresses of patterns and macros in MDAT file
 		uint32 _patternPointers[128];
 		uint32 _macroPointers[128]; 
 
-		static const uint16 notes[]; //note table , needs verification
+		//uint16 stream for current song trackstep
+		//need count and length to keep running tally
+		uint16 *_trackData;
+		uint32 _trackCount;
+		uint32 _trackLength;
+		uint16 _tempo; //current value for tempo
 
-		struct Note {
-			uint8 noteValue;
-			uint8 macroNumber;
-			uint8 volume;
-			uint8 channelNumber;
-			uint8 wait;
-		};
+		//note table , needs verification
+		static const uint16 notes[]; 
 
+		//Song structure
 		struct Song {
 			uint16 startPosition;
 			uint16 endPosition;
 			uint16 tempoValue;
 		}_songs[32];
+		
+		//Note structure
+		struct Note {
+			uint8 noteNumber;
+			uint8 macroNumber;
+			uint8 channelNumber;
+			uint8 volume;
+			uint8 wait;
+		};
 
-		struct Channel {
-			//empty 
-			//need to implement channel structure properly
-			//will have data to send to Paula via interrupt()
-			uint8 crap;
-		}_channels[4];
+		//Pattern structure; contains note
+		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;
+		//	bool loopFlag;
+		//	uint16 loopCount;
+		};
 
+		//Track structure; contains pattern
+		//Setup as 8-track array, each track gets updated on interrupt
 		struct Track {
 			uint16 data;
-			uint8 patternNumber;
-			uint8 patternTranspose;
-			uint16 tempo; //can be changed by track command
 			bool updateFlag;
 			bool activeFlag;
-			//should setup as 8-track array 
-			//each track gets updated as trackstep progresses at predefined speed
+			Pattern pattern;
+		//	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;
+		}_channels[4];
 
+		//TODO: Will likely need to add more data members to structures
+		//for effects and macro proccessing. 
+
 		//functions used in playback (in order by relationship)
-		void loadSongs();
-		void readTrackstep(uint8 songNumber);
-		void readPattern(uint8 patternNumber);
-		void readNote(Note _aNote);
-		void readMacro(int _macroNumber);
+		void playSong(uint8 songNumber);
+		void updateTrackstep( );
+		void updatePattern(uint8 trackNumber);
+		void updateNote(uint8 trackNumber);
+		void doMacros(uint8 trackNumber);
+		
 		//trackstep functions
 		void stopPlayer();
-		void playSelection();
 		void setTempo();
 		void volumeSlide();
 
-		//pattern functions + macro functions will either be handled as discrete functions
-		//or handled directly in the readX functions.
-		//F0 -> FF pattern commands
-		//00 -> 29 macro commands
-
 		//PAULA Interrupt override
 		virtual void interrupt();
 
+		//Debugging function to dump information to console
+		void dumpTracks();
+
 };//End of TFMX class
 } // End of namespace Audio
 


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