2020-04-04 00:05:36 +00:00
|
|
|
//
|
|
|
|
// OPL2.hpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 02/04/2020.
|
|
|
|
// Copyright © 2020 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef OPL2_hpp
|
|
|
|
#define OPL2_hpp
|
|
|
|
|
|
|
|
#include "../../Outputs/Speaker/Implementation/SampleSource.hpp"
|
|
|
|
#include "../../Concurrency/AsyncTaskQueue.hpp"
|
|
|
|
|
2020-04-16 02:10:50 +00:00
|
|
|
#include "Implementation/Channel.hpp"
|
|
|
|
#include "Implementation/Operator.hpp"
|
|
|
|
|
2020-04-14 22:32:06 +00:00
|
|
|
#include <atomic>
|
2020-04-12 16:46:40 +00:00
|
|
|
|
2020-04-04 00:05:36 +00:00
|
|
|
namespace Yamaha {
|
2020-04-08 03:15:26 +00:00
|
|
|
namespace OPL {
|
|
|
|
|
|
|
|
template <typename Child> class OPLBase: public ::Outputs::Speaker::SampleSource {
|
2020-04-04 00:05:36 +00:00
|
|
|
public:
|
2020-04-08 03:15:26 +00:00
|
|
|
void write(uint16_t address, uint8_t value);
|
2020-04-04 00:05:36 +00:00
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
protected:
|
|
|
|
OPLBase(Concurrency::DeferringAsyncTaskQueue &task_queue);
|
|
|
|
|
|
|
|
Concurrency::DeferringAsyncTaskQueue &task_queue_;
|
2020-04-24 03:55:49 +00:00
|
|
|
LowFrequencyOscillator oscillator_;
|
2020-04-08 03:15:26 +00:00
|
|
|
|
|
|
|
uint8_t depth_rhythm_control_;
|
|
|
|
uint8_t csm_keyboard_split_;
|
|
|
|
bool waveform_enable_;
|
|
|
|
|
|
|
|
private:
|
|
|
|
uint8_t selected_register_ = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct OPL2: public OPLBase<OPL2> {
|
|
|
|
public:
|
|
|
|
// Creates a new OPL2.
|
|
|
|
OPL2(Concurrency::DeferringAsyncTaskQueue &task_queue);
|
2020-04-04 00:05:36 +00:00
|
|
|
|
|
|
|
/// As per ::SampleSource; provides a broadphase test for silence.
|
|
|
|
bool is_zero_level();
|
|
|
|
|
|
|
|
/// As per ::SampleSource; provides audio output.
|
|
|
|
void get_samples(std::size_t number_of_samples, std::int16_t *target);
|
|
|
|
void set_sample_volume_range(std::int16_t range);
|
|
|
|
|
|
|
|
/// Reads from the OPL.
|
|
|
|
uint8_t read(uint16_t address);
|
|
|
|
|
|
|
|
private:
|
2020-04-08 03:15:26 +00:00
|
|
|
friend OPLBase<OPL2>;
|
2020-04-05 03:29:25 +00:00
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
Operator operators_[18];
|
|
|
|
Channel channels_[9];
|
2020-04-05 03:39:09 +00:00
|
|
|
|
|
|
|
// Synchronous properties, valid only on the emulation thread.
|
2020-04-08 03:15:26 +00:00
|
|
|
uint8_t timers_[2] = {0, 0};
|
|
|
|
uint8_t timer_control_ = 0;
|
2020-04-06 02:57:53 +00:00
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
void write_register(uint8_t address, uint8_t value);
|
2020-04-04 00:05:36 +00:00
|
|
|
};
|
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
struct OPLL: public OPLBase<OPLL> {
|
|
|
|
public:
|
|
|
|
// Creates a new OPLL or VRC7.
|
2020-04-12 16:46:40 +00:00
|
|
|
OPLL(Concurrency::DeferringAsyncTaskQueue &task_queue, int audio_divider = 1, bool is_vrc7 = false);
|
2020-04-08 03:15:26 +00:00
|
|
|
|
|
|
|
/// As per ::SampleSource; provides a broadphase test for silence.
|
|
|
|
bool is_zero_level();
|
|
|
|
|
|
|
|
/// As per ::SampleSource; provides audio output.
|
|
|
|
void get_samples(std::size_t number_of_samples, std::int16_t *target);
|
|
|
|
void set_sample_volume_range(std::int16_t range);
|
|
|
|
|
|
|
|
/// Reads from the OPL.
|
|
|
|
uint8_t read(uint16_t address);
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend OPLBase<OPLL>;
|
|
|
|
|
2020-04-11 02:05:22 +00:00
|
|
|
Operator operators_[38]; // There's an extra level of indirection with the OPLL; these 38
|
|
|
|
// operators are to describe 19 hypothetical channels, being
|
|
|
|
// one user-configurable channel, 15 hard-coded channels, and
|
|
|
|
// three channels configured for rhythm generation.
|
|
|
|
|
2020-04-24 03:55:49 +00:00
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
struct Channel: public ::Yamaha::OPL::Channel {
|
2020-04-30 02:07:40 +00:00
|
|
|
void update(const LowFrequencyOscillator &oscillator) {
|
|
|
|
Yamaha::OPL::Channel::update(true, oscillator, modulator[0]);
|
|
|
|
Yamaha::OPL::Channel::update(false, oscillator, modulator[1], false, &overrides);
|
2020-04-25 22:01:05 +00:00
|
|
|
}
|
|
|
|
|
2020-04-30 02:07:40 +00:00
|
|
|
void update(const LowFrequencyOscillator &oscillator, Operator *mod, bool key_on) {
|
|
|
|
Yamaha::OPL::Channel::update(true, oscillator, mod[0], key_on);
|
|
|
|
Yamaha::OPL::Channel::update(false, oscillator, mod[1], key_on, &overrides);
|
2020-04-14 01:39:06 +00:00
|
|
|
}
|
|
|
|
|
2020-04-30 02:07:40 +00:00
|
|
|
using ::Yamaha::OPL::Channel::update;
|
|
|
|
|
|
|
|
int melodic_output() {
|
|
|
|
return Yamaha::OPL::Channel::melodic_output(modulator[0], modulator[1]);
|
2020-04-25 23:21:55 +00:00
|
|
|
}
|
|
|
|
|
2020-04-30 02:07:40 +00:00
|
|
|
// 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);
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// int update_tom_tom(const LowFrequencyOscillator &oscillator, Operator *bass, bool key_on) {
|
|
|
|
// // TODO: should overrides be applied here?
|
|
|
|
// return Yamaha::OPL::Channel::update_tom_tom(oscillator, bass, key_on, &overrides);
|
|
|
|
// }
|
|
|
|
|
2020-04-14 01:39:06 +00:00
|
|
|
bool is_audible() {
|
|
|
|
return Yamaha::OPL::Channel::is_audible(modulator + 1, &overrides);
|
|
|
|
}
|
|
|
|
|
2020-04-08 03:15:26 +00:00
|
|
|
Operator *modulator; // Implicitly, the carrier is modulator+1.
|
2020-04-11 02:05:22 +00:00
|
|
|
OperatorOverrides overrides;
|
2020-04-08 03:15:26 +00:00
|
|
|
};
|
2020-04-18 21:48:29 +00:00
|
|
|
void update_all_chanels();
|
2020-04-08 03:15:26 +00:00
|
|
|
Channel channels_[9];
|
2020-04-25 22:01:05 +00:00
|
|
|
int output_levels_[18];
|
2020-04-30 02:44:15 +00:00
|
|
|
OperatorOverrides rhythm_overrides_[6];
|
2020-04-08 03:15:26 +00:00
|
|
|
|
|
|
|
void setup_fixed_instrument(int number, const uint8_t *data);
|
|
|
|
uint8_t custom_instrument_[8];
|
|
|
|
|
|
|
|
void write_register(uint8_t address, uint8_t value);
|
2020-04-12 16:46:40 +00:00
|
|
|
|
|
|
|
const int audio_divider_ = 1;
|
|
|
|
int audio_offset_ = 0;
|
2020-04-14 22:32:06 +00:00
|
|
|
|
|
|
|
std::atomic<int> total_volume_;
|
2020-04-08 03:15:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
2020-04-04 00:05:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* OPL2_hpp */
|