aboutsummaryrefslogtreecommitdiff
path: root/sound/mods/protracker.cpp
diff options
context:
space:
mode:
authorTravis Howell2006-10-23 01:37:59 +0000
committerTravis Howell2006-10-23 01:37:59 +0000
commit99d6e6db5ce2c0fcb8c3884d7b834ab6728daa66 (patch)
treede10147775e39e456d316bfc0f822cdc30bb71d0 /sound/mods/protracker.cpp
parentf0a162e8bbfd06340ec63348f5fcfdaca7349bc1 (diff)
downloadscummvm-rg350-99d6e6db5ce2c0fcb8c3884d7b834ab6728daa66.tar.gz
scummvm-rg350-99d6e6db5ce2c0fcb8c3884d7b834ab6728daa66.tar.bz2
scummvm-rg350-99d6e6db5ce2c0fcb8c3884d7b834ab6728daa66.zip
Add patch to make ProTracker a subclass of AudioStream, from madmoose
svn-id: r24465
Diffstat (limited to 'sound/mods/protracker.cpp')
-rw-r--r--sound/mods/protracker.cpp375
1 files changed, 149 insertions, 226 deletions
diff --git a/sound/mods/protracker.cpp b/sound/mods/protracker.cpp
index 74733d5c15..ab3776624b 100644
--- a/sound/mods/protracker.cpp
+++ b/sound/mods/protracker.cpp
@@ -22,80 +22,158 @@
*/
#include "common/stdafx.h"
-#include "common/system.h"
#include "sound/mods/protracker.h"
+#include "sound/mods/module.h"
+
+#include "sound/audiostream.h"
namespace Modules {
-#define DUMP 1
+class SoundBuffer {
+private:
+ int _capacity;
+ int _size;
+ int16 *_data;
+
+public:
+ SoundBuffer() {
+ _size = 0;
+ _capacity = 8192;
+ _data = (int16 *)malloc(_capacity * sizeof(int16));
+ assert(_data);
+ }
-void ProtrackerPlayer::init(OSystem *system) {
- _system = system;
+ ~SoundBuffer() {
+ free(_data);
+ }
- _buf = new SoundBuffer();
+ int size() {
+ return _size;
+ }
-// FIXME BROKEN: You must NOT use OSystem::setSoundCallback(),
-// ever! The only piece of code allowed to use it is the mixer.
-// And soon the call might be removed completely, too.
-// The proper way to do this is to create a AudioStream
-// subclass and hook that with the mixer. See also the
-// code used by other softsynths (sound/softsynth/emumidi.h).
+ int16 *getEnd() {
+ return _data + _size;
+ }
-// _system->setSoundCallback(&audioCallback, this);
-error("ProtrackerPlayer::init -- setSoundCallback is no more");
-}
+ void ensureCapacity(int len) {
+ if (_size + len > _capacity) {
+ do {
+ _capacity *= 2;
+ } while (_size + len > _capacity);
-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;
+ _data = (int16 *)realloc(_data, _capacity * sizeof(int16));
+ assert(_data);
}
+ }
- //_system->startAudio();
+ void finish(int len) {
+ _size += len;
}
-}
-void ProtrackerPlayer::pause() {
-}
+ 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;
+ }
+};
-void ProtrackerPlayer::stop() {
- //_system->stopAudio();
-}
+class ProtrackerStream : public ::Audio::AudioStream {
+private:
+ Module *_module;
-void ProtrackerPlayer::loadModule(const char *fn) {
- if (_module)
- delete _module;
+ int _rate;
+ SoundBuffer *_buf;
+ double _generatedSamplesOverflow;
- _module = new Module();
- _module->load(fn);
-}
+ 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;
-void ProtrackerPlayer::loadModuleStream(Common::SeekableReadStream &fs) {
- if (_module)
- delete _module;
+ // 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:
+ ProtrackerStream(Common::ReadStream *stream, int rate);
+
+ int readBuffer(int16 *buffer, const int numSamples);
+ bool isStereo() const { return false; }
+ bool endOfData() const { return false; }
+
+ int getRate() const { return _rate; }
+
+private:
+ void generateSound();
+
+ void updateRow();
+ void updateEffects();
+};
+
+ProtrackerStream::ProtrackerStream(Common::ReadStream *stream, int rate) {
_module = new Module();
- _module->loadStream(fs);
+ bool result = _module->load(*stream);
+ assert(result);
+
+ _buf = new SoundBuffer();
+
+ _rate = rate;
+ _tick = _row = _pos = 0;
+ _hasJumpToPattern = false;
+ _hasPatternBreak = false;
+ _hasPatternLoop = false;
+ _patternDelay = 0;
+ _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;
+ }
}
-void ProtrackerPlayer::generateSound() {
- _generatedSamplesOverflow += 5.0 * 44100.0 / (2.0 * _bpm);
+void ProtrackerStream::generateSound() {
+ _generatedSamplesOverflow += 5.0 * _rate / (2.0 * _bpm);
int samples = (int)floor(_generatedSamplesOverflow);
_generatedSamplesOverflow -= samples;
@@ -113,11 +191,11 @@ void ProtrackerPlayer::generateSound() {
(7093789.2 / 2.0) / (_track[track].period +
_track[track].vibrato);
- double rate = frequency / 44100.0;
+ double rate = frequency / _rate;
double offset = _track[track].offset;
int sample = _track[track].sample - 1;
int slen = _module->sample[sample].len;
- byte *data = _module->sample[sample].data;
+ int8 *data = _module->sample[sample].data;
static bool did_warn_about_finetune = false;
if (!did_warn_about_finetune && _module->sample[sample].finetune != 0) {
@@ -128,22 +206,15 @@ void ProtrackerPlayer::generateSound() {
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);
+ /* The repeat length is the limiting factor */
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)];
@@ -153,11 +224,8 @@ void ProtrackerPlayer::generateSound() {
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);
+ /* The requested number of samples is the limiting factor, not the repeat length */
- //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)];
@@ -169,7 +237,6 @@ void ProtrackerPlayer::generateSound() {
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++)
@@ -178,7 +245,6 @@ void ProtrackerPlayer::generateSound() {
_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 *
@@ -193,12 +259,7 @@ void ProtrackerPlayer::generateSound() {
_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
+void ProtrackerStream::updateRow() {
for (int track = 0; track < 4; track++) {
_track[track].vibrato = 0;
note_t note =
@@ -224,136 +285,6 @@ void ProtrackerPlayer::updateRow() {
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;
@@ -406,32 +337,24 @@ void ProtrackerPlayer::updateRow() {
case 0x9:
break; // Retrigger note
default:
- printf("Unimplemented effect %X\n",
- note.effect);
+ warning("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);
+ warning("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);
+void ProtrackerStream::updateEffects() {
static const int16 sinetable[64] = {
0, 24, 49, 74, 97, 120, 141, 161,
@@ -456,8 +379,6 @@ void ProtrackerPlayer::updateEffects() {
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:
@@ -568,11 +489,8 @@ void ProtrackerPlayer::updateEffects() {
}
}
-void ProtrackerPlayer::mix(byte *buf0, int len) {
- int16 *buf = (int16 *)buf0;
- len /= 2;
-
- while (_buf->size() < len) {
+int ProtrackerStream::readBuffer(int16 *buffer, const int numSamples) {
+ while (_buf->size() < numSamples) {
if (_tick == 0) {
if (_hasJumpToPattern) {
_hasJumpToPattern = false;
@@ -608,12 +526,17 @@ void ProtrackerPlayer::mix(byte *buf0, int len) {
generateSound();
}
- _buf->pop(buf, len);
-}
+ _buf->pop(buffer, numSamples);
-void ProtrackerPlayer::audioCallback(void *param, byte *buf, int len) {
- ((ProtrackerPlayer *)param)->mix(buf, len);
+ return numSamples;
}
} // End of namespace Modules
+namespace Audio {
+
+AudioStream *makeProtrackerStream(Common::ReadStream *stream, int rate) {
+ return new Modules::ProtrackerStream(stream, rate);
+}
+
+} // End of namespace Audio