1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-02 20:30:00 +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:
Thomas Harte 2020-04-19 13:27:24 -04:00
parent 020c760976
commit 92d0c466c2
5 changed files with 32 additions and 24 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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