2015-02-13 03:13:54 +00:00
|
|
|
#pragma once
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
#include "adlib.h"
|
|
|
|
#include "dbopl.h"
|
2016-02-07 10:22:18 +00:00
|
|
|
// Integer buffer used by DOSBox OPL emulator, later converted to floating point.
|
|
|
|
|
|
|
|
// Number of 32-bit samples to use. ~1 MB per buffer. Probably excessive, but should be safe.
|
|
|
|
// In future, consider using samplesPerBlock value in AdlibBlasterAudioProcessor::prepareToPlay
|
|
|
|
#define INTERMEDIATE_BUF_SAMPLES 100000
|
|
|
|
// Number of static buffers to use. Again probably excessive, but let's be safe.
|
|
|
|
#define INTERMEDIATE_BUF_N 4
|
2015-02-13 03:13:54 +00:00
|
|
|
|
2016-02-07 10:47:22 +00:00
|
|
|
#define OPL_N_REG 256
|
|
|
|
|
2015-02-13 03:13:54 +00:00
|
|
|
enum Waveform
|
|
|
|
{
|
|
|
|
SIN = 0, HALF_SIN = 1, ABS_SIN = 2, QUART_SIN = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
enum FreqMultiple
|
|
|
|
{
|
|
|
|
xHALF=0, x1=1, x2=2, x3=3, x4=4, x5=5, x6=6, x7=7, x8=8, x9=9, x10=10, x12=12, x15=15
|
|
|
|
};
|
|
|
|
|
|
|
|
enum Emulator
|
|
|
|
{
|
|
|
|
DOSBOX=0, ZDOOM=1
|
|
|
|
};
|
|
|
|
|
|
|
|
enum Drum
|
|
|
|
{
|
|
|
|
BDRUM=0x10, SNARE=0x8, TOM=0x4, CYMBAL=0x2, HIHAT=0x1
|
|
|
|
};
|
|
|
|
|
|
|
|
class Hiopl {
|
|
|
|
public:
|
|
|
|
static const int CHANNELS = 9;
|
|
|
|
static const int OSCILLATORS = 2;
|
2016-02-07 10:22:18 +00:00
|
|
|
Hiopl(Emulator emulator = DOSBOX);
|
2015-02-13 03:13:54 +00:00
|
|
|
void SetEmulator(Emulator emulator);
|
|
|
|
void SetPercussionMode(bool enable);
|
|
|
|
void HitPercussion(Drum drum);
|
|
|
|
void ReleasePercussion();
|
|
|
|
|
|
|
|
void Generate(int length, short* buffer);
|
|
|
|
void Generate(int length, float* buffer);
|
|
|
|
void SetSampleRate(int hz);
|
|
|
|
void EnableWaveformControl();
|
|
|
|
void EnableOpl3Mode();
|
|
|
|
|
|
|
|
void EnableTremolo(int ch, int osc, bool enable);
|
|
|
|
void EnableVibrato(int ch, int osc, bool enable);
|
|
|
|
void VibratoDepth(bool high);
|
|
|
|
void TremoloDepth(bool high);
|
|
|
|
void EnableSustain(int ch, int osc, bool enable);
|
|
|
|
void EnableKsr(int ch, int osc, bool enable);
|
|
|
|
// true = additive; false = frequency modulation
|
|
|
|
void EnableAdditiveSynthesis(int ch, bool enable);
|
|
|
|
|
|
|
|
void SetWaveform(int ch, int osc, Waveform wave);
|
|
|
|
void SetAttenuation(int ch, int osc, int level);
|
|
|
|
void SetKsl(int ch, int osc, int level);
|
|
|
|
void SetFrequencyMultiple(int ch, int osc, FreqMultiple mult);
|
|
|
|
void SetEnvelopeAttack(int ch, int osc, int t);
|
|
|
|
void SetEnvelopeDecay(int ch, int osc, int t);
|
|
|
|
void SetEnvelopeSustain(int ch, int osc, int level);
|
|
|
|
void SetEnvelopeRelease(int ch, int osc, int t);
|
|
|
|
// Get register address offset for operator settings for the specified channel and operator.
|
|
|
|
int _GetOffset(int ch, int osc);
|
|
|
|
// Get register address offset for channel-wide register settings for the specified channel.
|
|
|
|
int _GetOffset(int ch);
|
|
|
|
|
|
|
|
void SetModulatorFeedback(int ch, int level);
|
|
|
|
void KeyOn(int ch, float frqHz);
|
|
|
|
void KeyOff(int ch);
|
|
|
|
// Return false if no note is active on the channel (ie release is complete)
|
|
|
|
bool IsActive(int ch);
|
|
|
|
// Return a single character string representing the stage of the envelope for the carrier operator for the channel
|
|
|
|
const char* GetState(int ch) const;
|
|
|
|
void SetFrequency(int ch, float frqHz, bool keyOn=false);
|
|
|
|
void _WriteReg(Bit32u reg, Bit8u value, Bit8u mask=0x0);
|
|
|
|
void _ClearRegBits(Bit32u reg, Bit8u mask);
|
|
|
|
// Read the last value written to the specified register address (cached)
|
|
|
|
Bit8u _ReadReg(Bit32u reg);
|
|
|
|
|
|
|
|
~Hiopl();
|
|
|
|
private:
|
|
|
|
Emulator emulator;
|
|
|
|
DBOPL::Handler *adlib;
|
2016-02-07 10:47:22 +00:00
|
|
|
Bit8u regCache[OPL_N_REG];
|
2016-02-07 10:22:18 +00:00
|
|
|
int intermediateBufIdx;
|
|
|
|
Bit32s intermediateBuf[INTERMEDIATE_BUF_N][INTERMEDIATE_BUF_SAMPLES];
|
2015-02-13 03:13:54 +00:00
|
|
|
bool _CheckParams(int ch, int osc);
|
|
|
|
void _milliHertzToFnum(unsigned int milliHertz, unsigned int *fnum, unsigned int *block, unsigned int conversionFactor=49716);
|
|
|
|
void _ClearRegisters();
|
|
|
|
|
|
|
|
std::map<int, int> _op1offset;
|
|
|
|
std::map<int, int> _op2offset;
|
|
|
|
|
|
|
|
};
|