1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
|
/* 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 GOB_SOUND_ADLIB_H
#define GOB_SOUND_ADLIB_H
#include "common/mutex.h"
#include "audio/mixer.h"
namespace OPL {
class OPL;
}
namespace Gob {
/** Base class for a player of an AdLib music format. */
class AdLib {
public:
AdLib(int callbackFrequency);
virtual ~AdLib();
bool isPlaying() const; ///< Are we currently playing?
int32 getRepeating() const; ///< Return number of times left to loop.
/** Set the loop counter.
*
* @param repCount Number of times to loop (i.e. number of additional
* paythroughs to the first one, not overall).
* A negative value means infinite looping.
*/
void setRepeating(int32 repCount);
void startPlay();
void stopPlay();
void syncVolume();
protected:
enum kVoice {
kVoiceMelody0 = 0,
kVoiceMelody1 = 1,
kVoiceMelody2 = 2,
kVoiceMelody3 = 3,
kVoiceMelody4 = 4,
kVoiceMelody5 = 5,
kVoiceMelody6 = 6, // Only available in melody mode.
kVoiceMelody7 = 7, // Only available in melody mode.
kVoiceMelody8 = 8, // Only available in melody mode.
kVoiceBaseDrum = 6, // Only available in percussion mode.
kVoiceSnareDrum = 7, // Only available in percussion mode.
kVoiceTom = 8, // Only available in percussion mode.
kVoiceCymbal = 9, // Only available in percussion mode.
kVoiceHihat = 10 // Only available in percussion mode.
};
/** Operator parameters. */
enum kParam {
kParamKeyScaleLevel = 0,
kParamFreqMulti = 1,
kParamFeedback = 2,
kParamAttack = 3,
kParamSustain = 4,
kParamSustaining = 5,
kParamDecay = 6,
kParamRelease = 7,
kParamLevel = 8,
kParamAM = 9,
kParamVib = 10,
kParamKeyScaleRate = 11,
kParamFM = 12,
kParamWaveSelect = 13
};
static const int kOperatorCount = 18; ///< Number of operators.
static const int kParamCount = 14; ///< Number of operator parameters.
static const int kPitchStepCount = 25; ///< Number of pitch bend steps in a half tone.
static const int kOctaveCount = 8; ///< Number of octaves we can play.
static const int kHalfToneCount = 12; ///< Number of half tones in an octave.
static const int kOperatorsPerVoice = 2; ///< Number of operators per voice.
static const int kMelodyVoiceCount = 9; ///< Number of melody voices.
static const int kPercussionVoiceCount = 5; ///< Number of percussion voices.
static const int kMaxVoiceCount = 11; ///< Max number of voices.
/** Number of notes we can play. */
static const int kNoteCount = kHalfToneCount * kOctaveCount;
static const int kMaxVolume = 0x007F;
static const int kMaxPitch = 0x3FFF;
static const int kMidPitch = 0x2000;
static const int kStandardMidC = 60; ///< A mid C in standard MIDI.
static const int kOPLMidC = 48; ///< A mid C for the OPL.
/** Write a value into an OPL register. */
void writeOPL(byte reg, byte val);
/** Signal that the playback ended.
*
* @param killRepeat Explicitly request that the song is not to be looped.
*/
void end(bool killRepeat = false);
/** The callback function that's called for polling more AdLib commands.
*
* @param first Is this the first poll since the start of the song?
* @return The number of ticks until the next poll.
*/
virtual uint32 pollMusic(bool first) = 0;
/** Rewind the song. */
virtual void rewind() = 0;
/** Return whether we're in percussion mode. */
bool isPercussionMode() const;
/** Set percussion or melody mode. */
void setPercussionMode(bool percussion);
/** Enable/Disable the wave select operator parameters.
*
* When disabled, all operators use the sine wave, regardless of the parameter.
*/
void enableWaveSelect(bool enable);
/** Change the pitch bend range.
*
* @param range The range in half tones from 1 to 12 inclusive.
* See bendVoicePitch() for how this works in practice.
*/
void setPitchRange(uint8 range);
/** Set the tremolo (amplitude vibrato) depth.
*
* @param tremoloDepth false: 1.0dB, true: 4.8dB.
*/
void setTremoloDepth(bool tremoloDepth);
/** Set the frequency vibrato depth.
*
* @param vibratoDepth false: 7 cent, true: 14 cent. 1 cent = 1/100 half tone.
*/
void setVibratoDepth(bool vibratoDepth);
/** Set the keyboard split point. */
void setKeySplit(bool keySplit);
/** Set the timbre of a voice.
*
* Layout of the operator parameters is as follows:
* - First 13 parameter for the first operator
* - First 13 parameter for the second operator
* - 14th parameter (wave select) for the first operator
* - 14th parameter (wave select) for the second operator
*/
void setVoiceTimbre(uint8 voice, const uint16 *params);
/** Set a voice's volume. */
void setVoiceVolume(uint8 voice, uint8 volume);
/** Bend a voice's pitch.
*
* The pitchBend parameter is a value between 0 (full down) and kMaxPitch (full up).
* The actual frequency depends on the pitch range set previously by setPitchRange(),
* with full down being -range half tones and full up range half tones.
*/
void bendVoicePitch(uint8 voice, uint16 pitchBend);
/** Switch a voice on.
*
* Plays one of the kNoteCount notes. However, the valid range of a note is between
* 0 and 127, of which only 12 to 107 are audible.
*/
void noteOn(uint8 voice, uint8 note);
/** Switch a voice off. */
void noteOff(uint8 voice);
/**
* Set the OPL timer frequency
*/
void setTimerFrequency(int timerFrequency);
private:
static const uint8 kVolumeTable[Audio::Mixer::kMaxMixerVolume + 1];
static const uint8 kOperatorType [kOperatorCount];
static const uint8 kOperatorOffset[kOperatorCount];
static const uint8 kOperatorVoice [kOperatorCount];
static const uint8 kVoiceMelodyOperator [kOperatorsPerVoice][kMelodyVoiceCount];
static const uint8 kVoicePercussionOperator[kOperatorsPerVoice][kPercussionVoiceCount];
static const byte kPercussionMasks[kPercussionVoiceCount];
static const uint16 kPianoParams [kOperatorsPerVoice][kParamCount];
static const uint16 kBaseDrumParams [kOperatorsPerVoice][kParamCount];
static const uint16 kSnareDrumParams[kParamCount];
static const uint16 kTomParams [kParamCount];
static const uint16 kCymbalParams [kParamCount];
static const uint16 kHihatParams [kParamCount];
OPL::OPL *_opl;
Common::Mutex _mutex;
int _volume;
uint32 _toPoll;
int32 _repCount;
bool _first;
bool _playing;
bool _ended;
bool _tremoloDepth;
bool _vibratoDepth;
bool _keySplit;
bool _enableWaveSelect;
bool _percussionMode;
byte _percussionBits;
uint8 _pitchRange;
uint16 _pitchRangeStep;
uint8 _voiceNote[kMaxVoiceCount]; // Last note of each voice
uint8 _voiceOn [kMaxVoiceCount]; // Whether each voice is currently on
uint8 _operatorVolume[kOperatorCount]; // Volume of each operator
byte _operatorParams[kOperatorCount][kParamCount]; // All operator parameters
uint16 _freqs[kPitchStepCount][kHalfToneCount];
uint16 *_freqPtr[kMaxVoiceCount];
int _halfToneOffset[kMaxVoiceCount];
void createOPL();
void initOPL();
void reset();
void allOff();
// Write global parameters into the OPL
void writeTremoloVibratoDepthPercMode();
void writeKeySplit();
// Write operator parameters into the OPL
void writeWaveSelect(uint8 oper);
void writeTremoloVibratoSustainingKeyScaleRateFreqMulti(uint8 oper);
void writeSustainRelease(uint8 oper);
void writeAttackDecay(uint8 oper);
void writeFeedbackFM(uint8 oper);
void writeKeyScaleLevelVolume(uint8 oper);
void writeAllParams(uint8 oper);
void initOperatorParams();
void initOperatorVolumes();
void setOperatorParams(uint8 oper, const uint16 *params, uint8 wave);
void voiceOff(uint8 voice);
void initFreqs();
void setFreqs(uint16 *freqs, int32 num, int32 denom);
int32 calcFreq(int32 deltaDemiToneNum, int32 deltaDemiToneDenom);
void resetFreqs();
void changePitch(uint8 voice, uint16 pitchBend);
void setFreq(uint8 voice, uint16 note, bool on);
/**
* Callback function for OPL
*/
void onTimer();
};
} // End of namespace Gob
#endif // GOB_SOUND_ADLIB_H
|