mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Adds waveform generation logic to the new factoring.
This commit is contained in:
parent
1ff5ea0a6e
commit
1223c99e0f
@ -27,7 +27,7 @@ template <int frequency_precision> class KeyLevelScaler {
|
||||
// on the sign bit to clamp to zero.
|
||||
level_ = key_level_scales[period >> (frequency_precision - 4)];
|
||||
level_ -= 16 * (octave ^ 7);
|
||||
level_ &= masks[(key_scale_rate_ >> ((sizeof(int) * 8) - 1)) & 1];
|
||||
level_ &= masks[(level_ >> ((sizeof(int) * 8) - 1)) & 1];
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -51,6 +51,13 @@ template <int precision> class PhaseGenerator {
|
||||
return phase_ >> precision_shift;
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns Current phase, scaled up by (1 << precision).
|
||||
*/
|
||||
int scaled_phase() const {
|
||||
return phase_ >> 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the multiple for this phase generator, in the same terms as an OPL programmer,
|
||||
i.e. a 4-bit number that is used as a lookup into the internal multiples table.
|
||||
|
92
Components/OPL2/Implementation/WaveformGenerator.hpp
Normal file
92
Components/OPL2/Implementation/WaveformGenerator.hpp
Normal file
@ -0,0 +1,92 @@
|
||||
//
|
||||
// WaveformGenerator.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 03/05/2020.
|
||||
// Copyright © 2020 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef WaveformGenerator_h
|
||||
#define WaveformGenerator_h
|
||||
|
||||
#include "Tables.hpp"
|
||||
#include "LowFrequencyOscillator.hpp"
|
||||
|
||||
namespace Yamaha {
|
||||
namespace OPL {
|
||||
|
||||
template <int phase_precision> class WaveformGenerator {
|
||||
public:
|
||||
enum class Waveform {
|
||||
Sine, HalfSine, AbsSine, PulseSine
|
||||
};
|
||||
|
||||
/*!
|
||||
@returns The output of waveform @c form at [integral] phase @c phase.
|
||||
*/
|
||||
static constexpr LogSign wave(Waveform form, int phase) {
|
||||
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.
|
||||
};
|
||||
return negative_log_sin(phase & waveforms[int(form)][(phase >> 8) & 3]);
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns The output of waveform @c form at [scaled] phase @c scaled_phase given the modulation input @c modulation.
|
||||
*/
|
||||
static constexpr LogSign wave(Waveform form, int scaled_phase, LogSign modulation) {
|
||||
const int scaled_phase_offset = modulation.level(phase_precision);
|
||||
const int phase = (scaled_phase + scaled_phase_offset) >> phase_precision;
|
||||
return wave(form, phase);
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns Snare output, calculated from the current LFSR state as captured in @c oscillator and an operator's phase.
|
||||
*/
|
||||
static constexpr LogSign snare(const LowFrequencyOscillator &oscillator, int phase) {
|
||||
// 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.
|
||||
const int sign = phase & 0x200;
|
||||
const int level = ((phase >> 9) & 1) ^ oscillator.lfsr;
|
||||
return negative_log_sin(sign + (level << 8));
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns Cymbal output, calculated from an operator's phase and a modulator's phase.
|
||||
*/
|
||||
static constexpr LogSign cymbal(int carrier_phase, int modulator_phase) {
|
||||
return negative_log_sin(256 + (phase_combination(carrier_phase, modulator_phase) << 9));
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns High-hat output, calculated from the current LFSR state as captured in @c oscillator, an operator's phase and a modulator's phase.
|
||||
*/
|
||||
static constexpr LogSign high_hat(const LowFrequencyOscillator &oscillator, int carrier_phase, int modulator_phase) {
|
||||
constexpr int angles[] = {0x234, 0xd0, 0x2d0, 0x34};
|
||||
return negative_log_sin(angles[
|
||||
phase_combination(carrier_phase, modulator_phase) |
|
||||
(oscillator.lfsr << 1)
|
||||
]);
|
||||
}
|
||||
|
||||
private:
|
||||
/*!
|
||||
@returns The phase bit used for cymbal and high-hat generation, which is a function of two operators' phases.
|
||||
*/
|
||||
static constexpr int phase_combination(int carrier_phase, int modulator_phase) {
|
||||
return (
|
||||
((carrier_phase >> 5) ^ (carrier_phase >> 3)) &
|
||||
((modulator_phase >> 7) ^ (modulator_phase >> 2)) &
|
||||
((carrier_phase >> 5) ^ (modulator_phase >> 3))
|
||||
) & 1;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* WaveformGenerator_h */
|
@ -13,6 +13,8 @@
|
||||
|
||||
#include "Implementation/PhaseGenerator.hpp"
|
||||
#include "Implementation/EnvelopeGenerator.hpp"
|
||||
#include "Implementation/KeyLevelScaler.hpp"
|
||||
#include "Implementation/WaveformGenerator.hpp"
|
||||
|
||||
using namespace Yamaha::OPL;
|
||||
|
||||
|
@ -1154,6 +1154,7 @@
|
||||
4B619092245BC1000013F202 /* PhaseGenerator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PhaseGenerator.hpp; sourceTree = "<group>"; };
|
||||
4B619093245CD63E0013F202 /* EnvelopeGenerator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = EnvelopeGenerator.hpp; sourceTree = "<group>"; };
|
||||
4B619094245E73B90013F202 /* KeyLevelScaler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = KeyLevelScaler.hpp; sourceTree = "<group>"; };
|
||||
4B619095245FA04B0013F202 /* WaveformGenerator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = WaveformGenerator.hpp; sourceTree = "<group>"; };
|
||||
4B622AE3222E0AD5008B59F2 /* DisplayMetrics.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DisplayMetrics.cpp; path = ../../Outputs/DisplayMetrics.cpp; sourceTree = "<group>"; };
|
||||
4B622AE4222E0AD5008B59F2 /* DisplayMetrics.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DisplayMetrics.hpp; path = ../../Outputs/DisplayMetrics.hpp; sourceTree = "<group>"; };
|
||||
4B643F381D77AD1900D431D6 /* CSStaticAnalyser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSStaticAnalyser.h; path = StaticAnalyser/CSStaticAnalyser.h; sourceTree = "<group>"; };
|
||||
@ -3538,6 +3539,7 @@
|
||||
4B619092245BC1000013F202 /* PhaseGenerator.hpp */,
|
||||
4B619093245CD63E0013F202 /* EnvelopeGenerator.hpp */,
|
||||
4B619094245E73B90013F202 /* KeyLevelScaler.hpp */,
|
||||
4B619095245FA04B0013F202 /* WaveformGenerator.hpp */,
|
||||
);
|
||||
path = Implementation;
|
||||
sourceTree = "<group>";
|
||||
|
Loading…
x
Reference in New Issue
Block a user