mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-01 17:31:18 +00:00
Moves complete phase -> output calculation inside Operator.
Reasoning being: otherwise I wasn't currently enforcing non-sine waveforms.
This commit is contained in:
parent
020c760976
commit
92d0c466c2
@ -35,22 +35,21 @@ void Channel::set_feedback_mode(uint8_t value) {
|
||||
}
|
||||
|
||||
int Channel::update(Operator *modulator, Operator *carrier, OperatorOverrides *modulator_overrides, OperatorOverrides *carrier_overrides) {
|
||||
modulator->update(modulator_state_, key_on_, period_ << frequency_shift_, octave_, modulator_overrides);
|
||||
carrier->update(carrier_state_, key_on_, period_ << frequency_shift_, octave_, carrier_overrides);
|
||||
|
||||
const auto modulator_level = level(modulator_state_);
|
||||
if(use_fm_synthesis_) {
|
||||
return level(carrier_state_, modulator_level) << 2;
|
||||
// Get modulator level, use that as a phase-adjusting input to the carrier and then return the carrier level.
|
||||
modulator->update(modulator_state_, key_on_, period_ << frequency_shift_, octave_, 0, modulator_overrides);
|
||||
const auto modulator_level = modulator_state_.level();
|
||||
|
||||
carrier->update(carrier_state_, key_on_, period_ << frequency_shift_, octave_, modulator_level, carrier_overrides);
|
||||
return carrier_state_.level() << 2;
|
||||
} else {
|
||||
return (modulator_level + level(carrier_state_)) << 1;
|
||||
// Get modulator and carrier levels separately, return their sum.
|
||||
modulator->update(modulator_state_, key_on_, period_ << frequency_shift_, octave_, 0, modulator_overrides);
|
||||
carrier->update(carrier_state_, key_on_, period_ << frequency_shift_, octave_, 0, carrier_overrides);
|
||||
return (modulator_state_.level() + carrier_state_.level()) << 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool Channel::is_audible(Operator *carrier, OperatorOverrides *carrier_overrides) {
|
||||
return carrier->is_audible(carrier_state_, carrier_overrides);
|
||||
}
|
||||
|
||||
int Channel::level(OperatorState &state, int modulator_level) {
|
||||
const auto log_sin = negative_log_sin(modulator_level + state.phase);
|
||||
return power_two(log_sin.logsin + state.attenuation) * log_sin.sign;
|
||||
}
|
||||
|
@ -46,9 +46,6 @@ class Channel {
|
||||
bool is_audible(Operator *carrier, OperatorOverrides *carrier_overrides = nullptr);
|
||||
|
||||
private:
|
||||
/// @returns The linear output level for the operator with state @c state and with an [optional] modulation input of @c modulator_level.
|
||||
int level(OperatorState &state, int modulator_level = 0);
|
||||
|
||||
/// 'F-Num' in the spec; this plus the current octave determines channel frequency.
|
||||
int period_ = 0;
|
||||
|
||||
|
@ -9,9 +9,14 @@
|
||||
#include "Operator.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include "Tables.h"
|
||||
|
||||
using namespace Yamaha::OPL;
|
||||
|
||||
int OperatorState::level() {
|
||||
return power_two(attenuation.logsin) * attenuation.sign;
|
||||
}
|
||||
|
||||
void Operator::set_attack_decay(uint8_t value) {
|
||||
attack_rate_ = (value & 0xf0) >> 2;
|
||||
decay_rate_ = (value & 0x0f) << 2;
|
||||
@ -50,7 +55,7 @@ bool Operator::is_audible(OperatorState &state, OperatorOverrides *overrides) {
|
||||
return state.adsr_attenuation_ != 511;
|
||||
}
|
||||
|
||||
void Operator::update(OperatorState &state, bool key_on, int channel_period, int channel_octave, OperatorOverrides *overrides) {
|
||||
void Operator::update(OperatorState &state, bool key_on, int channel_period, int channel_octave, int phase_offset, OperatorOverrides *overrides) {
|
||||
// Per the documentation:
|
||||
//
|
||||
// Delta phase = ( [desired freq] * 2^19 / [input clock / 72] ) / 2 ^ (b - 1)
|
||||
@ -73,8 +78,8 @@ void Operator::update(OperatorState &state, bool key_on, int channel_period, int
|
||||
{511, 511, 511, 511}, // AbsSine: endlessly repeat the first half of the sine wave.
|
||||
{255, 0, 255, 0}, // PulseSine: act as if the first quadrant is in the first and third; lock the other two to 0.
|
||||
};
|
||||
const int phase = state.raw_phase_ >> 11;
|
||||
state.phase = phase & waveforms[int(waveform_)][(phase >> 8) & 3];
|
||||
const int phase = (state.raw_phase_ >> 12) + phase_offset;
|
||||
state.attenuation = negative_log_sin(phase & waveforms[int(waveform_)][(phase >> 8) & 3]);
|
||||
|
||||
// Key-on logic: any time it is false, be in the release state.
|
||||
// On the leading edge of it becoming true, enter the attack state.
|
||||
@ -169,10 +174,15 @@ void Operator::update(OperatorState &state, bool key_on, int channel_period, int
|
||||
state.time_in_phase_ = 0;
|
||||
}
|
||||
|
||||
// Combine the ADSR attenuation and overall channel attenuation, clamping to the permitted range.
|
||||
// Combine the ADSR attenuation and overall channel attenuation.
|
||||
if(overrides) {
|
||||
state.attenuation = state.adsr_attenuation_ + (overrides->attenuation << 4);
|
||||
// Overrides here represent per-channel volume on an OPLL. The bits are defined to represent
|
||||
// attenuations of 24db to 3db; the main envelope generator is stated to have a resolution of
|
||||
// 0.325db (which I've assumed is supposed to say 0.375db).
|
||||
state.attenuation.logsin += state.adsr_attenuation_ + (overrides->attenuation << 4);
|
||||
} else {
|
||||
state.attenuation = state.adsr_attenuation_ + (attenuation_ << 2);
|
||||
// Overrides here represent per-channel volume on an OPLL. The bits are defined to represent
|
||||
// attenuations of 24db to 0.75db.
|
||||
state.attenuation.logsin += (state.adsr_attenuation_ << 3) + (attenuation_ << 5);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define Operator_hpp
|
||||
|
||||
#include <cstdint>
|
||||
#include "Tables.h"
|
||||
|
||||
namespace Yamaha {
|
||||
namespace OPL {
|
||||
@ -19,10 +20,11 @@ namespace OPL {
|
||||
*/
|
||||
struct OperatorState {
|
||||
public:
|
||||
int phase = 0; // Will be in the range [0, 1023], mapping into a 1024-unit sine curve.
|
||||
int attenuation = 1023; // Will be in the range [0, 1023].
|
||||
/// @returns The linear output level for the operator with this state..
|
||||
int level();
|
||||
|
||||
private:
|
||||
LogSin attenuation;
|
||||
int raw_phase_ = 0;
|
||||
|
||||
enum class ADSRPhase {
|
||||
@ -81,7 +83,7 @@ class Operator {
|
||||
void set_am_vibrato_hold_sustain_ksr_multiple(uint8_t value);
|
||||
|
||||
/// Provides one clock tick to the operator, along with the relevant parameters of its channel.
|
||||
void update(OperatorState &state, bool key_on, int channel_period, int channel_octave, OperatorOverrides *overrides = nullptr);
|
||||
void update(OperatorState &state, bool key_on, int channel_period, int channel_octave, int phase_offset, OperatorOverrides *overrides = nullptr);
|
||||
|
||||
/// @returns @c true if this channel currently has a non-zero output; @c false otherwise.
|
||||
bool is_audible(OperatorState &state, OperatorOverrides *overrides = nullptr);
|
||||
|
@ -168,8 +168,8 @@ void OPLL::setup_fixed_instrument(int number, const uint8_t *data) {
|
||||
modulator->set_scaling_output(data[2]);
|
||||
|
||||
// Set waveforms — only sine and halfsine are available.
|
||||
carrier->set_waveform((data[3] >> 4) & 1);
|
||||
modulator->set_waveform((data[3] >> 3) & 1);
|
||||
carrier->set_waveform((data[3] >> 4) & 1);
|
||||
|
||||
// TODO: data[3] b0-b2: modulator feedback level
|
||||
// TODO: data[3] b6, b7: carrier key-scale level
|
||||
|
Loading…
Reference in New Issue
Block a user