aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/mods/module.cpp101
-rw-r--r--sound/mods/module.h11
-rw-r--r--sound/mods/protracker.cpp375
-rw-r--r--sound/mods/protracker.h129
4 files changed, 173 insertions, 443 deletions
diff --git a/sound/mods/module.cpp b/sound/mods/module.cpp
index 4c20c3a741..291f95fe3f 100644
--- a/sound/mods/module.cpp
+++ b/sound/mods/module.cpp
@@ -22,40 +22,16 @@
*/
#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);
+#include "common/util.h"
- bool result = loadStream(st);
-
- delete[] buf;
-
- return result;
-}
+namespace Modules {
-bool Module::loadStream(Common::SeekableReadStream &st) {
+bool Module::load(Common::ReadStream &st) {
st.read(songname, 20);
- songname[0] = '\0';
+ songname[20] = '\0';
for (int i = 0; i < 31; ++i) {
st.read(sample[i].name, 22);
@@ -68,18 +44,17 @@ bool Module::loadStream(Common::SeekableReadStream &st) {
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));
+ st.read(sig, 4);
+ if (memcmp(sig, "M.K.", 4)) {
+ warning("Expected 'M.K.' in protracker module");
+ return false;
+ }
int maxpattern = 0;
for (int i = 0; i < 128; ++i)
@@ -93,62 +68,9 @@ bool Module::loadStream(Common::SeekableReadStream &st) {
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");
}
}
@@ -156,12 +78,13 @@ bool Module::loadStream(Common::SeekableReadStream &st) {
if (!sample[i].len)
sample[i].data = 0;
else {
- sample[i].data = new byte[sample[i].len];
+ sample[i].data = new int8[sample[i].len];
st.read((byte *)sample[i].data, sample[i].len);
}
}
- assert(st.eos());
+ if (!st.eos())
+ warning("Expected EOS on module stream");
return true;
}
diff --git a/sound/mods/module.h b/sound/mods/module.h
index 4073d5d4ec..1e87b7e1ea 100644
--- a/sound/mods/module.h
+++ b/sound/mods/module.h
@@ -24,7 +24,7 @@
#ifndef SOUND_MODS_MODULE_H
#define SOUND_MODS_MODULE_H
-#include "common/file.h"
+#include "common/stream.h"
namespace Modules {
@@ -36,12 +36,16 @@ namespace Modules {
* like they are in the file.
*/
+#include "common/pack-start.h" // START STRUCT PACKING
+
struct note_t {
byte sample;
uint16 period;
uint16 effect;
};
+#include "common/pack-end.h" // END STRUCT PACKING
+
typedef note_t pattern_t[64][4];
struct sample_t {
@@ -51,7 +55,7 @@ struct sample_t {
byte vol;
uint16 repeat;
uint16 replen;
- byte *data;
+ int8 *data;
};
class Module {
@@ -69,8 +73,7 @@ public:
Module();
~Module();
- bool load(const char *fn);
- bool loadStream(Common::SeekableReadStream &st);
+ bool load(Common::ReadStream &stream);
};
} // End of namespace Modules
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
diff --git a/sound/mods/protracker.h b/sound/mods/protracker.h
index c6511e8a47..d79694d26d 100644
--- a/sound/mods/protracker.h
+++ b/sound/mods/protracker.h
@@ -25,133 +25,14 @@
#define SOUND_MODS_PROTRACKER_H
#include "common/stdafx.h"
-#include "common/system.h"
+#include "common/stream.h"
-#include "sound/mods/module.h"
+namespace Audio {
-namespace Modules {
+class AudioStream;
-class SoundBuffer {
-private:
- int _capacity;
- int _size;
- int16 *_data;
+AudioStream *makeProtrackerStream(Common::ReadStream *stream, int rate = 44100);
-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 {
-private:
- 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(0), _module(0) { };
-
- void init(OSystem *system);
-
- void start();
- void pause();
- void stop();
-
- void loadModule(const char *fn);
- void loadModuleStream(Common::SeekableReadStream &fs);
-
- 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
+} // End of namespace Audio
#endif