2014-02-16 20:22:57 +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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef MADS_SOUND_NEBULAR_H
|
|
|
|
#define MADS_SOUND_NEBULAR_H
|
|
|
|
|
|
|
|
#include "common/scummsys.h"
|
|
|
|
#include "common/file.h"
|
2014-02-17 04:04:02 +00:00
|
|
|
#include "common/mutex.h"
|
|
|
|
#include "common/queue.h"
|
2014-02-16 20:22:57 +00:00
|
|
|
#include "audio/audiostream.h"
|
|
|
|
#include "audio/fmopl.h"
|
|
|
|
#include "audio/mixer.h"
|
|
|
|
|
|
|
|
namespace MADS {
|
|
|
|
|
|
|
|
class SoundManager;
|
|
|
|
|
2014-02-19 01:08:58 +00:00
|
|
|
namespace Nebular {
|
|
|
|
|
2014-02-16 20:22:57 +00:00
|
|
|
/**
|
|
|
|
* Represents the data for a channel on the Adlib
|
|
|
|
*/
|
|
|
|
class AdlibChannel {
|
|
|
|
public:
|
|
|
|
int _activeCount;
|
|
|
|
int _field1;
|
|
|
|
int _field2;
|
|
|
|
int _field3;
|
|
|
|
int _field4;
|
2014-02-16 22:02:13 +00:00
|
|
|
int _sampleIndex;
|
2014-02-16 20:22:57 +00:00
|
|
|
int _volume;
|
|
|
|
int _field7;
|
|
|
|
int _field8;
|
|
|
|
int _field9;
|
|
|
|
int _fieldA;
|
2014-02-17 03:26:31 +00:00
|
|
|
uint8 _fieldB;
|
2014-02-16 20:22:57 +00:00
|
|
|
int _fieldC;
|
|
|
|
int _fieldD;
|
|
|
|
int _fieldE;
|
|
|
|
byte *_ptr1;
|
|
|
|
byte *_pSrc;
|
|
|
|
byte *_ptr3;
|
|
|
|
byte *_ptr4;
|
|
|
|
int _field17;
|
|
|
|
int _field19;
|
|
|
|
byte *_soundData;
|
|
|
|
int _field1D;
|
|
|
|
int _field1E;
|
|
|
|
int _field1F;
|
|
|
|
public:
|
|
|
|
AdlibChannel();
|
|
|
|
|
|
|
|
void reset();
|
|
|
|
void enable(int flag);
|
|
|
|
void setPtr2(byte *pData);
|
|
|
|
void load(byte *pData);
|
|
|
|
void check(byte *nullPtr);
|
|
|
|
};
|
|
|
|
|
|
|
|
class AdlibChannelData {
|
|
|
|
public:
|
|
|
|
int _field0;
|
|
|
|
int _freqMask;
|
|
|
|
int _freqBase;
|
|
|
|
int _field6;
|
|
|
|
};
|
|
|
|
|
2014-02-16 22:02:13 +00:00
|
|
|
class AdlibSample {
|
2014-02-16 20:22:57 +00:00
|
|
|
public:
|
2014-02-16 22:02:13 +00:00
|
|
|
int _attackRate;
|
|
|
|
int _decayRate;
|
|
|
|
int _sustainLevel;
|
|
|
|
int _releaseRate;
|
|
|
|
bool _egTyp;
|
|
|
|
bool _ksr;
|
|
|
|
int _totalLevel;
|
|
|
|
int _scalingLevel;
|
|
|
|
int _waveformSelect;
|
|
|
|
int _freqMultiple;
|
|
|
|
int _feedback;
|
|
|
|
bool _ampMod;
|
|
|
|
int _vib;
|
|
|
|
int _alg;
|
2014-02-16 20:22:57 +00:00
|
|
|
int _fieldE;
|
2014-02-16 22:02:13 +00:00
|
|
|
int _freqMask;
|
|
|
|
int _freqBase;
|
2014-02-16 20:22:57 +00:00
|
|
|
int _field14;
|
|
|
|
|
2014-02-16 22:02:13 +00:00
|
|
|
AdlibSample() {}
|
|
|
|
AdlibSample(Common::SeekableReadStream &s);
|
2014-02-16 20:22:57 +00:00
|
|
|
};
|
|
|
|
|
2014-02-17 04:04:02 +00:00
|
|
|
struct RegisterValue {
|
|
|
|
uint8 _regNum;
|
|
|
|
uint8 _value;
|
|
|
|
|
|
|
|
RegisterValue(int regNum, int value) {
|
|
|
|
_regNum = regNum; _value = value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-02-16 20:22:57 +00:00
|
|
|
#define ADLIB_CHANNEL_COUNT 9
|
|
|
|
#define ADLIB_CHANNEL_MIDWAY 5
|
2014-02-17 04:04:02 +00:00
|
|
|
#define CALLBACKS_PER_SECOND 60
|
2014-02-16 20:22:57 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Base class for the sound player resource files
|
|
|
|
*/
|
2014-02-17 04:04:02 +00:00
|
|
|
class ASound: public Audio::AudioStream {
|
2014-02-16 20:22:57 +00:00
|
|
|
private:
|
|
|
|
struct CachedDataEntry {
|
|
|
|
int _offset;
|
|
|
|
byte *_data;
|
|
|
|
};
|
|
|
|
Common::List<CachedDataEntry> _dataCache;
|
|
|
|
uint16 _randomSeed;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Does the initial Adlib initialisation
|
|
|
|
*/
|
|
|
|
void adlibInit();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Does on-going processing for the Adlib sounds being played
|
|
|
|
*/
|
|
|
|
void update();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Polls each of the channels for updates
|
|
|
|
*/
|
|
|
|
void pollChannels();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks the status of the channels
|
|
|
|
*/
|
|
|
|
void checkChannels();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Polls the currently active channel
|
|
|
|
*/
|
|
|
|
void pollActiveChannel();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates the octave of the currently active channel
|
|
|
|
*/
|
|
|
|
void updateOctave();
|
|
|
|
|
|
|
|
void updateChannelState();
|
|
|
|
void updateActiveChannel();
|
2014-02-16 22:02:13 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads up the specified sample
|
|
|
|
*/
|
|
|
|
void loadSample(int sampleIndex);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Writes out the data of the selected sample to the Adlib
|
|
|
|
*/
|
|
|
|
void processSample();
|
|
|
|
|
2014-02-16 20:22:57 +00:00
|
|
|
void updateFNumber();
|
|
|
|
protected:
|
|
|
|
/**
|
2014-02-17 04:04:02 +00:00
|
|
|
* Queue a byte for an Adlib register
|
2014-02-16 20:22:57 +00:00
|
|
|
*/
|
|
|
|
void write(int reg, int val);
|
|
|
|
|
|
|
|
/**
|
2014-02-17 04:04:02 +00:00
|
|
|
* Queue a byte for an Adlib register, and store it in the _ports array
|
2014-02-16 20:22:57 +00:00
|
|
|
*/
|
|
|
|
int write2(int state, int reg, int val);
|
|
|
|
|
2014-02-17 04:04:02 +00:00
|
|
|
/**
|
|
|
|
* Flush any pending Adlib register values to the OPL driver
|
|
|
|
*/
|
|
|
|
void flush();
|
|
|
|
|
2014-02-16 20:22:57 +00:00
|
|
|
/**
|
|
|
|
* Turn a channel on
|
|
|
|
*/
|
|
|
|
void channelOn(int reg, int volume);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Turn a channel off
|
|
|
|
*/
|
|
|
|
void channelOff(int reg);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks for whether a poll result needs to be set
|
|
|
|
*/
|
|
|
|
void resultCheck();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads a data block from the sound file, caching the result for any future
|
|
|
|
* calls for the same data
|
|
|
|
*/
|
|
|
|
byte *loadData(int offset, int size);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Play the specified sound
|
|
|
|
* @param offset Offset of sound data within sound player data segment
|
|
|
|
* @param size Size of sound data block
|
|
|
|
*/
|
|
|
|
void playSound(int offset, int size);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Play the specified raw sound data
|
|
|
|
* @param pData Pointer to data block containing sound data
|
|
|
|
*/
|
|
|
|
void playSound(byte *pData);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks to see whether the given block of data is already loaded into a channel.
|
|
|
|
*/
|
|
|
|
bool isSoundActive(byte *pData);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the frequency for a given channel.
|
|
|
|
*/
|
|
|
|
void setFrequency(int channel, int freq);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a 16-bit random number
|
|
|
|
*/
|
|
|
|
int getRandomNumber();
|
|
|
|
|
|
|
|
int command0();
|
|
|
|
int command1();
|
|
|
|
int command2();
|
|
|
|
int command3();
|
|
|
|
int command4();
|
|
|
|
int command5();
|
|
|
|
int command6();
|
|
|
|
int command7();
|
|
|
|
int command8();
|
|
|
|
public:
|
|
|
|
Audio::Mixer *_mixer;
|
|
|
|
FM_OPL *_opl;
|
2014-02-17 04:04:02 +00:00
|
|
|
Audio::SoundHandle _soundHandle;
|
2014-02-16 20:22:57 +00:00
|
|
|
AdlibChannel _channels[ADLIB_CHANNEL_COUNT];
|
|
|
|
AdlibChannel *_activeChannelPtr;
|
|
|
|
AdlibChannelData _channelData[11];
|
2014-02-16 22:02:13 +00:00
|
|
|
Common::Array<AdlibSample> _samples;
|
|
|
|
AdlibSample *_samplePtr;
|
2014-02-16 20:22:57 +00:00
|
|
|
Common::File _soundFile;
|
2014-02-17 04:04:02 +00:00
|
|
|
Common::Queue<RegisterValue> _queue;
|
|
|
|
Common::Mutex _driverMutex;
|
2014-02-16 20:22:57 +00:00
|
|
|
int _dataOffset;
|
|
|
|
int _frameCounter;
|
|
|
|
bool _isDisabled;
|
|
|
|
int _v1;
|
|
|
|
int _v2;
|
|
|
|
int _activeChannelNumber;
|
|
|
|
int _freqMask1;
|
|
|
|
int _freqMask2;
|
|
|
|
int _freqBase1;
|
|
|
|
int _freqBase2;
|
|
|
|
int _channelNum1, _channelNum2;
|
|
|
|
int _v7;
|
|
|
|
int _v8;
|
|
|
|
int _v9;
|
|
|
|
int _v10;
|
|
|
|
int _pollResult;
|
|
|
|
int _resultFlag;
|
|
|
|
byte _nullData[2];
|
|
|
|
int _ports[256];
|
|
|
|
bool _stateFlag;
|
|
|
|
int _activeChannelReg;
|
|
|
|
int _v11;
|
|
|
|
bool _amDep, _vibDep, _splitPoint;
|
2014-02-17 04:04:02 +00:00
|
|
|
int _samplesPerCallback;
|
|
|
|
int _samplesPerCallbackRemainder;
|
|
|
|
int _samplesTillCallback;
|
|
|
|
int _samplesTillCallbackRemainder;
|
2014-02-16 20:22:57 +00:00
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
* @param filename Specifies the adlib sound player file to use
|
|
|
|
* @param dataOffset Offset in the file of the data segment
|
|
|
|
*/
|
|
|
|
ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffset);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destructor
|
|
|
|
*/
|
|
|
|
virtual ~ASound();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Execute a player command. Most commands represent sounds to play, but some
|
|
|
|
* low number commands also provide control operations
|
|
|
|
*/
|
|
|
|
virtual int command(int commandId) = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop all currently playing sounds
|
|
|
|
*/
|
|
|
|
int stop();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Main poll method to allow sounds to progress
|
|
|
|
*/
|
|
|
|
int poll();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* General noise/note output
|
|
|
|
*/
|
|
|
|
void noise();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the current frame counter
|
|
|
|
*/
|
|
|
|
int getFrameCounter() { return _frameCounter; }
|
2014-02-17 04:04:02 +00:00
|
|
|
|
|
|
|
// AudioStream interface
|
|
|
|
/**
|
|
|
|
* Main buffer read
|
|
|
|
*/
|
|
|
|
virtual int readBuffer(int16 *buffer, const int numSamples);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mono sound only
|
|
|
|
*/
|
|
|
|
virtual bool isStereo() const { return false; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data is continuously pushed, so definitive end
|
|
|
|
*/
|
|
|
|
virtual bool endOfData() const { return false; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return sample rate
|
|
|
|
*/
|
|
|
|
virtual int getRate() const { return 11025; }
|
2014-02-16 20:22:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class ASound1: public ASound {
|
|
|
|
private:
|
|
|
|
typedef int (ASound1::*CommandPtr)();
|
|
|
|
static const CommandPtr _commandList[42];
|
|
|
|
bool _cmd23Toggle;
|
|
|
|
|
|
|
|
int command9();
|
|
|
|
int command10();
|
|
|
|
int command11();
|
|
|
|
int command12();
|
|
|
|
int command13();
|
|
|
|
int command14();
|
|
|
|
int command15();
|
|
|
|
int command16();
|
|
|
|
int command17();
|
|
|
|
int command18();
|
|
|
|
int command19();
|
|
|
|
int command20();
|
|
|
|
int command21();
|
|
|
|
int command22();
|
|
|
|
int command23();
|
|
|
|
int command24();
|
|
|
|
int command25();
|
|
|
|
int command26();
|
|
|
|
int command27();
|
|
|
|
int command28();
|
|
|
|
int command29();
|
|
|
|
int command30();
|
|
|
|
int command31();
|
|
|
|
int command32();
|
|
|
|
int command33();
|
|
|
|
int command34();
|
|
|
|
int command35();
|
|
|
|
int command36();
|
|
|
|
int command37();
|
|
|
|
int command38();
|
|
|
|
int command39();
|
|
|
|
int command40();
|
|
|
|
int command41();
|
|
|
|
|
|
|
|
void command111213();
|
|
|
|
void command2627293032();
|
|
|
|
public:
|
|
|
|
ASound1(Audio::Mixer *mixer);
|
|
|
|
|
|
|
|
virtual int command(int commandId);
|
|
|
|
};
|
|
|
|
|
|
|
|
} // End of namespace Nebular
|
|
|
|
|
|
|
|
} // End of namespace MADS
|
|
|
|
|
|
|
|
#endif /* MADS_SOUND_NEBULAR_H */
|