Skip to content

Commit

Permalink
XEEN: Implement Music playEffect method
Browse files Browse the repository at this point in the history
  • Loading branch information
dreammaster committed Sep 13, 2016
1 parent 48235c9 commit dd06b6f
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 2 deletions.
58 changes: 56 additions & 2 deletions engines/xeen/music.cpp
Expand Up @@ -27,10 +27,15 @@

namespace Xeen {

#define ADLIB_CHANNEL_COUNT 9
#define CALLBACKS_PER_SECOND 60

Music::Music(Audio::Mixer *mixer) : _mixer(mixer), _effectsData(nullptr) {
Music::Music(Audio::Mixer *mixer) : _mixer(mixer), _effectsData(nullptr),
_musicPtr1(nullptr), _musicPtr2(nullptr), _lowMusicIgnored(false),
_fieldF(false), _field109(0), _field10B(0), _field114(0),
_field115(0), _field117(0) {
_channels.resize(ADLIB_CHANNEL_COUNT);
Common::fill(&_field10D[0], &_field10D[7], 0);

_mixer = mixer;
_opl = OPL::Config::create();
_opl->init();
Expand Down Expand Up @@ -72,6 +77,10 @@ void Music::onTimer() {
flush();
}

void Music::write(int reg, int val) {
_queue.push(RegisterValue(reg, val));
}

void Music::flush() {
Common::StackLock slock(_driverMutex);

Expand All @@ -85,4 +94,49 @@ void Music::update() {
// TODO
}

void Music::playEffect(uint effectId) {
if (!_lowMusicIgnored || effectId < 7 || effectId >= 11) {
if (effectId < _effectsOffsets.size()) {
_musicPtr1 = _musicPtr2 = &_effectsData[_effectsOffsets[effectId]];
_field117 = 0;
_field115 = 0;
_field114 = 0;
reset();
_lowMusicIgnored = true;
}
}
}

void Music::reset() {
if (!_fieldF) {
_field109 = 0;
setFrequency(7, 0);
_channels[7]._outputLevel = 63;
setOutputLevel(7, 63);
}

_field10B = 0;
setFrequency(8, 0);
_channels[8]._outputLevel = 63;
setOutputLevel(8, 63);
}

void Music::setFrequency(byte operatorNum, uint frequency) {
write(0xA0 + operatorNum, frequency & 0xff);
write(0xB0 + operatorNum, (frequency >> 8));
}

void Music::setOutputLevel(byte channelNum, uint level) {
write(0x40 + OPERATOR2_INDEXES[channelNum], level |
(_channels[channelNum]._scalingValue & 0xC0));
}

const byte Music::OPERATOR1_INDEXES[ADLIB_CHANNEL_COUNT] = {
0, 1, 2, 8, 9, 0xA, 0x10, 0x11, 0x12
};

const byte Music::OPERATOR2_INDEXES[ADLIB_CHANNEL_COUNT] = {
3, 4, 5, 0xB, 0xC, 0xD, 0x13, 0x14, 0x15
};

} // End of namespace Xeen
47 changes: 47 additions & 0 deletions engines/xeen/music.h
Expand Up @@ -29,6 +29,8 @@
#include "common/mutex.h"
#include "common/queue.h"

#define ADLIB_CHANNEL_COUNT 9

namespace OPL {
class OPL;
}
Expand All @@ -45,18 +47,43 @@ struct RegisterValue {
};

class Music {
struct Channel {
byte _outputLevel;
byte _scalingValue;

Channel() : _outputLevel(0), _scalingValue(0) {}
};
private:
static const byte OPERATOR1_INDEXES[ADLIB_CHANNEL_COUNT];
static const byte OPERATOR2_INDEXES[ADLIB_CHANNEL_COUNT];
private:
OPL::OPL *_opl;
Common::Mutex _driverMutex;
Common::Array<Channel> _channels;
Common::Queue<RegisterValue> _queue;
const byte *_effectsData;
Common::Array<uint16> _effectsOffsets;
const byte *_musicPtr1, *_musicPtr2;
bool _fieldF;
int _field109;
int _field10B;
byte _field10D[7];
int _field114;
int _field115;
int _field117;
bool _lowMusicIgnored;
private:
/**
* Loads effects data that was embedded in the music driver
*/
void loadEffectsData();

/**
* Adds a register write to the pending queue that will be flushed
* out to the OPL on the next timer call
*/
void write(int reg, int val);

/**
* Timer function for OPL
*/
Expand All @@ -71,11 +98,31 @@ class Music {
* Updates any playing music
*/
void update();

/**
* Does a reset
*/
void reset();

/**
* Sets the frequency for an operator
*/
void setFrequency(byte operatorNum, uint frequency);

/**
* Sets the output level for a channel
*/
void setOutputLevel(byte channelNum, uint level);
protected:
Audio::Mixer *_mixer;
public:
Music(Audio::Mixer *mixer);
~Music();

/**
* Starts an effect playing
*/
void playEffect(uint effectId);
};

} // End of namespace Xeen
Expand Down

0 comments on commit dd06b6f

Please sign in to comment.