2009-07-01 23:11:56 +00:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* 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_MAXTRAX_H
|
|
|
|
#define SOUND_MODS_MAXTRAX_H
|
|
|
|
|
|
|
|
#include "sound/mods/paula.h"
|
|
|
|
|
|
|
|
namespace Audio {
|
|
|
|
|
|
|
|
class MaxTrax : public Paula {
|
|
|
|
public:
|
|
|
|
MaxTrax(int rate, bool stereo);
|
|
|
|
virtual ~MaxTrax();
|
|
|
|
|
2009-07-19 14:02:19 +00:00
|
|
|
bool load(Common::SeekableReadStream &musicData, bool loadScores = true, bool loadSamples = true);
|
|
|
|
bool playSong(int songIndex, bool loop = false, int advance = 0);
|
|
|
|
int playNote(byte note, byte patch, uint16 duration, uint16 volume, bool rightSide);
|
|
|
|
void setVolume(const byte volume) { _playerCtx.volume = volume; }
|
|
|
|
void setTempo(const uint16 tempo) {
|
|
|
|
_playerCtx.tickUnit = (int32)(((uint32)(tempo & 0xFFF0) << 8) / (uint16)(5 * _playerCtx.vBlankFreq));
|
|
|
|
}
|
|
|
|
void stopMusic();
|
|
|
|
|
2009-07-04 16:24:15 +00:00
|
|
|
protected:
|
2009-07-01 23:11:56 +00:00
|
|
|
void interrupt();
|
|
|
|
|
2009-07-04 16:24:15 +00:00
|
|
|
private:
|
2009-07-06 17:37:54 +00:00
|
|
|
enum { kNumPatches = 64, kNumVoices = 4, kNumChannels = 16, kNumExtraChannels = 1 };
|
|
|
|
enum { kPriorityScore, kPriorityNote, kPrioritySound };
|
2009-07-19 14:02:19 +00:00
|
|
|
// int16 _microtonal[128];
|
2009-07-04 16:24:15 +00:00
|
|
|
|
2009-07-19 14:02:19 +00:00
|
|
|
struct Event {
|
|
|
|
uint16 startTime;
|
|
|
|
uint16 stopTime;
|
|
|
|
byte command;
|
|
|
|
byte parameter;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Score {
|
|
|
|
const Event *events;
|
|
|
|
uint32 numEvents;
|
|
|
|
} *_scores;
|
|
|
|
|
|
|
|
int _numScores;
|
|
|
|
|
|
|
|
struct {
|
2009-07-06 17:37:54 +00:00
|
|
|
uint16 vBlankFreq;
|
|
|
|
int32 ticks;
|
|
|
|
int32 tickUnit;
|
|
|
|
uint16 frameUnit;
|
|
|
|
|
|
|
|
uint16 maxScoreNum;
|
2009-07-04 16:24:15 +00:00
|
|
|
uint16 tempo;
|
2009-07-06 17:37:54 +00:00
|
|
|
uint16 tempoInitial;
|
|
|
|
uint16 tempoStart;
|
|
|
|
int16 tempoDelta;
|
|
|
|
int32 tempoTime;
|
|
|
|
int32 tempoTicks;
|
|
|
|
|
|
|
|
byte volume;
|
|
|
|
|
2009-07-04 16:24:15 +00:00
|
|
|
bool filterOn;
|
|
|
|
bool handleVolume;
|
2009-07-06 17:37:54 +00:00
|
|
|
bool musicPlaying;
|
|
|
|
bool musicLoop;
|
|
|
|
|
|
|
|
int scoreIndex;
|
2009-07-10 16:01:40 +00:00
|
|
|
const Event *nextEvent;
|
2009-07-06 17:37:54 +00:00
|
|
|
int32 nextEventTime;
|
2009-07-04 16:24:15 +00:00
|
|
|
} _playerCtx;
|
|
|
|
|
|
|
|
struct Envelope {
|
|
|
|
uint16 duration;
|
|
|
|
uint16 volume;
|
|
|
|
};
|
|
|
|
|
2009-07-10 16:01:40 +00:00
|
|
|
const struct Patch {
|
|
|
|
const Envelope *attackPtr;
|
2009-07-04 16:24:15 +00:00
|
|
|
//Envelope *releasePtr;
|
|
|
|
uint16 attackLen;
|
|
|
|
uint16 releaseLen;
|
|
|
|
|
2009-07-17 00:07:36 +00:00
|
|
|
int16 tune;
|
2009-07-04 16:24:15 +00:00
|
|
|
uint16 volume;
|
|
|
|
|
|
|
|
// this was the SampleData struct in the assembler source
|
2009-07-10 16:01:40 +00:00
|
|
|
const int8 *samplePtr;
|
2009-07-06 17:37:54 +00:00
|
|
|
uint32 sampleTotalLen;
|
|
|
|
uint32 sampleAttackLen;
|
2009-07-04 16:24:15 +00:00
|
|
|
uint16 sampleOctaves;
|
2009-07-06 17:37:54 +00:00
|
|
|
} _patch[kNumPatches];
|
2009-07-04 16:24:15 +00:00
|
|
|
|
2009-07-06 17:37:54 +00:00
|
|
|
struct ChannelContext {
|
2009-07-10 16:01:40 +00:00
|
|
|
const Patch *patch;
|
2009-07-06 17:37:54 +00:00
|
|
|
uint16 regParamNumber;
|
|
|
|
|
|
|
|
uint16 modulation;
|
|
|
|
uint16 modulationTime;
|
|
|
|
|
2009-07-19 14:02:19 +00:00
|
|
|
// int16 microtonal;
|
2009-07-06 17:37:54 +00:00
|
|
|
|
2009-07-13 22:49:34 +00:00
|
|
|
uint16 portamentoTime;
|
2009-07-06 17:37:54 +00:00
|
|
|
|
|
|
|
int16 pitchBend;
|
|
|
|
int16 pitchReal;
|
|
|
|
int8 pitchBendRange;
|
|
|
|
|
|
|
|
uint8 volume;
|
|
|
|
uint8 voicesActive;
|
|
|
|
// uint8 number;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
kFlagRightChannel = 1 << 0,
|
|
|
|
kFlagPortamento = 1 << 1,
|
|
|
|
kFlagDamper = 1 << 2,
|
|
|
|
kFlagMono = 1 << 3,
|
2009-07-19 14:02:19 +00:00
|
|
|
// kFlagMicrotonal = 1 << 4,
|
2009-07-17 00:07:36 +00:00
|
|
|
kFlagModVolume = 1 << 5//,
|
|
|
|
//kFlagAltered = 1 << 6
|
2009-07-06 17:37:54 +00:00
|
|
|
};
|
|
|
|
byte flags;
|
2009-07-14 02:15:31 +00:00
|
|
|
bool isAltered;
|
2009-07-06 17:37:54 +00:00
|
|
|
|
|
|
|
uint8 lastNote;
|
2009-07-19 14:02:19 +00:00
|
|
|
// uint8 program;
|
2009-07-06 17:37:54 +00:00
|
|
|
|
|
|
|
} _channelCtx[kNumChannels + kNumExtraChannels];
|
|
|
|
|
|
|
|
struct VoiceContext {
|
|
|
|
ChannelContext *channel;
|
2009-07-10 16:01:40 +00:00
|
|
|
const Patch *patch;
|
|
|
|
const Envelope *envelope;
|
2009-07-17 00:58:26 +00:00
|
|
|
// uint32 uinqueId;
|
|
|
|
int32 preCalcNote;
|
2009-07-10 13:38:13 +00:00
|
|
|
uint32 ticksLeft;
|
2009-07-08 22:59:50 +00:00
|
|
|
int32 portaTicks;
|
2009-07-10 13:38:13 +00:00
|
|
|
int32 incrVolume;
|
2009-07-17 01:42:58 +00:00
|
|
|
// int32 periodOffset;
|
2009-07-06 17:37:54 +00:00
|
|
|
/*ifne FASTSOUND
|
|
|
|
APTR voice_CurFastIOB ; current fast iob playing
|
|
|
|
APTR voice_NextFastIOB ; next fast iob to play
|
|
|
|
APTR voice_FastBuffer ; pointer to buffer area
|
|
|
|
endc*/
|
|
|
|
uint16 envelopeLeft;
|
|
|
|
uint16 noteVolume;
|
|
|
|
uint16 baseVolume;
|
|
|
|
uint16 lastPeriod;
|
|
|
|
byte baseNote;
|
|
|
|
byte endNote;
|
2009-07-17 01:42:58 +00:00
|
|
|
byte octave;
|
|
|
|
// byte number;
|
|
|
|
// byte link;
|
2009-07-06 17:37:54 +00:00
|
|
|
byte priority;
|
|
|
|
enum {
|
|
|
|
kStatusFree,
|
|
|
|
kStatusHalt,
|
|
|
|
kStatusDecay,
|
|
|
|
kStatusRelease,
|
|
|
|
kStatusSustain,
|
|
|
|
kStatusAttack,
|
|
|
|
kStatusStart
|
|
|
|
};
|
|
|
|
byte status;
|
2009-07-19 14:02:19 +00:00
|
|
|
bool hasDamper;
|
|
|
|
bool isBlocked;
|
2009-07-06 17:37:54 +00:00
|
|
|
byte lastVolume;
|
2009-07-14 02:15:31 +00:00
|
|
|
bool hasPortamento;
|
2009-07-19 14:02:19 +00:00
|
|
|
byte dmaOff;
|
2009-07-06 17:37:54 +00:00
|
|
|
|
|
|
|
int32 stopEventTime;
|
2009-07-14 02:15:31 +00:00
|
|
|
byte stopEventCommand; // TODO: Remove?
|
|
|
|
byte stopEventParameter; // TODO: Remove?
|
2009-07-06 17:37:54 +00:00
|
|
|
} _voiceCtx[kNumVoices];
|
2009-07-04 16:24:15 +00:00
|
|
|
|
|
|
|
void freePatches();
|
|
|
|
void freeScores();
|
2009-07-10 15:04:41 +00:00
|
|
|
void resetChannel(ChannelContext &chan, bool rightChannel);
|
2009-07-04 16:24:15 +00:00
|
|
|
|
2009-07-14 02:15:31 +00:00
|
|
|
static int8 pickvoice(const VoiceContext voice[4], uint pick, int16 pri);
|
|
|
|
int32 calcVolumeDelta(int32 delta, uint16 time);
|
2009-07-17 01:42:58 +00:00
|
|
|
static uint16 calcNote(const VoiceContext &voice);
|
2009-07-06 17:37:54 +00:00
|
|
|
int8 noteOn(ChannelContext &channel, byte note, uint16 volume, uint16 pri);
|
2009-07-13 22:49:34 +00:00
|
|
|
void noteOff(VoiceContext &voice, byte note);
|
2009-07-06 17:37:54 +00:00
|
|
|
void killVoice(byte num);
|
|
|
|
|
2009-07-17 01:42:58 +00:00
|
|
|
static int32 precalcNote(byte baseNote, int16 tune, byte octave) {
|
|
|
|
return 0x9fd77 + 0x3C000 + (1 << 16) - ((baseNote << 14) + (tune << 11) / 3) / 3 - (octave << 16);
|
2009-07-17 00:58:26 +00:00
|
|
|
}
|
|
|
|
|
2009-07-04 16:24:15 +00:00
|
|
|
static void outPutEvent(const Event &ev, int num = -1) {
|
|
|
|
struct {
|
|
|
|
byte cmd;
|
2009-07-06 18:15:50 +00:00
|
|
|
const char *name;
|
|
|
|
const char *param;
|
2009-07-04 16:24:15 +00:00
|
|
|
} COMMANDS[] = {
|
|
|
|
{0x80, "TEMPO ", "TEMPO, N/A "},
|
|
|
|
{0xa0, "SPECIAL ", "CHAN, SPEC # | VAL"},
|
|
|
|
{0xb0, "CONTROL ", "CHAN, CTRL # | VAL"},
|
|
|
|
{0xc0, "PROGRAM ", "CHANNEL, PROG # "},
|
|
|
|
{0xe0, "BEND ", "CHANNEL, BEND VALUE"},
|
|
|
|
{0xf0, "SYSEX ", "TYPE, SIZE "},
|
|
|
|
{0xf8, "REALTIME", "REALTIME, N/A "},
|
|
|
|
{0xff, "END ", "N/A, N/A "},
|
|
|
|
{0xff, "NOTE ", "VOL | CHAN, STOP"},
|
|
|
|
};
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
for (; i < ARRAYSIZE(COMMANDS) - 1 && ev.command != COMMANDS[i].cmd; ++i)
|
|
|
|
;
|
|
|
|
|
|
|
|
if (num == -1)
|
|
|
|
debug("Event : %02X %s %s %02X %04X %04X", ev.command, COMMANDS[i].name, COMMANDS[i].param, ev.parameter, ev.startTime, ev.stopTime);
|
|
|
|
else
|
|
|
|
debug("Event %3d: %02X %s %s %02X %04X %04X", num, ev.command, COMMANDS[i].name, COMMANDS[i].param, ev.parameter, ev.startTime, ev.stopTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void outPutScore(const Score &sc, int num = -1) {
|
|
|
|
if (num == -1)
|
|
|
|
debug("score : %i Events", sc.numEvents);
|
|
|
|
else
|
|
|
|
debug("score %2d: %i Events", num, sc.numEvents);
|
|
|
|
for (uint i = 0; i < sc.numEvents; ++i)
|
|
|
|
outPutEvent(sc.events[i], i);
|
|
|
|
debug("");
|
|
|
|
}
|
|
|
|
};
|
2009-07-01 23:11:56 +00:00
|
|
|
} // End of namespace Audio
|
|
|
|
|
2009-07-06 18:15:50 +00:00
|
|
|
#endif
|