2020-04-16 02:10:50 +00:00
//
// Operator.cpp
// Clock Signal
//
// Created by Thomas Harte on 15/04/2020.
// Copyright © 2020 Thomas Harte. All rights reserved.
//
# include "Operator.hpp"
# include <algorithm>
2020-04-22 02:48:52 +00:00
# include <cassert>
2020-04-16 02:10:50 +00:00
using namespace Yamaha : : OPL ;
2020-04-22 03:35:48 +00:00
// MARK: - Setters
2020-04-16 02:10:50 +00:00
void Operator : : set_attack_decay ( uint8_t value ) {
attack_rate_ = ( value & 0xf0 ) > > 2 ;
decay_rate_ = ( value & 0x0f ) < < 2 ;
}
void Operator : : set_sustain_release ( uint8_t value ) {
sustain_level_ = ( value & 0xf0 ) > > 4 ;
release_rate_ = ( value & 0x0f ) < < 2 ;
}
void Operator : : set_scaling_output ( uint8_t value ) {
2020-04-21 04:09:42 +00:00
key_level_scaling_ = value > > 6 ;
2020-04-16 02:10:50 +00:00
attenuation_ = value & 0x3f ;
}
void Operator : : set_waveform ( uint8_t value ) {
waveform_ = Operator : : Waveform ( value & 3 ) ;
}
void Operator : : set_am_vibrato_hold_sustain_ksr_multiple ( uint8_t value ) {
apply_amplitude_modulation_ = value & 0x80 ;
apply_vibrato_ = value & 0x40 ;
use_sustain_level_ = value & 0x20 ;
2020-04-22 02:57:56 +00:00
key_rate_scaling_shift_ = ( value & 0x10 ) ? 0 : 2 ;
2020-04-16 02:10:50 +00:00
frequency_multiple_ = value & 0xf ;
}
2020-04-22 03:35:48 +00:00
// MARK: - Getter
2020-04-16 02:10:50 +00:00
bool Operator : : is_audible ( OperatorState & state , OperatorOverrides * overrides ) {
2020-04-22 03:35:48 +00:00
// TODO: (i) do I actually want to support this functionality? (ii) if so, fix below.
2020-04-16 02:10:50 +00:00
if ( state . adsr_phase_ = = OperatorState : : ADSRPhase : : Release ) {
if ( overrides ) {
if ( overrides - > attenuation = = 0xf ) return false ;
} else {
if ( attenuation_ = = 0x3f ) return false ;
}
}
return state . adsr_attenuation_ ! = 511 ;
}
2020-04-22 03:35:48 +00:00
// MARK: - Update logic.
2020-04-24 22:48:32 +00:00
void Operator : : update_adsr (
2020-04-24 03:55:49 +00:00
OperatorState & state ,
const LowFrequencyOscillator & oscillator ,
bool key_on ,
int channel_period ,
int channel_octave ,
const OperatorOverrides * overrides ) {
2020-04-16 02:10:50 +00:00
// 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.
if ( ! key_on ) {
state . adsr_phase_ = OperatorState : : ADSRPhase : : Release ;
} else if ( ! state . last_key_on_ ) {
state . adsr_phase_ = OperatorState : : ADSRPhase : : Attack ;
2020-04-24 03:55:49 +00:00
state . attack_time_ = 0 ;
2020-04-25 23:21:55 +00:00
// TODO: should this happen only if current ADSR attenuation is 511?
2020-04-26 03:07:40 +00:00
state . raw_phase_ = 0 ;
2020-04-16 02:10:50 +00:00
}
state . last_key_on_ = key_on ;
// Adjust the ADSR attenuation appropriately;
// cf. http://forums.submarine.org.uk/phpBB/viewtopic.php?f=9&t=16 (primarily) for the source of the maths below.
// "An attack rate value of 52 (AR = 13) has 32 samples in the attack phase, an attack rate value of 48 (AR = 12)
// has 64 samples in the attack phase, but pairs of samples show the same envelope attenuation. I am however struggling to find a plausible algorithm to match the experimental results.
2020-04-22 02:57:56 +00:00
const int key_scaling_rate = ( ( channel_octave < < 1 ) | ( channel_period > > 9 ) ) > > key_rate_scaling_shift_ ;
assert ( key_scaling_rate < 16 ) ;
assert ( ( channel_period > > 9 ) < 2 ) ;
2020-04-24 03:55:49 +00:00
switch ( state . adsr_phase_ ) {
2020-04-16 02:10:50 +00:00
case OperatorState : : ADSRPhase : : Attack : {
2020-04-22 02:57:56 +00:00
const int attack_rate = attack_rate_ + key_scaling_rate ;
2020-04-16 02:10:50 +00:00
// Rules:
//
// An attack rate of '13' has 32 samples in the attack phase; a rate of '12' has the same 32 steps, but spread out over 64 samples, etc.
// An attack rate of '14' uses a divide by four instead of two.
// 15 is instantaneous.
if ( attack_rate > = 56 ) {
state . adsr_attenuation_ = state . adsr_attenuation_ - ( state . adsr_attenuation_ > > 2 ) - 1 ;
} else {
const int sample_length = 1 < < ( 14 - ( attack_rate > > 2 ) ) ; // TODO: don't throw away KSR bits.
2020-04-24 03:55:49 +00:00
if ( ! ( state . attack_time_ & ( sample_length - 1 ) ) ) {
2020-04-16 02:10:50 +00:00
state . adsr_attenuation_ = state . adsr_attenuation_ - ( state . adsr_attenuation_ > > 3 ) - 1 ;
}
}
// Two possible terminating conditions: (i) the attack rate is 15; (ii) full volume has been reached.
if ( attack_rate > 60 | | state . adsr_attenuation_ < = 0 ) {
state . adsr_attenuation_ = 0 ;
state . adsr_phase_ = OperatorState : : ADSRPhase : : Decay ;
}
} break ;
case OperatorState : : ADSRPhase : : Release :
case OperatorState : : ADSRPhase : : Decay :
{
// Rules:
//
// (relative to a 511 scale)
//
// A rate of 0 is no decay at all.
// A rate of 1 means increase 4 per cycle.
// A rate of 2 means increase 2 per cycle.
// A rate of 3 means increase 1 per cycle.
// A rate of 4 means increase 1 every other cycle.
2020-04-22 03:35:48 +00:00
// A rate of 5 means increase once every fourth cycle.
// etc.
// eighth, sixteenth, 32nd, 64th, 128th, 256th, 512th, 1024th, 2048th, 4096th, 8192th
2020-04-22 02:57:56 +00:00
const int decrease_rate = key_scaling_rate + ( ( state . adsr_phase_ = = OperatorState : : ADSRPhase : : Decay ) ? decay_rate_ : release_rate_ ) ;
2020-04-16 02:10:50 +00:00
2020-04-22 03:35:48 +00:00
2020-04-16 02:10:50 +00:00
if ( decrease_rate ) {
// TODO: don't throw away KSR bits.
switch ( decrease_rate > > 2 ) {
2020-04-20 22:58:10 +00:00
case 1 : state . adsr_attenuation_ + = 32 ; break ;
case 2 : state . adsr_attenuation_ + = 16 ; break ;
2020-04-16 02:10:50 +00:00
default : {
const int sample_length = 1 < < ( ( decrease_rate > > 2 ) - 4 ) ;
2020-04-24 03:55:49 +00:00
if ( ! ( oscillator . counter & ( sample_length - 1 ) ) ) {
2020-04-20 22:58:10 +00:00
state . adsr_attenuation_ + = 8 ;
2020-04-16 02:10:50 +00:00
}
} break ;
}
}
// Clamp to the proper range.
state . adsr_attenuation_ = std : : min ( state . adsr_attenuation_ , 511 ) ;
// Check for the decay exit condition.
2020-04-21 23:58:40 +00:00
if ( state . adsr_phase_ = = OperatorState : : ADSRPhase : : Decay & & state . adsr_attenuation_ > = ( sustain_level_ < < 3 ) ) {
state . adsr_attenuation_ = sustain_level_ < < 3 ;
2020-04-16 02:10:50 +00:00
state . adsr_phase_ = ( ( overrides & & overrides - > use_sustain_level ) | | use_sustain_level_ ) ? OperatorState : : ADSRPhase : : Sustain : OperatorState : : ADSRPhase : : Release ;
}
} break ;
case OperatorState : : ADSRPhase : : Sustain :
// Nothing to do.
break ;
}
2020-04-24 03:55:49 +00:00
+ + state . attack_time_ ;
2020-04-24 22:48:32 +00:00
}
2020-04-26 04:18:09 +00:00
void Operator : : update_phase ( OperatorState & state , const LowFrequencyOscillator & oscillator , int channel_period , int channel_octave ) {
// Per the documentation:
//
// Delta phase = ( [desired freq] * 2^19 / [input clock / 72] ) / 2 ^ (b - 1)
//
// After experimentation, I think this gives rate calculation as formulated below.
// This encodes the MUL -> multiple table given on page 12,
// multiplied by two.
constexpr int multipliers [ ] = {
1 , 2 , 4 , 6 , 8 , 10 , 12 , 14 , 16 , 18 , 20 , 20 , 24 , 24 , 30 , 30
} ;
const int top_freq = channel_period > > 7 ;
assert ( top_freq < 8 ) ;
constexpr int vibrato_shifts [ 8 ] = { 3 , 1 , 0 , 1 , 3 , 1 , 0 , 1 } ;
constexpr int vibrato_signs [ 2 ] = { 1 , - 1 } ;
const int vibrato = ( top_freq > > vibrato_shifts [ oscillator . vibrato ] ) * vibrato_signs [ oscillator . vibrato > > 2 ] * int ( apply_vibrato_ ) ;
// Update the raw phase.
state . raw_phase_ + = multipliers [ frequency_multiple_ ] * ( channel_period + vibrato ) < < channel_octave ;
}
2020-04-30 23:35:09 +00:00
int Operator : : key_level_scaling ( const OperatorState & state , int channel_period , int channel_octave ) const {
2020-04-21 04:09:42 +00:00
// Calculate key-level scaling. Table is as per p14 of the YM3812 application manual,
// converted into a fixed-point scheme. Compare with https://www.smspower.org/Development/RE12
// and apologies for the highly ad hoc indentation.
2020-04-22 00:19:02 +00:00
constexpr int key_level_scale_shifts [ 4 ] = { 7 , 1 , 2 , 0 } ; // '7' is just a number large enough to render all the numbers below as 0.
constexpr int key_level_scales [ 8 ] [ 16 ] = {
2020-04-21 04:09:42 +00:00
# define _ 0
2020-04-22 00:19:02 +00:00
// 6 db attenuations.
{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ } ,
{ _ , _ , _ , _ , _ , _ , _ , _ , _ , 4 , 6 , 8 , 10 , 12 , 14 , 16 } ,
{ _ , _ , _ , _ , _ , 6 , 10 , 14 , 16 , 20 , 22 , 24 , 26 , 28 , 30 , 32 } ,
{ _ , _ , _ , 10 , 16 , 22 , 26 , 30 , 32 , 36 , 38 , 40 , 42 , 44 , 46 , 48 } ,
{ _ , _ , 16 , 26 , 32 , 38 , 42 , 46 , 48 , 52 , 54 , 56 , 58 , 60 , 62 , 64 } ,
{ _ , 16 , 32 , 42 , 48 , 54 , 58 , 62 , 64 , 68 , 70 , 72 , 74 , 76 , 78 , 80 } ,
{ _ , 32 , 48 , 58 , 64 , 70 , 74 , 78 , 80 , 84 , 86 , 88 , 90 , 92 , 94 , 96 } ,
{ _ , 48 , 64 , 74 , 80 , 86 , 90 , 94 , 96 , 100 , 102 , 104 , 106 , 108 , 110 , 112 } ,
2020-04-21 04:09:42 +00:00
# undef _
} ;
2020-04-22 00:19:02 +00:00
assert ( ( channel_period > > 6 ) < 16 ) ;
2020-04-22 00:10:40 +00:00
assert ( channel_octave < 8 ) ;
2020-04-26 04:18:09 +00:00
return ( key_level_scales [ channel_octave ] [ channel_period > > 6 ] > > key_level_scale_shifts [ key_level_scaling_ ] ) < < 7 ;
2020-04-26 03:07:40 +00:00
}
2020-04-21 04:09:42 +00:00
2020-04-30 23:35:09 +00:00
int Operator : : adsr_tremolo_attenuation ( const OperatorState & state , const LowFrequencyOscillator & oscillator ) const {
// Add optional tremolo to the current ADSR attenuation.
return ( state . adsr_attenuation_ < < 3 ) + ( int ( apply_amplitude_modulation_ ) * oscillator . tremolo < < 4 ) ;
}
2020-04-26 04:18:09 +00:00
2020-04-30 23:35:09 +00:00
int Operator : : fixed_attenuation ( const OperatorState & state , const OperatorOverrides * overrides ) const {
2020-04-16 02:10:50 +00:00
if ( overrides ) {
2020-04-19 17:27:24 +00:00
// 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).
2020-04-30 23:35:09 +00:00
return overrides - > attenuation < < 7 ;
2020-04-16 02:10:50 +00:00
} else {
2020-04-19 17:27:24 +00:00
// Overrides here represent per-channel volume on an OPLL. The bits are defined to represent
// attenuations of 24db to 0.75db.
2020-04-30 23:35:09 +00:00
return attenuation_ < < 5 ;
2020-04-16 02:10:50 +00:00
}
2020-04-26 03:07:40 +00:00
}
void Operator : : update (
OperatorState & state ,
const LowFrequencyOscillator & oscillator ,
bool key_on ,
int channel_period ,
int channel_octave ,
const OperatorOverrides * overrides ) {
update_adsr ( state , oscillator , key_on , channel_period , channel_octave , overrides ) ;
update_phase ( state , oscillator , channel_period , channel_octave ) ;
2020-04-26 04:18:09 +00:00
state . key_level_scaling_ = key_level_scaling ( state , channel_period , channel_octave ) ;
2020-04-30 23:35:09 +00:00
state . adsr_tremolo_attenuation_ = adsr_tremolo_attenuation ( state , oscillator ) ;
2020-04-26 04:18:09 +00:00
state . lfsr_ = oscillator . lfsr ;
}
// TODO: both the tremolo and ADSR envelopes should be half-resolution on an OPLL.
2020-04-26 03:07:40 +00:00
2020-04-26 04:18:09 +00:00
// MARK: - Output Generators.
2020-04-26 19:51:33 +00:00
// A heavy debt is owed to https://github.com/andete/ym2413/blob/master/results/rhythm/rhythm.md regarding
// the drum sound generation below.
2020-04-30 23:35:09 +00:00
LogSign Operator : : melodic_output ( const OperatorState & state , const LogSign * phase_offset , const OperatorOverrides * overrides ) const {
2020-04-26 03:07:40 +00:00
// Calculate raw attenuation level.
constexpr int waveforms [ 4 ] [ 4 ] = {
{ 1023 , 1023 , 1023 , 1023 } , // Sine: don't mask in any quadrant.
{ 511 , 511 , 0 , 0 } , // Half sine: keep the first half intact, lock to 0 in the second half.
{ 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.
} ;
2020-04-26 04:18:09 +00:00
const int scaled_phase_offset = phase_offset ? phase_offset - > level ( 11 ) : 0 ;
2020-04-26 03:07:40 +00:00
const int phase = ( state . raw_phase_ + scaled_phase_offset ) > > 11 ;
2020-04-26 04:18:09 +00:00
LogSign result = negative_log_sin ( phase & waveforms [ int ( waveform_ ) ] [ ( phase > > 8 ) & 3 ] ) ;
result + = state . key_level_scaling_ ;
2020-04-30 23:35:09 +00:00
result + = state . adsr_tremolo_attenuation_ + fixed_attenuation ( state , overrides ) ;
2020-04-26 04:18:09 +00:00
return result ;
2020-04-26 03:07:40 +00:00
}
2020-04-30 23:35:09 +00:00
LogSign Operator : : snare_output ( const OperatorState & state , const OperatorOverrides * overrides ) const {
2020-04-26 04:18:09 +00:00
LogSign result ;
// If noise is 0, output is positive.
// If noise is 1, output is negative.
// If (noise ^ sign) is 0, output is 0. Otherwise it is max.
2020-04-26 04:21:15 +00:00
const int sign = ( state . raw_phase_ > > 11 ) & 0x200 ;
const int level = ( ( state . raw_phase_ > > 20 ) & 1 ) ^ state . lfsr_ ;
result = negative_log_sin ( sign + ( level < < 8 ) ) ;
2020-04-26 19:51:33 +00:00
result + = state . key_level_scaling_ ;
2020-04-30 23:35:09 +00:00
result + = state . adsr_tremolo_attenuation_ + fixed_attenuation ( state , overrides ) ;
2020-04-26 19:51:33 +00:00
return result ;
}
2020-04-30 23:35:09 +00:00
LogSign Operator : : cymbal_output ( const OperatorState & state , const OperatorState & modulator , const OperatorOverrides * overrides ) const {
2020-04-26 19:51:33 +00:00
const int output =
( ( state . raw_phase_ > > 16 ) ^ ( state . raw_phase_ > > 14 ) ) &
( ( modulator . raw_phase_ > > 18 ) ^ ( modulator . raw_phase_ > > 13 ) ) &
( ( state . raw_phase_ > > 16 ) ^ ( modulator . raw_phase_ > > 14 ) ) ;
constexpr int angles [ ] = { 256 , 768 } ;
LogSign result = negative_log_sin ( angles [ output & 1 ] ) ;
result + = state . key_level_scaling_ ;
2020-04-30 23:35:09 +00:00
result + = state . adsr_tremolo_attenuation_ + fixed_attenuation ( state , overrides ) ;
2020-04-26 19:51:33 +00:00
return result ;
}
2020-04-26 04:18:09 +00:00
2020-04-30 23:35:09 +00:00
LogSign Operator : : high_hat_output ( const OperatorState & state , const OperatorState & modulator , const OperatorOverrides * overrides ) const {
2020-04-26 19:51:33 +00:00
const int output =
( ( state . raw_phase_ > > 16 ) ^ ( state . raw_phase_ > > 14 ) ) &
( ( modulator . raw_phase_ > > 18 ) ^ ( modulator . raw_phase_ > > 13 ) ) &
( ( state . raw_phase_ > > 16 ) ^ ( modulator . raw_phase_ > > 14 ) ) ;
2020-04-26 04:18:09 +00:00
2020-04-26 19:51:33 +00:00
constexpr int angles [ ] = { 0x234 , 0xd0 , 0x2d0 , 0x34 } ;
LogSign result = negative_log_sin ( angles [ ( output & 1 ) | ( state . lfsr_ < < 1 ) ] ) ;
2020-04-26 04:18:09 +00:00
result + = state . key_level_scaling_ ;
2020-04-30 23:35:09 +00:00
result + = state . adsr_tremolo_attenuation_ + fixed_attenuation ( state , overrides ) ;
2020-04-26 04:18:09 +00:00
return result ;
}