[Scummvm-cvs-logs] SF.net SVN: scummvm: [24351] scummvm/trunk/sound

sev at users.sourceforge.net sev at users.sourceforge.net
Tue Oct 17 00:21:49 CEST 2006


Revision: 24351
          http://svn.sourceforge.net/scummvm/?rev=24351&view=rev
Author:   sev
Date:     2006-10-16 15:20:46 -0700 (Mon, 16 Oct 2006)

Log Message:
-----------
Add WIP (not yet plugged in) Protracker modules player

Modified Paths:
--------------
    scummvm/trunk/sound/module.mk

Added Paths:
-----------
    scummvm/trunk/sound/mods/
    scummvm/trunk/sound/mods/module.cpp
    scummvm/trunk/sound/mods/module.h
    scummvm/trunk/sound/mods/protracker.cpp
    scummvm/trunk/sound/mods/protracker.h

Added: scummvm/trunk/sound/mods/module.cpp
===================================================================
--- scummvm/trunk/sound/mods/module.cpp	                        (rev 0)
+++ scummvm/trunk/sound/mods/module.cpp	2006-10-16 22:20:46 UTC (rev 24351)
@@ -0,0 +1,177 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ * Based on code by madmoose
+ *
+ * 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 "common/stdafx.h"
+#include "common/system.h"
+#include "common/file.h"
+#include "common/stream.h"
+
+#include "sound/mods/module.h"
+
+namespace Modules {
+
+bool Module::load(const char *fn) {
+	Common::File f;
+
+	if (!f.open(fn))
+		return false;
+
+	int bufsz = f.size();
+	byte *buf = new byte[bufsz];
+
+	int r = f.read(buf, bufsz);
+	assert(r);
+
+	f.close();
+
+	Common::MemoryReadStream st(buf, bufsz);
+
+	st.read(songname, 20);
+	songname[0] = '\0';
+
+	for (int i = 0; i < 31; ++i) {
+		st.read(sample[i].name, 22);
+		sample[i].name[22] = '\0';
+		sample[i].len = 2 * st.readUint16BE();
+
+		sample[i].finetune = st.readByte();
+		assert(sample[i].finetune < 0x10);
+
+		sample[i].vol = st.readByte();
+		sample[i].repeat = 2 * st.readUint16BE();
+		sample[i].replen = 2 * st.readUint16BE();
+
+		//printf("\"%s\"\tlen: %d\tfinetune: %d\tvol: %d\trepeat: %d\treplen: %d\n",
+		//       sample[i].name, sample[i].len, sample[i].finetune, sample[i].vol, sample[i].repeat, sample[i].replen);
+
+	}
+
+	songlen = 2 * st.readByte();
+	undef = 2 * st.readByte();
+
+	st.read(songpos, 128);
+	st.read(sig, 4);	// Should be "M.K."
+	assert(0 == memcmp(sig, "M.K.", 4));
+
+	int maxpattern = 0;
+	for (int i = 0; i < 128; ++i)
+		if (maxpattern < songpos[i])
+			maxpattern = songpos[i];
+
+	pattern = new pattern_t[maxpattern + 1];
+
+	for (int i = 0; i <= maxpattern; ++i) {
+		for (int j = 0; j < 64; ++j) {
+			for (int k = 0; k < 4; ++k) {
+				uint32 note = st.readUint32BE();
+				pattern[i][j][k].sample = (note & 0xf0000000) >> 24 | (note & 0x0000f000) >> 12;
+
+				pattern[i][j][k].period = (note >> 16) & 0xfff;
+				pattern[i][j][k].effect = note & 0xfff;
+/*
+        const char *notename;
+
+        switch (pattern[i][j][k].period) {
+          case 856: notename = "C-1"; break;
+          case 808: notename = "C#1"; break;
+          case 762: notename = "D-1"; break;
+          case 720: notename = "D#1"; break;
+          case 678: notename = "E-1"; break;
+          case 640: notename = "E#1"; break;
+          case 604: notename = "F-1"; break;
+          case 570: notename = "F#1"; break;
+          case 538: notename = "A-1"; break;
+          case 508: notename = "A#1"; break;
+          case 480: notename = "B-1"; break;
+          case 453: notename = "B#1"; break;
+          case 428: notename = "C-2"; break;
+          case 404: notename = "C#2"; break;
+          case 381: notename = "D-2"; break;
+          case 360: notename = "D#2"; break;
+          case 339: notename = "E-2"; break;
+          case 320: notename = "E#2"; break;
+          case 302: notename = "F-2"; break;
+          case 285: notename = "F#2"; break;
+          case 269: notename = "A-2"; break;
+          case 254: notename = "A#2"; break;
+          case 240: notename = "B-2"; break;
+          case 226: notename = "B#2"; break;
+          case 214: notename = "C-3"; break;
+          case 202: notename = "C#3"; break;
+          case 190: notename = "D-3"; break;
+          case 180: notename = "D#3"; break;
+          case 170: notename = "E-3"; break;
+          case 160: notename = "E#3"; break;
+          case 151: notename = "F-3"; break;
+          case 143: notename = "F#3"; break;
+          case 135: notename = "A-3"; break;
+          case 127: notename = "A#3"; break;
+          case 120: notename = "B-3"; break;
+          case 113: notename = "B#3"; break;
+          case   0: notename = "   "; break;
+          default:  notename = "???"; break;
+        }
+
+        if (k > 0) printf("  |  ");
+
+        if (pattern[i][j][k].sample)
+          printf("%2d %s %3X", pattern[i][j][k].sample, notename, pattern[i][j][k].effect);
+        else
+          printf("   %s %3X", notename, pattern[i][j][k].effect);
+*/
+			}
+			//printf("\n");
+		}
+	}
+
+	for (int i = 0; i < 31; ++i) {
+		if (!sample[i].len)
+			sample[i].data = 0;
+		else {
+			sample[i].data = new byte[sample[i].len];
+			st.read((byte *)sample[i].data, sample[i].len);
+		}
+	}
+
+	assert(st.eos());
+
+	delete[] buf;
+
+	return true;
+}
+
+Module::Module() {
+	pattern = NULL;
+	for (int i = 0; i < 31; ++i) {
+		sample[i].data = NULL;
+	}
+}
+
+Module::~Module() {
+	delete[] pattern;
+	for (int i = 0; i < 31; ++i) {
+		delete[] sample[i].data;
+	}
+}
+
+} // End of namespace Modules


Property changes on: scummvm/trunk/sound/mods/module.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/sound/mods/module.h
===================================================================
--- scummvm/trunk/sound/mods/module.h	                        (rev 0)
+++ scummvm/trunk/sound/mods/module.h	2006-10-16 22:20:46 UTC (rev 24351)
@@ -0,0 +1,75 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ * Based on code by madmoose
+ *
+ * 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$
+ *
+ */
+
+#ifndef __SOUND_MODS_MODULE_H__
+#define __SOUND_MODS_MODULE_H__
+
+namespace Modules {
+
+/*
+ * Storing notes and patterns like this
+ * wastes insane amounts of memory.
+ *
+ * They should be stored in memory
+ * like they are in the file.
+ */
+
+typedef struct {
+	byte sample;
+	uint16 period;
+	uint16 effect;
+} note_t;
+
+typedef note_t pattern_t[64][4];
+
+typedef struct {
+	byte name[23];
+	uint16 len;
+	byte finetune;
+	byte vol;
+	uint16 repeat;
+	uint16 replen;
+	byte *data;
+} sample_t;
+
+class Module {
+public:
+	byte songname[21];
+
+	sample_t sample[32];
+
+	byte songlen;
+	byte undef;
+	byte songpos[128];
+	byte sig[4];
+	pattern_t *pattern;
+
+	Module();
+	~Module();
+
+	bool load(const char *fn);
+};
+
+} // End of namespace Modules
+
+#endif


Property changes on: scummvm/trunk/sound/mods/module.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/sound/mods/protracker.cpp
===================================================================
--- scummvm/trunk/sound/mods/protracker.cpp	                        (rev 0)
+++ scummvm/trunk/sound/mods/protracker.cpp	2006-10-16 22:20:46 UTC (rev 24351)
@@ -0,0 +1,603 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ * Based on code by madmoose
+ *
+ * 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 "common/stdafx.h"
+#include "common/system.h"
+
+#include "sound/mods/protracker.h"
+
+namespace Modules {
+
+#define DUMP 1
+
+void ProtrackerPlayer::init(OSystem *system) {
+	_system = system;
+
+	_buf = new SoundBuffer();
+
+	_system->setSoundCallback(&audioCallback, this);
+}
+
+void ProtrackerPlayer::start() {
+	if (_module) {
+		_tick = _row = _pos = 0;
+		_hasJumpToPattern = false;
+		_hasPatternBreak = false;
+		_hasPatternLoop = false;
+		_patternLoopCount = 0;
+		_patternLoopRow = 0;
+		_speed = 6;
+		_bpm = 125;
+
+		_generatedSamplesOverflow = 0.0;
+
+		for (int t = 0; t < 4; t++) {
+			_track[t].sample = 0;
+			_track[t].period = 0;
+			_track[t].offset = 0.0;
+
+			_track[t].vibrato = 0;
+		}
+
+		//_system->startAudio();
+	}
+}
+
+void ProtrackerPlayer::pause() {
+}
+
+void ProtrackerPlayer::stop() {
+	//_system->stopAudio();
+}
+
+void ProtrackerPlayer::loadModule(const char *fn) {
+	if (_module)
+		delete _module;
+
+	_module = new Module();
+	_module->load(fn);
+}
+
+void ProtrackerPlayer::generateSound() {
+	_generatedSamplesOverflow += 5.0 * 44100.0 / (2.0 * _bpm);
+	int samples = (int)floor(_generatedSamplesOverflow);
+	_generatedSamplesOverflow -= samples;
+
+	_buf->ensureCapacity(samples);
+
+	int16 *p = _buf->getEnd();
+	for (int i = 0; i < samples; i++)
+		p[i] = 0;
+
+	for (int track = 0; track < 4; track++) {
+		if (_track[track].sample > 0) {
+			p = _buf->getEnd();
+
+			double frequency =
+			    (7093789.2 / 2.0) / (_track[track].period +
+			    _track[track].vibrato);
+
+			double rate = frequency / 44100.0;
+			double offset = _track[track].offset;
+			int sample = _track[track].sample - 1;
+			int slen = _module->sample[sample].len;
+			byte *data = _module->sample[sample].data;
+
+			static bool did_warn_about_finetune = false;
+			if (!did_warn_about_finetune && _module->sample[sample].finetune != 0) {
+				did_warn_about_finetune = true;
+				puts("Warning! Finetuning not implemented!");
+			}
+
+			if (_module->sample[sample].replen > 2) {
+				int neededSamples = samples;
+
+				//printf("%d %d >= %d\n", (int)offset, (int)(offset + neededSamples*rate), _module->sample[sample].repeat + _module->sample[sample].replen);
+
+				while ((int)(offset + neededSamples * rate) >=
+				    (_module->sample[sample].repeat + _module->sample[sample].replen)) {
+					//puts("/* The repeat length is the limiting factor */");
+					//printf("case 1: period: %d\trate: %g\toffset: %g\tsample: %d\tslen: %d\tvol: %d\n", _track[track].period, rate, _track[track].offset, _track[track].sample, slen, _track[track].vol);
+
+					int end =
+					    (int)((_module->sample[sample].
+						repeat + _module->sample[sample].
+						replen - offset) / rate);
+
+					if ((int)(offset + rate * end) > slen)
+						warning("!!!!!!!!!");
+					//printf("writing %d-%d max %d\n", (int)offset, (int)(offset + rate*end), slen);
+
+					for (int i = 0; i < end; i++)
+						*p++ +=
+						    _track[track].vol * data[(int)(offset + rate * i)];
+					_track[track].offset =
+					    _module->sample[sample].repeat;
+					offset = _track[track].offset;
+					neededSamples -= end;
+				}
+				if (neededSamples > 0) {
+					//puts("/* The requested number of samples is the limiting factor, not the repeat length */");
+					//printf("case 2: period: %d\trate: %g\toffset: %g\tsample: %d\tslen: %d\tvol: %d\n", _track[track].period, rate, _track[track].offset, _track[track].sample, slen, _track[track].vol);
+
+					//if ((int)(offset + rate*neededSamples) > slen) puts("!!!!!!!!!");
+					//printf("writing %d-%d max %d\n", (int)offset, (int)(offset + rate*neededSamples), slen);
+					for (int i = 0; i < neededSamples; i++)
+						*p++ +=
+						    _track[track].vol * data[(int)(offset + rate * i)];
+					_track[track].offset +=
+					    rate * neededSamples;
+				}
+			} else {
+				if (offset < slen) {
+					if ((int)(offset + samples * rate) >=
+					    slen) {
+						/* The end of the sample is the limiting factor */
+						//printf("case 3: period: %d\trate: %g\toffset: %g\tsample: %d\tslen: %d\tvol: %d\n", _track[track].period, rate, _track[track].offset, _track[track].sample, slen, _track[track].vol);
+
+						int end = (int)((slen - offset) / rate);
+						for (int i = 0; i < end; i++)
+							*p++ += _track[track].vol *
+							    data[(int)(offset + rate * i)];
+						_track[track].offset = slen;
+					} else {
+						/* The requested number of samples is the limiting factor, not the sample */
+						//printf("case 4: period: %d\trate: %g\toffset: %g\tsample: %d\tslen: %d\tvol: %d\n", _track[track].period, rate, _track[track].offset, _track[track].sample, slen, _track[track].vol);
+
+						for (int i = 0; i < samples; i++)
+							*p++ += _track[track].vol *
+							    data[(int)(offset + rate * i)];
+						_track[track].offset += rate * samples;
+					}
+				}
+			}
+		}
+	}
+
+	_buf->finish(samples);
+}
+
+void ProtrackerPlayer::updateRow() {
+	//printf("ProtrackerPlayer::updateRow(): tick: %d\tpos: %d->%d\trow: %d\n", _tick, _pos, _module->songpos[_pos], _row);
+
+#ifdef DUMP
+	printf("%3d:%3d:%2d: ", _pos, _module->songpos[_pos], _row);
+#endif
+	for (int track = 0; track < 4; track++) {
+		_track[track].vibrato = 0;
+		note_t note =
+		    _module->pattern[_module->songpos[_pos]][_row][track];
+
+		int effect = note.effect >> 8;
+
+		if (note.sample) {
+			if (_track[track].sample != note.sample) {
+				_track[track].vibratoPos = 0;
+			}
+			_track[track].sample = note.sample;
+			_track[track].vol = _module->sample[note.sample - 1].vol;
+		}
+		if (note.period) {
+			if (effect != 3 && effect != 5) {
+				_track[track].period = note.period;
+				_track[track].offset = 0.0;
+			}
+		}
+
+		int exy = note.effect & 0xff;
+		int ex = (note.effect >> 4) & 0xf;
+		int ey = note.effect & 0xf;
+
+#ifdef DUMP
+		const char *notename;
+
+		switch (note.period) {
+		case 856:
+			notename = "C-1";
+			break;
+		case 808:
+			notename = "C#1";
+			break;
+		case 762:
+			notename = "D-1";
+			break;
+		case 720:
+			notename = "D#1";
+			break;
+		case 678:
+			notename = "E-1";
+			break;
+		case 640:
+			notename = "E#1";
+			break;
+		case 604:
+			notename = "F-1";
+			break;
+		case 570:
+			notename = "F#1";
+			break;
+		case 538:
+			notename = "A-1";
+			break;
+		case 508:
+			notename = "A#1";
+			break;
+		case 480:
+			notename = "B-1";
+			break;
+		case 453:
+			notename = "B#1";
+			break;
+		case 428:
+			notename = "C-2";
+			break;
+		case 404:
+			notename = "C#2";
+			break;
+		case 381:
+			notename = "D-2";
+			break;
+		case 360:
+			notename = "D#2";
+			break;
+		case 339:
+			notename = "E-2";
+			break;
+		case 320:
+			notename = "E#2";
+			break;
+		case 302:
+			notename = "F-2";
+			break;
+		case 285:
+			notename = "F#2";
+			break;
+		case 269:
+			notename = "A-2";
+			break;
+		case 254:
+			notename = "A#2";
+			break;
+		case 240:
+			notename = "B-2";
+			break;
+		case 226:
+			notename = "B#2";
+			break;
+		case 214:
+			notename = "C-3";
+			break;
+		case 202:
+			notename = "C#3";
+			break;
+		case 190:
+			notename = "D-3";
+			break;
+		case 180:
+			notename = "D#3";
+			break;
+		case 170:
+			notename = "E-3";
+			break;
+		case 160:
+			notename = "E#3";
+			break;
+		case 151:
+			notename = "F-3";
+			break;
+		case 143:
+			notename = "F#3";
+			break;
+		case 135:
+			notename = "A-3";
+			break;
+		case 127:
+			notename = "A#3";
+			break;
+		case 120:
+			notename = "B-3";
+			break;
+		case 113:
+			notename = "B#3";
+			break;
+		case 0:
+			notename = "   ";
+			break;
+		default:
+			notename = "???";
+			break;
+		}
+
+		if (track > 0)
+			printf("  |  ");
+
+		if (note.sample)
+			printf("%2d %s %3X", note.sample, notename,
+			    note.effect);
+		else
+			printf("   %s %3X", notename, note.effect);
+#endif
+
+		switch (effect) {
+		case 0x0:
+			break;
+		case 0x1:
+			break;
+		case 0x2:
+			break;
+		case 0x3:
+			if (note.period)
+				_track[track].portaToNote = note.period;
+
+			if (exy)
+				_track[track].portaToNoteSpeed = exy;
+			break;
+		case 0x4:
+			if (ex || ey) {
+				_track[track].vibratoSpeed = ex;
+				_track[track].vibratoDepth = ey;
+			}
+			break;
+		case 0x5:
+			break;
+		case 0xA:
+			break;
+		case 0xB:
+			_hasJumpToPattern = true;
+			_jumpToPattern = exy;
+			break;
+		case 0xC:
+			_track[track].vol = exy;
+			break;
+		case 0xD:
+			_hasPatternBreak = true;
+			_skiprow = ex * 10 + ey;
+			break;
+
+		case 0xE:
+			switch (ex) {
+			case 0x6:
+				if (ey == 0) {
+					_patternLoopRow = _row;
+				} else {
+					_patternLoopCount++;
+					if (_patternLoopCount <= ey)
+						_hasPatternLoop = true;
+					else
+						_patternLoopCount = 0;
+				}
+				break;
+			case 0x9:
+				break;	// Retrigger note
+			default:
+				printf("Unimplemented effect %X\n",
+				    note.effect);
+			}
+			break;
+
+		case 0xF:
+			if (exy < 0x20) {
+				_speed = exy;
+				//printf("Speed: %x\n", _speed);
+			} else {
+				_bpm = exy;
+				//printf("BPM: %x\n", _bpm);
+			}
+			break;
+		default:
+			printf("Unimplemented effect %X\n", note.effect);
+		}
+	}
+#ifdef DUMP
+	putchar('\n');
+	fflush(NULL);
+#endif
+}
+
+void ProtrackerPlayer::updateEffects() {
+	//printf("ProtrackerPlayer::updateEffects(): tick: %d\tpos: %d->%d\trow: %d\n", _tick, _pos, _module->songpos[_pos], _row);
+
+	static const int16 sinetable[64] = {
+		   0,   24,   49,   74,   97,  120,  141,  161,
+		 180,  197,  212,  224,  235,  244,  250,  253,
+		 255,  253,  250,  244,  235,  224,  212,  197,
+		 180,  161,  141,  120,   97,   74,   49,   24,
+		   0,  -24,  -49,  -74,  -97, -120, -141, -161,
+		-180, -197, -212, -224, -235, -244, -250, -253,
+		-255, -253, -250, -244, -235, -224, -212, -197,
+		-180, -161, -141, -120,  -97,  -74,  -49,  -24
+	};
+
+	for (int track = 0; track < 4; track++) {
+		_track[track].vibrato = 0;
+
+		note_t note =
+		    _module->pattern[_module->songpos[_pos]][_row][track];
+
+		int effect = note.effect >> 8;
+
+		int exy = note.effect & 0xff;
+		int ex = (note.effect >> 4) & 0xf;
+		int ey = (note.effect) & 0xf;
+
+		//printf("track %d: period: %3d\tsample: %2d\teffect: %x\n", track, note.period, note.sample, note.effect);
+
+		int vol;
+		switch (effect) {
+		case 0x0:
+			break;
+		case 0x1:
+			_track[track].period -= exy;
+			break;
+		case 0x2:
+			_track[track].period += exy;
+			break;
+		case 0x3:
+			if (_track[track].portaToNote && _track[track].portaToNoteSpeed) {
+				if (_track[track].period < _track[track].portaToNote) {
+					_track[track].period += _track[track].portaToNoteSpeed;
+					if (_track[track].period > _track[track].portaToNote)
+						_track[track].period = _track[track].portaToNote;
+				} else if (_track[track].period > _track[track].portaToNote) {
+					_track[track].period -= _track[track].portaToNoteSpeed;
+					if (_track[track].period < _track[track].portaToNote)
+						_track[track].period = _track[track].portaToNote;
+				}
+			}
+			break;
+		case 0x4:
+			_track[track].vibrato =
+			    (_track[track].vibratoDepth * sinetable[_track[track].vibratoPos]) / 128;
+			_track[track].vibratoPos += _track[track].vibratoSpeed;
+			_track[track].vibratoPos %= 64;
+			break;
+
+		case 0x5:
+			if (_track[track].portaToNote
+			    && _track[track].portaToNoteSpeed) {
+				if (_track[track].period < _track[track].portaToNote) {
+					_track[track].period += _track[track].portaToNoteSpeed;
+					if (_track[track].period > _track[track].portaToNote)
+						_track[track].period = _track[track].portaToNote;
+				} else if (_track[track].period > _track[track].portaToNote) {
+					_track[track].period -= _track[track].portaToNoteSpeed;
+					if (_track[track].period < _track[track].portaToNote)
+						_track[track].period = _track[track].portaToNote;
+				}
+			}
+
+			vol = _track[track].vol;
+			if (ex == 0)
+				vol -= ey;
+			else if (ey == 0)
+				vol += ex;
+
+			if (vol < 0)
+				vol = 0;
+			else if (vol > 64)
+				vol = 64;
+
+			_track[track].vol = vol;
+
+			break;
+
+		case 0x6:
+			_track[track].vibrato =
+			    (_track[track].vibratoDepth * sinetable[_track[track].vibratoPos]) / 128;
+			_track[track].vibratoPos += _track[track].vibratoSpeed;
+			_track[track].vibratoPos %= 64;
+
+			vol = _track[track].vol;
+			if (ex == 0)
+				vol -= ey;
+			else if (ey == 0)
+				vol += ex;
+
+			if (vol < 0)
+				vol = 0;
+			else if (vol > 64)
+				vol = 64;
+
+			_track[track].vol = vol;
+
+			break;
+
+		case 0xA:
+			vol = _track[track].vol;
+			if (ex == 0)
+				vol -= ey;
+			else if (ey == 0)
+				vol += ex;
+
+			if (vol < 0)
+				vol = 0;
+			else if (vol > 64)
+				vol = 64;
+
+			_track[track].vol = vol;
+
+			break;
+
+		case 0xE:
+			switch (ex) {
+			case 0x6:
+				break;	// Pattern loop
+			case 0x9:	// Retrigger note
+				if (ey && _tick % ey == 0)
+					_track[track].offset = 0.0;
+				break;
+			}
+			break;
+		}
+	}
+}
+
+void ProtrackerPlayer::mix(byte *buf0, int len) {
+	int16 *buf = (int16 *)buf0;
+	len /= 2;
+
+	while (_buf->size() < len) {
+		if (_tick == 0) {
+			if (_hasJumpToPattern) {
+				_hasJumpToPattern = false;
+				_pos = _jumpToPattern;
+				_row = 0;
+			} else if (_hasPatternBreak) {
+				_hasPatternBreak = false;
+				_row = _skiprow;
+				_pos = (_pos + 1) % _module->songlen;
+				_patternLoopRow = 0;
+			} else if (_hasPatternLoop) {
+				_hasPatternLoop = false;
+				_row = _patternLoopRow;
+			}
+			if (_row >= 64) {
+				_row = 0;
+				_pos = (_pos + 1) % _module->songlen;
+				_patternLoopRow = 0;
+			}
+
+			if (_patternDelay == 0) {
+				updateRow();
+			} else {
+				_patternDelay--;
+			}
+		} else
+			updateEffects();
+
+		_tick = (_tick + 1) % _speed;
+		if (_tick == 0)
+			_row++;
+
+		generateSound();
+	}
+
+	_buf->pop(buf, len);
+}
+
+void ProtrackerPlayer::audioCallback(void *param, byte *buf, int len) {
+	((ProtrackerPlayer *)param)->mix(buf, len);
+}
+
+} // End of namespace Modules
+


Property changes on: scummvm/trunk/sound/mods/protracker.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/sound/mods/protracker.h
===================================================================
--- scummvm/trunk/sound/mods/protracker.h	                        (rev 0)
+++ scummvm/trunk/sound/mods/protracker.h	2006-10-16 22:20:46 UTC (rev 24351)
@@ -0,0 +1,155 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ * Based on code by madmoose
+ *
+ * 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$
+ *
+ */
+
+#ifndef __SOUND_MODS_PROTRACKER_H__
+#define __SOUND_MODS_PROTRACKER_H__
+
+#include "common/stdafx.h"
+#include "common/system.h"
+
+#include "sound/mods/module.h"
+
+namespace Modules {
+
+class SoundBuffer {
+      private:
+	int _capacity;
+	int _size;
+	int16 *_data;
+
+public:
+	SoundBuffer() {
+		_size = 0;
+		_capacity = 8192;
+		_data = (int16 *)malloc(_capacity * sizeof(int16));
+		assert(_data);
+	}
+
+	~SoundBuffer() {
+		free(_data);
+	}
+
+	int size() {
+		return _size;
+	}
+
+	int16 *getEnd() {
+		return _data + _size;
+	}
+
+	void ensureCapacity(int len) {
+		if (_size + len > _capacity) {
+			do {
+				_capacity *= 2;
+			} while (_size + len > _capacity);
+
+			_data = (int16 *)realloc(_data, _capacity * sizeof(int16));
+			assert(_data);
+			memset(_data + _size, 0, len);
+		}
+	}
+
+	void finish(int len) {
+		_size += len;
+	}
+
+	void pop(int16 *dest, int len) {
+		assert(_size >= len);
+		memcpy(dest, _data, len * sizeof(int16));
+		memmove(_data, _data + len, (_size - len) * sizeof(int16));
+		_size -= len;
+	}
+};
+
+class ProtrackerPlayer {
+	OSystem *_system;
+	Module *_module;
+
+	SoundBuffer *_buf;
+	double _generatedSamplesOverflow;
+
+	int _tick;
+	int _row;
+	int _pos;
+
+	int _patternDelay;
+
+	int _speed;
+	int _bpm;
+
+	// For effect 0xB - Jump To Pattern;
+	bool _hasJumpToPattern;
+	int _jumpToPattern;
+
+	// For effect 0xD - PatternBreak;
+	bool _hasPatternBreak;
+	int _skiprow;
+
+	// For effect 0xE6 - Pattern Loop
+	bool _hasPatternLoop;
+	int _patternLoopCount;
+	int _patternLoopRow;
+
+	struct {
+		byte sample;
+		uint16 period;
+		double offset;
+
+		byte vol;
+
+		// For effect 0x3 - Porta to note
+		uint16 portaToNote;
+		byte portaToNoteSpeed;
+
+		// For effect 0x4 - Vibrato
+		int vibrato;
+		byte vibratoPos;
+		byte vibratoSpeed;
+		byte vibratoDepth;
+	} _track[4];
+
+public:
+	ProtrackerPlayer() : _system(NULL), _module(NULL) { };
+
+	void init(OSystem *system);
+
+	void start();
+	void pause();
+	void stop();
+
+	void loadModule(const char *fn);
+
+	void mix(byte *buf, int len);
+
+private:
+	void generateSound();
+
+	void updateRow();
+	void updateEffects();
+
+	static void audioCallback(void *param, byte *buf, int len);
+};
+
+} // End of namespace Modules
+
+#endif


Property changes on: scummvm/trunk/sound/mods/protracker.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Modified: scummvm/trunk/sound/module.mk
===================================================================
--- scummvm/trunk/sound/module.mk	2006-10-16 11:23:47 UTC (rev 24350)
+++ scummvm/trunk/sound/module.mk	2006-10-16 22:20:46 UTC (rev 24351)
@@ -18,6 +18,8 @@
 	voc.o \
 	vorbis.o \
 	wave.o \
+	mods/module.o \
+	mods/protracker.o \
 	softsynth/adlib.o \
 	softsynth/ym2612.o \
 	softsynth/fluidsynth.o \


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