2020-04-04 00:05:36 +00:00
|
|
|
//
|
|
|
|
// OPL2.hpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 02/04/2020.
|
|
|
|
// Copyright © 2020 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef OPL2_hpp
|
|
|
|
#define OPL2_hpp
|
|
|
|
|
|
|
|
#include "../../Outputs/Speaker/Implementation/SampleSource.hpp"
|
|
|
|
#include "../../Concurrency/AsyncTaskQueue.hpp"
|
2020-04-06 02:57:53 +00:00
|
|
|
#include "../../Numeric/LFSR.hpp"
|
2020-04-04 00:05:36 +00:00
|
|
|
|
2020-04-14 22:32:06 +00:00
|
|
|
#include <atomic>
|
2020-04-12 16:46:40 +00:00
|
|
|
#include <cmath>
|
|
|
|
|
2020-04-04 00:05:36 +00:00
|
|
|
namespace Yamaha {
|
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
|
|
|
|
namespace OPL {
|
|
|
|
|
2020-04-11 02:05:22 +00:00
|
|
|
/*!
|
|
|
|
Describes the ephemeral state of an operator.
|
|
|
|
*/
|
|
|
|
struct OperatorState {
|
|
|
|
public:
|
2020-04-14 22:32:06 +00:00
|
|
|
int phase = 0; // Will be in the range [0, 1023], mapping into a 1024-unit sine curve.
|
|
|
|
int attenuation = 255; // Will be in the range [0, 1023].
|
2020-04-11 02:05:22 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
int divider_ = 0;
|
|
|
|
int raw_phase_ = 0;
|
|
|
|
|
2020-04-14 01:39:06 +00:00
|
|
|
enum class ADSRPhase {
|
|
|
|
Attack, Decay, Sustain, Release
|
|
|
|
} adsr_phase_ = ADSRPhase::Attack;
|
|
|
|
int time_in_phase_ = 0;
|
|
|
|
int adsr_attenuation_ = 511;
|
|
|
|
bool last_key_on_ = false;
|
|
|
|
|
2020-04-11 02:05:22 +00:00
|
|
|
friend class Operator;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Describes parts of an operator that are genuinely stored per-operator on the OPLL;
|
|
|
|
these can be provided to the Operator in order to have it ignore its local values
|
|
|
|
if the host is an OPLL or VRC7.
|
|
|
|
*/
|
|
|
|
struct OperatorOverrides {
|
2020-04-14 01:39:06 +00:00
|
|
|
int attenuation = 0;
|
2020-04-11 02:05:22 +00:00
|
|
|
bool hold_sustain_level = false;
|
|
|
|
};
|
|
|
|
|
2020-04-10 23:13:52 +00:00
|
|
|
/*!
|
|
|
|
Models an operator.
|
|
|
|
|
|
|
|
In Yamaha FM terms, an operator is a combination of a few things:
|
|
|
|
|
|
|
|
* an oscillator, producing one of a handful of sine-derived waveforms;
|
|
|
|
* an ADSR output level envelope; and
|
|
|
|
* a bunch of potential adjustments to those two things:
|
|
|
|
* optional tremolo and/or vibrato (the rates of which are global);
|
|
|
|
* the option to skip 'sustain' in ADSR and go straight to release (since no sustain period is supplied,
|
|
|
|
it otherwise runs for as long as the programmer leaves a channel enabled);
|
|
|
|
* an attenuation for the output level; and
|
|
|
|
* a factor by which to speed up the ADSR envelope as a function of frequency.
|
|
|
|
|
|
|
|
Oscillator frequency isn't set directly, it's a multiple of the owning channel, in which
|
|
|
|
frequency is set as a combination of f-num and octave.
|
|
|
|
*/
|
|
|
|
class Operator {
|
|
|
|
public:
|
|
|
|
/// Sets this operator's attack rate as the top nibble of @c value, its decay rate as the bottom nibble.
|
|
|
|
void set_attack_decay(uint8_t value) {
|
2020-04-14 01:39:06 +00:00
|
|
|
attack_rate_ = (value & 0xf0) >> 2;
|
|
|
|
decay_rate_ = (value & 0x0f) << 2;
|
2020-04-10 23:13:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets this operator's sustain level as the top nibble of @c value, its release rate as the bottom nibble.
|
|
|
|
void set_sustain_release(uint8_t value) {
|
2020-04-14 01:39:06 +00:00
|
|
|
sustain_level_ = (value & 0xf0) >> 4;
|
|
|
|
release_rate_ = (value & 0x0f) << 2;
|
2020-04-10 23:13:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets this operator's key scale level as the top two bits of @c value, its total output level as the low six bits.
|
|
|
|
void set_scaling_output(uint8_t value) {
|
|
|
|
scaling_level = value >> 6;
|
2020-04-14 01:39:06 +00:00
|
|
|
attenuation_ = value & 0x3f;
|
2020-04-10 23:13:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets this operator's waveform using the low two bits of @c value.
|
|
|
|
void set_waveform(uint8_t value) {
|
|
|
|
waveform = Operator::Waveform(value & 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// From the top nibble of @c value sets the AM, vibrato, hold/sustain level and keyboard sampling rate flags;
|
|
|
|
/// uses the bottom nibble to set the frequency multiplier.
|
|
|
|
void set_am_vibrato_hold_sustain_ksr_multiple(uint8_t value) {
|
|
|
|
apply_amplitude_modulation = value & 0x80;
|
|
|
|
apply_vibrato = value & 0x40;
|
|
|
|
hold_sustain_level = value & 0x20;
|
|
|
|
keyboard_scaling_rate = value & 0x10;
|
|
|
|
frequency_multiple = value & 0xf;
|
|
|
|
}
|
|
|
|
|
2020-04-14 01:39:06 +00:00
|
|
|
void update(OperatorState &state, bool key_on, int channel_frequency, int channel_octave, OperatorOverrides *overrides = nullptr);
|
|
|
|
|
|
|
|
bool is_audible(OperatorState &state, OperatorOverrides *overrides = nullptr) {
|
2020-04-14 02:12:55 +00:00
|
|
|
if(state.adsr_phase_ == OperatorState::ADSRPhase::Release) {
|
|
|
|
if(overrides) {
|
|
|
|
if(overrides->attenuation == 0xf) return false;
|
|
|
|
} else {
|
|
|
|
if(attenuation_ == 0x3f) return false;
|
|
|
|
}
|
2020-04-14 01:39:06 +00:00
|
|
|
}
|
|
|
|
return state.adsr_attenuation_ != 511;
|
2020-04-10 23:13:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
/// If true then an amplitude modulation of "3.7Hz" is applied,
|
|
|
|
/// with a depth "determined by the AM-DEPTH of the BD register"?
|
|
|
|
bool apply_amplitude_modulation = false;
|
|
|
|
|
|
|
|
/// If true then a vibrato of '6.4 Hz' is applied, with a depth
|
|
|
|
/// "determined by VOB_DEPTH of the BD register"?
|
|
|
|
bool apply_vibrato = false;
|
|
|
|
|
|
|
|
/// Selects between an ADSR envelope that holds at the sustain level
|
|
|
|
/// for as long as this key is on, releasing afterwards, and one that
|
|
|
|
/// simply switches straight to the release rate once the sustain
|
|
|
|
/// level is hit, getting back to 0 regardless of an ongoing key-on.
|
|
|
|
bool hold_sustain_level = false;
|
|
|
|
|
|
|
|
/// Provides a potential faster step through the ADSR envelope. Cf. p12.
|
|
|
|
bool keyboard_scaling_rate = false;
|
|
|
|
|
|
|
|
/// Indexes a lookup table to determine what multiple of the channel's frequency
|
|
|
|
/// this operator is advancing at.
|
|
|
|
int frequency_multiple = 0;
|
|
|
|
|
|
|
|
/// Sets the current output level of this modulator, as an attenuation.
|
2020-04-14 01:39:06 +00:00
|
|
|
int attenuation_ = 0;
|
2020-04-10 23:13:52 +00:00
|
|
|
|
|
|
|
/// Selects attenuation that is applied as a function of interval. Cf. p14.
|
|
|
|
int scaling_level = 0;
|
|
|
|
|
2020-04-12 16:46:40 +00:00
|
|
|
/// Sets the ADSR rates. These all provide the top four bits of a six-bit number;
|
|
|
|
/// the bottom two bits... are 'RL'?
|
2020-04-14 01:39:06 +00:00
|
|
|
int attack_rate_ = 0;
|
|
|
|
int decay_rate_ = 0;
|
|
|
|
int sustain_level_ = 0;
|
|
|
|
int release_rate_ = 0;
|
2020-04-10 23:13:52 +00:00
|
|
|
|
|
|
|
/// Selects the generated waveform.
|
|
|
|
enum class Waveform {
|
|
|
|
Sine, HalfSine, AbsSine, PulseSine
|
|
|
|
} waveform = Waveform::Sine;
|
2020-04-08 03:15:26 +00:00
|
|
|
};
|
|
|
|
|
2020-04-10 23:13:52 +00:00
|
|
|
/*!
|
|
|
|
Models an L-type two-operator channel.
|
|
|
|
|
|
|
|
Assuming FM synthesis is enabled, the channel modulates the output of the carrier with that of the modulator.
|
|
|
|
*/
|
2020-04-11 02:05:22 +00:00
|
|
|
class Channel {
|
|
|
|
public:
|
|
|
|
/// Sets the low 8 bits of frequency control.
|
|
|
|
void set_frequency_low(uint8_t value) {
|
|
|
|
frequency = (frequency &~0xff) | value;
|
|
|
|
}
|
2020-04-10 23:13:52 +00:00
|
|
|
|
2020-04-11 02:05:22 +00:00
|
|
|
/// Sets the high two bits of a 10-bit frequency control, along with this channel's
|
|
|
|
/// block/octave, and key on or off.
|
|
|
|
void set_10bit_frequency_octave_key_on(uint8_t value) {
|
|
|
|
frequency = (frequency & 0xff) | ((value & 3) << 8);
|
|
|
|
octave = (value >> 2) & 0x7;
|
2020-04-12 18:15:09 +00:00
|
|
|
key_on = value & 0x20;
|
|
|
|
frequency_shift = 0;
|
2020-04-11 02:05:22 +00:00
|
|
|
}
|
2020-04-10 23:13:52 +00:00
|
|
|
|
2020-04-11 02:05:22 +00:00
|
|
|
/// Sets the high two bits of a 9-bit frequency control, along with this channel's
|
|
|
|
/// block/octave, and key on or off.
|
|
|
|
void set_9bit_frequency_octave_key_on(uint8_t value) {
|
|
|
|
frequency = (frequency & 0xff) | ((value & 1) << 8);
|
|
|
|
octave = (value >> 1) & 0x7;
|
|
|
|
key_on = value & 0x10;;
|
2020-04-12 18:15:09 +00:00
|
|
|
frequency_shift = 1;
|
2020-04-11 02:05:22 +00:00
|
|
|
}
|
2020-04-10 23:13:52 +00:00
|
|
|
|
2020-04-11 02:05:22 +00:00
|
|
|
/// Sets the amount of feedback provided to the first operator (i.e. the modulator)
|
|
|
|
/// associated with this channel, and whether FM synthesis is in use.
|
|
|
|
void set_feedback_mode(uint8_t value) {
|
|
|
|
feedback_strength = (value >> 1) & 0x7;
|
|
|
|
use_fm_synthesis = value & 1;
|
|
|
|
}
|
2020-04-10 23:13:52 +00:00
|
|
|
|
2020-04-12 16:46:40 +00:00
|
|
|
/// This should be called at a rate of around 49,716 Hz; it returns the current output level
|
|
|
|
/// level for this channel.
|
2020-04-14 01:39:06 +00:00
|
|
|
int update(Operator *modulator, Operator *carrier, OperatorOverrides *modulator_overrides = nullptr, OperatorOverrides *carrier_overrides = nullptr) {
|
2020-04-14 22:32:06 +00:00
|
|
|
modulator->update(modulator_state_, key_on, frequency << frequency_shift, octave, modulator_overrides);
|
2020-04-14 01:39:06 +00:00
|
|
|
carrier->update(carrier_state_, key_on, frequency << frequency_shift, octave, carrier_overrides);
|
2020-04-12 16:46:40 +00:00
|
|
|
|
|
|
|
// TODO: almost everything else. This is a quick test.
|
2020-04-14 22:32:06 +00:00
|
|
|
// Specifically: use lookup tables.
|
|
|
|
const float carrier_volume = logf(float(carrier_state_.attenuation + 1)) / logf(1023.0);
|
|
|
|
const float modulator_volume = logf(float(modulator_state_.attenuation + 1)) / logf(1023.0);
|
|
|
|
|
|
|
|
const float modulator_output = modulator_volume * sinf(float(modulator_state_.phase) / 1024.0f);
|
|
|
|
return int(carrier_volume * sinf(modulator_output + (float(carrier_state_.phase) / 1024.0f)) * 20000.0f);
|
2020-04-12 16:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @returns @c true if this channel is currently producing any audio; @c false otherwise;
|
2020-04-14 01:39:06 +00:00
|
|
|
bool is_audible(Operator *carrier, OperatorOverrides *carrier_overrides = nullptr) {
|
|
|
|
return carrier->is_audible(carrier_state_, carrier_overrides);
|
2020-04-11 02:05:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
/// 'F-Num' in the spec; this plus the current octave determines channel frequency.
|
|
|
|
int frequency = 0;
|
|
|
|
|
|
|
|
/// Linked with the frequency, determines the channel frequency.
|
|
|
|
int octave = 0;
|
2020-04-09 03:15:44 +00:00
|
|
|
|
2020-04-11 02:05:22 +00:00
|
|
|
/// Sets sets this channel on or off, as an input to the ADSR envelope,
|
|
|
|
bool key_on = false;
|
|
|
|
|
|
|
|
/// Sets the degree of feedback applied to the modulator.
|
|
|
|
int feedback_strength = 0;
|
|
|
|
|
|
|
|
/// Selects between FM synthesis, using the modulator to modulate the carrier, or simple mixing of the two
|
|
|
|
/// underlying operators as completely disjoint entities.
|
|
|
|
bool use_fm_synthesis = true;
|
|
|
|
|
2020-04-12 18:15:09 +00:00
|
|
|
/// Used internally to make both the 10-bit OPL2 frequency selection and 9-bit OPLL/VRC7 frequency
|
|
|
|
/// selections look the same when passed to the operators.
|
|
|
|
int frequency_shift = 0;
|
|
|
|
|
2020-04-11 02:05:22 +00:00
|
|
|
// Stored separately because carrier/modulator may not be unique per channel —
|
|
|
|
// on the OPLL there's an extra level of indirection.
|
|
|
|
OperatorState carrier_state_, modulator_state_;
|
2020-04-08 03:15:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename Child> class OPLBase: public ::Outputs::Speaker::SampleSource {
|
2020-04-04 00:05:36 +00:00
|
|
|
public:
|
2020-04-08 03:15:26 +00:00
|
|
|
void write(uint16_t address, uint8_t value);
|
2020-04-04 00:05:36 +00:00
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
protected:
|
|
|
|
OPLBase(Concurrency::DeferringAsyncTaskQueue &task_queue);
|
|
|
|
|
|
|
|
Concurrency::DeferringAsyncTaskQueue &task_queue_;
|
|
|
|
|
|
|
|
int exponential_[256];
|
|
|
|
int log_sin_[256];
|
|
|
|
|
|
|
|
uint8_t depth_rhythm_control_;
|
|
|
|
uint8_t csm_keyboard_split_;
|
|
|
|
bool waveform_enable_;
|
|
|
|
|
|
|
|
private:
|
|
|
|
uint8_t selected_register_ = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct OPL2: public OPLBase<OPL2> {
|
|
|
|
public:
|
|
|
|
// Creates a new OPL2.
|
|
|
|
OPL2(Concurrency::DeferringAsyncTaskQueue &task_queue);
|
2020-04-04 00:05:36 +00:00
|
|
|
|
|
|
|
/// As per ::SampleSource; provides a broadphase test for silence.
|
|
|
|
bool is_zero_level();
|
|
|
|
|
|
|
|
/// As per ::SampleSource; provides audio output.
|
|
|
|
void get_samples(std::size_t number_of_samples, std::int16_t *target);
|
|
|
|
void set_sample_volume_range(std::int16_t range);
|
|
|
|
|
|
|
|
/// Reads from the OPL.
|
|
|
|
uint8_t read(uint16_t address);
|
|
|
|
|
|
|
|
private:
|
2020-04-08 03:15:26 +00:00
|
|
|
friend OPLBase<OPL2>;
|
2020-04-05 03:29:25 +00:00
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
Operator operators_[18];
|
|
|
|
Channel channels_[9];
|
2020-04-05 03:39:09 +00:00
|
|
|
|
2020-04-06 02:57:53 +00:00
|
|
|
// This is the correct LSFR per forums.submarine.org.uk.
|
|
|
|
Numeric::LFSR<uint32_t, 0x800302> noise_source_;
|
|
|
|
|
2020-04-05 03:39:09 +00:00
|
|
|
// Synchronous properties, valid only on the emulation thread.
|
2020-04-08 03:15:26 +00:00
|
|
|
uint8_t timers_[2] = {0, 0};
|
|
|
|
uint8_t timer_control_ = 0;
|
2020-04-06 02:57:53 +00:00
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
void write_register(uint8_t address, uint8_t value);
|
2020-04-04 00:05:36 +00:00
|
|
|
};
|
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
struct OPLL: public OPLBase<OPLL> {
|
|
|
|
public:
|
|
|
|
// Creates a new OPLL or VRC7.
|
2020-04-12 16:46:40 +00:00
|
|
|
OPLL(Concurrency::DeferringAsyncTaskQueue &task_queue, int audio_divider = 1, bool is_vrc7 = false);
|
2020-04-08 03:15:26 +00:00
|
|
|
|
|
|
|
/// As per ::SampleSource; provides a broadphase test for silence.
|
|
|
|
bool is_zero_level();
|
|
|
|
|
|
|
|
/// As per ::SampleSource; provides audio output.
|
|
|
|
void get_samples(std::size_t number_of_samples, std::int16_t *target);
|
|
|
|
void set_sample_volume_range(std::int16_t range);
|
|
|
|
|
|
|
|
/// Reads from the OPL.
|
|
|
|
uint8_t read(uint16_t address);
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend OPLBase<OPLL>;
|
|
|
|
|
2020-04-11 02:05:22 +00:00
|
|
|
Operator operators_[38]; // There's an extra level of indirection with the OPLL; these 38
|
|
|
|
// operators are to describe 19 hypothetical channels, being
|
|
|
|
// one user-configurable channel, 15 hard-coded channels, and
|
|
|
|
// three channels configured for rhythm generation.
|
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
struct Channel: public ::Yamaha::OPL::Channel {
|
2020-04-14 01:39:06 +00:00
|
|
|
int update() {
|
|
|
|
return Yamaha::OPL::Channel::update(modulator, modulator + 1, nullptr, &overrides);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_audible() {
|
|
|
|
return Yamaha::OPL::Channel::is_audible(modulator + 1, &overrides);
|
|
|
|
}
|
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
Operator *modulator; // Implicitly, the carrier is modulator+1.
|
2020-04-11 02:05:22 +00:00
|
|
|
OperatorOverrides overrides;
|
2020-04-12 16:46:40 +00:00
|
|
|
int level = 0;
|
2020-04-08 03:15:26 +00:00
|
|
|
};
|
2020-04-12 16:46:40 +00:00
|
|
|
void update_all_chanels() {
|
|
|
|
for(int c = 0; c < 6; ++ c) { // Don't do anything with channels that might be percussion for now.
|
2020-04-14 22:32:06 +00:00
|
|
|
channels_[c].level = (channels_[c].update() * total_volume_) >> 14;
|
2020-04-12 16:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-08 03:15:26 +00:00
|
|
|
Channel channels_[9];
|
|
|
|
|
|
|
|
void setup_fixed_instrument(int number, const uint8_t *data);
|
|
|
|
uint8_t custom_instrument_[8];
|
|
|
|
|
|
|
|
void write_register(uint8_t address, uint8_t value);
|
2020-04-12 16:46:40 +00:00
|
|
|
|
|
|
|
const int audio_divider_ = 1;
|
|
|
|
int audio_offset_ = 0;
|
2020-04-14 22:32:06 +00:00
|
|
|
|
|
|
|
std::atomic<int> total_volume_;
|
2020-04-08 03:15:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
2020-04-04 00:05:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* OPL2_hpp */
|