mirror of
https://github.com/TomHarte/CLK.git
synced 2026-04-21 02:17:08 +00:00
Divide state, start adding waveforms.
This commit is contained in:
+19
-9
@@ -14,19 +14,29 @@ SID::SID(Concurrency::AsyncTaskQueue<false> &audio_queue) : audio_queue_(audio_q
|
||||
|
||||
void SID::write(const Numeric::SizedInt<5> address, const uint8_t value) {
|
||||
audio_queue_.enqueue([&] {
|
||||
const auto voice = [&]() -> Voice & {
|
||||
return voices_[address.get() / 7];
|
||||
};
|
||||
const auto oscillator = [&]() -> Voice::Oscillator & {
|
||||
return voice().oscillator;
|
||||
};
|
||||
const auto adsr = [&]() -> Voice::ADSR & {
|
||||
return voice().adsr;
|
||||
};
|
||||
|
||||
switch(address.get()) {
|
||||
case 0x00: case 0x07: case 0x0e: voices_[address.get() / 7].pitch.load<0>(value); break;
|
||||
case 0x01: case 0x08: case 0x0f: voices_[address.get() / 7].pitch.load<8>(value); break;
|
||||
case 0x02: case 0x09: case 0x10: voices_[address.get() / 7].pulse_width.load<0>(value); break;
|
||||
case 0x03: case 0x0a: case 0x11: voices_[address.get() / 7].pulse_width.load<8>(value); break;
|
||||
case 0x04: case 0x0b: case 0x12: voices_[address.get() / 7].control = value; break;
|
||||
case 0x00: case 0x07: case 0x0e: oscillator().pitch.load<0>(value); break;
|
||||
case 0x01: case 0x08: case 0x0f: oscillator().pitch.load<8>(value); break;
|
||||
case 0x02: case 0x09: case 0x10: oscillator().pulse_width.load<0>(value); break;
|
||||
case 0x03: case 0x0a: case 0x11: oscillator().pulse_width.load<8>(value); break;
|
||||
case 0x04: case 0x0b: case 0x12: voice().control = value; break;
|
||||
case 0x05: case 0x0c: case 0x13:
|
||||
voices_[address.get() / 7].attack = value >> 4;
|
||||
voices_[address.get() / 7].decay = value;
|
||||
adsr().attack = value >> 4;
|
||||
adsr().decay = value;
|
||||
break;
|
||||
case 0x06: case 0x0d: case 0x14:
|
||||
voices_[address.get() / 7].sustain = value >> 4;
|
||||
voices_[address.get() / 7].release = value;
|
||||
adsr().sustain = value >> 4;
|
||||
adsr().release = value;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
+69
-22
@@ -32,40 +32,87 @@ private:
|
||||
Concurrency::AsyncTaskQueue<false> &audio_queue_;
|
||||
|
||||
struct Voice {
|
||||
Numeric::SizedInt<16> pitch;
|
||||
Numeric::SizedInt<12> pulse_width;
|
||||
struct Oscillator {
|
||||
// Programmer inputs.
|
||||
Numeric::SizedInt<16> pitch;
|
||||
Numeric::SizedInt<12> pulse_width;
|
||||
|
||||
// State.
|
||||
Numeric::SizedInt<24> phase;
|
||||
Numeric::SizedInt<24> previous_phase;
|
||||
} oscillator;
|
||||
struct ADSR {
|
||||
// Programmer inputs.
|
||||
Numeric::SizedInt<4> attack;
|
||||
Numeric::SizedInt<4> decay;
|
||||
Numeric::SizedInt<4> sustain;
|
||||
Numeric::SizedInt<4> release;
|
||||
|
||||
// State.
|
||||
Numeric::SizedInt<8> envelope;
|
||||
Numeric::SizedInt<15> rate_counter;
|
||||
enum class Phase {
|
||||
Attack,
|
||||
DecayAndHold,
|
||||
Release,
|
||||
} phase_ = Phase::Attack;
|
||||
} adsr;
|
||||
Numeric::SizedInt<8> control;
|
||||
Numeric::SizedInt<4> attack;
|
||||
Numeric::SizedInt<4> decay;
|
||||
Numeric::SizedInt<4> sustain;
|
||||
Numeric::SizedInt<4> release;
|
||||
|
||||
bool noise() const { return control.bit<7>(); }
|
||||
bool pulse() const { return control.bit<6>(); }
|
||||
bool sawtooth() const { return control.bit<5>(); }
|
||||
bool triangle() const { return control.bit<4>(); }
|
||||
bool test() const { return control.bit<3>(); } // Implemented.
|
||||
bool ring_mod() const { return control.bit<2>(); }
|
||||
bool sync() const { return control.bit<1>(); } // Implemented.
|
||||
bool gate() const { return control.bit<0>(); }
|
||||
|
||||
Numeric::SizedInt<24> phase;
|
||||
Numeric::SizedInt<24> previous_phase;
|
||||
bool noise() const { return control.bit<7>(); }
|
||||
bool pulse() const { return control.bit<6>(); }
|
||||
bool sawtooth() const { return control.bit<5>(); }
|
||||
bool triangle() const { return control.bit<4>(); }
|
||||
bool test() const { return control.bit<3>(); } // Implemented.
|
||||
bool ring_mod() const { return control.bit<2>(); }
|
||||
bool sync() const { return control.bit<1>(); } // Implemented.
|
||||
bool gate() const { return control.bit<0>(); }
|
||||
|
||||
void update() {
|
||||
previous_phase = phase;
|
||||
// Oscillator.
|
||||
oscillator.previous_phase = oscillator.phase;
|
||||
if(test()) {
|
||||
phase = 0;
|
||||
oscillator.phase = 0;
|
||||
} else {
|
||||
phase += pitch.get();
|
||||
oscillator.phase += oscillator.pitch.get();
|
||||
}
|
||||
|
||||
// TODO: ADSR.
|
||||
}
|
||||
|
||||
void synchronise(const Voice &prior) {
|
||||
if(sync() && !prior.previous_phase.bit<23>() && prior.phase.bit<23>()) {
|
||||
phase = 0;
|
||||
// Only oscillator work to do here.
|
||||
if(
|
||||
sync() &&
|
||||
!prior.oscillator.previous_phase.bit<23>() &&
|
||||
prior.oscillator.phase.bit<23>()
|
||||
) {
|
||||
oscillator.phase = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr uint16_t MaxWaveformValue = (1 << 12) - 1;
|
||||
|
||||
uint16_t pulse_output() const {
|
||||
return oscillator.phase.get<12>() > oscillator.pulse_width.get() ? MaxWaveformValue : 0;
|
||||
}
|
||||
|
||||
uint16_t output() const {
|
||||
// TODO: true composite waves.
|
||||
//
|
||||
// My current understanding on this: if multiple waveforms are enabled, the pull to zero beats the
|
||||
// pull to one on any line where the two compete. But the twist is that the lines are not necessarily
|
||||
// one per bit since they lead to a common ground. Ummm, I think.
|
||||
//
|
||||
// Anyway, first pass: logical AND. It's not right. It will temporarily do.
|
||||
|
||||
uint16_t output = MaxWaveformValue;
|
||||
|
||||
if(pulse()) output &= pulse_output();
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Voice voices_[3];
|
||||
|
||||
@@ -24,8 +24,9 @@ struct SizedInt {
|
||||
constexpr SizedInt(const IntT start_value) noexcept : counter_(start_value & Mask) {}
|
||||
SizedInt() = default;
|
||||
|
||||
template <int begin = 0>
|
||||
IntT get() const {
|
||||
return counter_;
|
||||
return counter_ >> begin;
|
||||
}
|
||||
|
||||
SizedInt operator +(const SizedInt offset) const { return SizedInt<bits>(counter_ + offset.counter_); }
|
||||
|
||||
Reference in New Issue
Block a user