mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-29 12:50:28 +00:00
Takes a first run at proper slot mixing and the bass drum.
This commit is contained in:
parent
12c618642e
commit
b9b5c2a3bc
@ -33,16 +33,16 @@ void Channel::set_feedback_mode(uint8_t value) {
|
|||||||
use_fm_synthesis_ = value & 1;
|
use_fm_synthesis_ = value & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Channel::update(const LowFrequencyOscillator &oscillator, Operator *modulator, Operator *carrier, OperatorOverrides *modulator_overrides, OperatorOverrides *carrier_overrides) {
|
int Channel::update_melodic(const LowFrequencyOscillator &oscillator, Operator *modulator, Operator *carrier, bool force_key_on, OperatorOverrides *modulator_overrides, OperatorOverrides *carrier_overrides) {
|
||||||
if(use_fm_synthesis_) {
|
if(use_fm_synthesis_) {
|
||||||
// Get modulator level, use that as a phase-adjusting input to the carrier and then return the carrier level.
|
// Get modulator level, use that as a phase-adjusting input to the carrier and then return the carrier level.
|
||||||
modulator->update(modulator_state_, nullptr, oscillator, key_on_, period_ << frequency_shift_, octave_, modulator_overrides);
|
modulator->update(modulator_state_, nullptr, oscillator, key_on_ || force_key_on, period_ << frequency_shift_, octave_, modulator_overrides);
|
||||||
carrier->update(carrier_state_, &modulator_state_, oscillator, key_on_, period_ << frequency_shift_, octave_, carrier_overrides);
|
carrier->update(carrier_state_, &modulator_state_, oscillator, key_on_ || force_key_on, period_ << frequency_shift_, octave_, carrier_overrides);
|
||||||
return carrier_state_.level();
|
return carrier_state_.level();
|
||||||
} else {
|
} else {
|
||||||
// Get modulator and carrier levels separately, return their sum.
|
// Get modulator and carrier levels separately, return their sum.
|
||||||
modulator->update(modulator_state_, nullptr, oscillator, key_on_, period_ << frequency_shift_, octave_, modulator_overrides);
|
modulator->update(modulator_state_, nullptr, oscillator, key_on_ || force_key_on, period_ << frequency_shift_, octave_, modulator_overrides);
|
||||||
carrier->update(carrier_state_, nullptr, oscillator, key_on_, period_ << frequency_shift_, octave_, carrier_overrides);
|
carrier->update(carrier_state_, nullptr, oscillator, key_on_ || force_key_on, period_ << frequency_shift_, octave_, carrier_overrides);
|
||||||
return (modulator_state_.level() + carrier_state_.level());
|
return (modulator_state_.level() + carrier_state_.level());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,14 @@ class Channel {
|
|||||||
/// associated with this channel, and whether FM synthesis is in use.
|
/// associated with this channel, and whether FM synthesis is in use.
|
||||||
void set_feedback_mode(uint8_t value);
|
void set_feedback_mode(uint8_t value);
|
||||||
|
|
||||||
/// This should be called at a rate of around 49,716 Hz; it returns the current output level
|
/// Updates this channel, using the operators for melodic output.
|
||||||
/// level for this channel.
|
int update_melodic(const LowFrequencyOscillator &oscillator, Operator *modulator, Operator *carrier, bool force_key_on = false, OperatorOverrides *modulator_overrides = nullptr, OperatorOverrides *carrier_overrides = nullptr);
|
||||||
int update(const LowFrequencyOscillator &oscillator, Operator *modulator, Operator *carrier, OperatorOverrides *modulator_overrides = nullptr, OperatorOverrides *carrier_overrides = nullptr);
|
|
||||||
|
/// Updates this channel, using the carrier to produce a snare drum and the modulator to produce a tom tom.
|
||||||
|
int update_snare_tom_tom(const LowFrequencyOscillator &oscillator, Operator *modulator, Operator *carrier, OperatorOverrides *modulator_overrides = nullptr, OperatorOverrides *carrier_overrides = nullptr);
|
||||||
|
|
||||||
|
/// Updates this channel, using the carrier to produce a cymbal and the modulator to produce a high-hat.
|
||||||
|
int update_symbal_high_hat(const LowFrequencyOscillator &oscillator, Operator *modulator, Operator *carrier, OperatorOverrides *modulator_overrides = nullptr, OperatorOverrides *carrier_overrides = nullptr);
|
||||||
|
|
||||||
/// @returns @c true if this channel is currently producing any audio; @c false otherwise;
|
/// @returns @c true if this channel is currently producing any audio; @c false otherwise;
|
||||||
bool is_audible(Operator *carrier, OperatorOverrides *carrier_overrides = nullptr);
|
bool is_audible(Operator *carrier, OperatorOverrides *carrier_overrides = nullptr);
|
||||||
|
@ -31,8 +31,8 @@ template class Yamaha::OPL::OPLBase<Yamaha::OPL::OPL2>;
|
|||||||
|
|
||||||
OPLL::OPLL(Concurrency::DeferringAsyncTaskQueue &task_queue, int audio_divider, bool is_vrc7): OPLBase(task_queue), audio_divider_(audio_divider) {
|
OPLL::OPLL(Concurrency::DeferringAsyncTaskQueue &task_queue, int audio_divider, bool is_vrc7): OPLBase(task_queue), audio_divider_(audio_divider) {
|
||||||
// Due to the way that sound mixing works on the OPLL, the audio divider may not
|
// Due to the way that sound mixing works on the OPLL, the audio divider may not
|
||||||
// be larger than 2.
|
// be larger than 4.
|
||||||
assert(audio_divider <= 2);
|
assert(audio_divider <= 4);
|
||||||
|
|
||||||
// Install fixed instruments.
|
// Install fixed instruments.
|
||||||
const uint8_t *patch_set = is_vrc7 ? vrc7_patch_set : opll_patch_set;
|
const uint8_t *patch_set = is_vrc7 ? vrc7_patch_set : opll_patch_set;
|
||||||
@ -64,12 +64,12 @@ void OPLL::get_samples(std::size_t number_of_samples, std::int16_t *target) {
|
|||||||
// unlike the OPL2 the OPLL time-divides the output for 'mixing'.
|
// unlike the OPL2 the OPLL time-divides the output for 'mixing'.
|
||||||
|
|
||||||
const int update_period = 72 / audio_divider_;
|
const int update_period = 72 / audio_divider_;
|
||||||
const int channel_output_period = 1;//2 / audio_divider_;
|
const int channel_output_period = 4 / audio_divider_;
|
||||||
|
|
||||||
while(number_of_samples--) {
|
while(number_of_samples--) {
|
||||||
if(!audio_offset_) update_all_chanels();
|
if(!audio_offset_) update_all_chanels();
|
||||||
|
|
||||||
*target = int16_t(channels_[(audio_offset_ / channel_output_period) % 9].level);
|
*target = int16_t(output_levels_[audio_offset_ / channel_output_period]);
|
||||||
++target;
|
++target;
|
||||||
audio_offset_ = (audio_offset_ + 1) % update_period;
|
audio_offset_ = (audio_offset_ + 1) % update_period;
|
||||||
}
|
}
|
||||||
@ -192,22 +192,61 @@ void OPLL::update_all_chanels() {
|
|||||||
// Update the LFO.
|
// Update the LFO.
|
||||||
oscillator_.update();
|
oscillator_.update();
|
||||||
|
|
||||||
|
int channel_levels[9];
|
||||||
|
|
||||||
// Channels that are updated for melodic output regardless;
|
// Channels that are updated for melodic output regardless;
|
||||||
// in rhythm mode the final three channels — 6, 7, and 8 —
|
// in rhythm mode the final three channels — 6, 7, and 8 —
|
||||||
// are lost as their operators are used for drum noises.
|
// are lost as their operators are used for drum noises.
|
||||||
for(int c = 0; c < 6; ++ c) {
|
for(int c = 0; c < 6; ++ c) {
|
||||||
channels_[c].level = (channels_[c].update(oscillator_) * total_volume_) >> 12;
|
channel_levels[c] = (channels_[c].update_melodic(oscillator_) * total_volume_) >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output_levels_[3] = channel_levels[0];
|
||||||
|
output_levels_[4] = channel_levels[1];
|
||||||
|
output_levels_[5] = channel_levels[2];
|
||||||
|
output_levels_[9] = channel_levels[3];
|
||||||
|
output_levels_[10] = channel_levels[4];
|
||||||
|
output_levels_[11] = channel_levels[5];
|
||||||
|
|
||||||
if(depth_rhythm_control_ & 0x20) {
|
if(depth_rhythm_control_ & 0x20) {
|
||||||
// Rhythm mode. Somehow?
|
// Rhythm mode.
|
||||||
|
output_levels_[8] = output_levels_[12] = 0;
|
||||||
|
|
||||||
|
// Update channel 6 as if melodic, but with the bass instrument.
|
||||||
|
output_levels_[2] = output_levels_[15] =
|
||||||
|
(channels_[6].update_bass(oscillator_, &operators_[32], depth_rhythm_control_ & 0x10) * total_volume_) >> 12;
|
||||||
|
|
||||||
|
// TODO: snare.
|
||||||
|
output_levels_[6] = output_levels_[16] = 0;
|
||||||
|
|
||||||
|
// TODO: tom tom.
|
||||||
|
output_levels_[1] = output_levels_[14] = 0;
|
||||||
|
|
||||||
|
// TODO: cymbal.
|
||||||
|
output_levels_[7] = output_levels_[17] = 0;
|
||||||
|
|
||||||
|
// TODO: high hat.
|
||||||
|
output_levels_[0] = output_levels_[13] = 0;
|
||||||
} else {
|
} else {
|
||||||
// Not in rhythm mode; channels 7, 8 and 9 are melodic.
|
// Not in rhythm mode; channels 7, 8 and 9 are melodic.
|
||||||
for(int c = 7; c < 9; ++ c) {
|
for(int c = 7; c < 9; ++ c) {
|
||||||
channels_[c].level = (channels_[c].update(oscillator_) * total_volume_) >> 12;
|
channel_levels[c] = (channels_[c].update_melodic(oscillator_) * total_volume_) >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output_levels_[0] = output_levels_[1] = output_levels_[2] =
|
||||||
|
output_levels_[6] = output_levels_[7] = output_levels_[8] =
|
||||||
|
output_levels_[12] = output_levels_[13] = output_levels_[14] = 0;
|
||||||
|
|
||||||
|
output_levels_[15] = channel_levels[3];
|
||||||
|
output_levels_[16] = channel_levels[4];
|
||||||
|
output_levels_[17] = channel_levels[5];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test!
|
||||||
|
// for(int c = 0; c < 18; ++c) {
|
||||||
|
// if(c != 2 && c != 15) output_levels_[c] = 0;
|
||||||
|
// }
|
||||||
|
|
||||||
// channels_[2].level = (channels_[2].update() * total_volume_) >> 14;
|
// channels_[2].level = (channels_[2].update() * total_volume_) >> 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,8 +95,12 @@ struct OPLL: public OPLBase<OPLL> {
|
|||||||
|
|
||||||
|
|
||||||
struct Channel: public ::Yamaha::OPL::Channel {
|
struct Channel: public ::Yamaha::OPL::Channel {
|
||||||
int update(const LowFrequencyOscillator &oscillator) {
|
int update_melodic(const LowFrequencyOscillator &oscillator) {
|
||||||
return Yamaha::OPL::Channel::update(oscillator, modulator, modulator + 1, nullptr, &overrides);
|
return Yamaha::OPL::Channel::update_melodic(oscillator, modulator, modulator + 1, false, nullptr, &overrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
int update_bass(const LowFrequencyOscillator &oscillator, Operator *bass, bool key_on) {
|
||||||
|
return Yamaha::OPL::Channel::update_melodic(oscillator, bass, bass + 1, key_on, nullptr, &overrides);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_audible() {
|
bool is_audible() {
|
||||||
@ -105,10 +109,10 @@ struct OPLL: public OPLBase<OPLL> {
|
|||||||
|
|
||||||
Operator *modulator; // Implicitly, the carrier is modulator+1.
|
Operator *modulator; // Implicitly, the carrier is modulator+1.
|
||||||
OperatorOverrides overrides;
|
OperatorOverrides overrides;
|
||||||
int level = 0;
|
|
||||||
};
|
};
|
||||||
void update_all_chanels();
|
void update_all_chanels();
|
||||||
Channel channels_[9];
|
Channel channels_[9];
|
||||||
|
int output_levels_[18];
|
||||||
|
|
||||||
void setup_fixed_instrument(int number, const uint8_t *data);
|
void setup_fixed_instrument(int number, const uint8_t *data);
|
||||||
uint8_t custom_instrument_[8];
|
uint8_t custom_instrument_[8];
|
||||||
|
Loading…
Reference in New Issue
Block a user