mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-18 17:06:15 +00:00
64 lines
1.9 KiB
C++
64 lines
1.9 KiB
C++
//
|
|
// LowFrequencyOscillator.hpp
|
|
// Clock Signal
|
|
//
|
|
// Created by Thomas Harte on 23/04/2020.
|
|
// Copyright © 2020 Thomas Harte. All rights reserved.
|
|
//
|
|
|
|
#pragma once
|
|
|
|
#include "../../../Numeric/LFSR.hpp"
|
|
|
|
namespace Yamaha::OPL {
|
|
|
|
/*!
|
|
Models the output of the OPL low-frequency oscillator, which provides a couple of optional fixed-frequency
|
|
modifications to an operator: tremolo and vibrato. Also exposes a global time counter, which oscillators use
|
|
as part of their ADSR envelope.
|
|
*/
|
|
class LowFrequencyOscillator {
|
|
public:
|
|
/// Current attenuation due to tremolo / amplitude modulation, between 0 and 26.
|
|
int tremolo = 0;
|
|
|
|
/// A number between 0 and 7 indicating the current vibrato offset; this should be combined by operators
|
|
/// with their frequency number to get the actual vibrato.
|
|
int vibrato = 0;
|
|
|
|
/// A counter of the number of operator update cycles (i.e. input clock / 72) since an arbitrary time.
|
|
int counter = 0;
|
|
|
|
/// Describes the current output of the LFSR; will be either 0 or 1.
|
|
int lfsr = 0;
|
|
|
|
/// Updates the oscillator outputs. Should be called at the (input clock/72) rate.
|
|
void update() {
|
|
++counter;
|
|
|
|
// This produces output of:
|
|
//
|
|
// four instances of 0, four instances of 1... _three_ instances of 26,
|
|
// four instances of 25, four instances of 24... _three_ instances of 0.
|
|
//
|
|
// ... advancing once every 64th update.
|
|
const int tremolo_index = (counter >> 6) % 210;
|
|
const int tremolo_levels[2] = {tremolo_index >> 2, 52 - ((tremolo_index+1) >> 2)};
|
|
tremolo = tremolo_levels[tremolo_index / 107];
|
|
|
|
// Vibrato is relatively simple: it's just three bits from the counter.
|
|
vibrato = (counter >> 10) & 7;
|
|
}
|
|
|
|
/// Updartes the LFSR output. Should be called at the input clock rate.
|
|
void update_lfsr() {
|
|
lfsr = noise_source_.next();
|
|
}
|
|
|
|
private:
|
|
// This is the correct LSFR per forums.submarine.org.uk.
|
|
Numeric::LFSR<int, 0x800302> noise_source_;
|
|
};
|
|
|
|
}
|