1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-19 08:31:11 +00:00

Enables AY audio, albeit underclocked.

This commit is contained in:
Thomas Harte 2024-02-14 22:15:21 -05:00
parent 1e877c7563
commit 3ac5fdafab
2 changed files with 70 additions and 38 deletions

View File

@ -61,40 +61,10 @@ constexpr int MockingboardSlot = 4; // Conventional Mockingboard slot.
// * ... and hence seven pixels per memory access window clock in high-res mode, 14 in double high-res, etc.
constexpr float master_clock = 14318180.0;
class AYPair {
public:
AYPair(Concurrency::AsyncTaskQueue<false> &queue) :
ays_{
{GI::AY38910::Personality::AY38910, queue},
{GI::AY38910::Personality::AY38910, queue},
} {}
void advance() {
ays_[0].advance();
ays_[1].advance();
}
void set_sample_volume_range(std::int16_t range) {
ays_[0].set_sample_volume_range(range >> 1);
ays_[1].set_sample_volume_range(range >> 1);
}
bool is_zero_level() const {
return ays_[0].is_zero_level() && ays_[1].is_zero_level();
}
Outputs::Speaker::MonoSample level() const {
return ays_[0].level() + ays_[1].level();
}
private:
GI::AY38910::AY38910SampleSource<false> ays_[2];
};
/// Provides an AY that runs at the CPU rate divided by 4 given an input of the master clock divided by 2,
/// allowing for stretched CPU clock cycles.
struct StretchedAYPair:
AYPair,
Apple::II::AYPair,
public Outputs::Speaker::BufferSource<StretchedAYPair, false> {
using AYPair::AYPair;
@ -681,7 +651,7 @@ template <Analyser::Static::AppleII::Target::Model model, bool has_mockingboard>
if(target.has_mockingboard) {
// The Mockingboard has a parasitic relationship with this class due to the way
// that audio outputs are implemented in this emulator.
install_card(MockingboardSlot, new Apple::II::Mockingboard());
install_card(MockingboardSlot, new Apple::II::Mockingboard(ays_));
}
rom_ = std::move(roms.find(system)->second);

View File

@ -12,15 +12,48 @@
#include "../../../Components/6522/6522.hpp"
namespace Apple::II {
class AYPair {
public:
AYPair(Concurrency::AsyncTaskQueue<false> &queue) :
ays_{
{GI::AY38910::Personality::AY38910, queue},
{GI::AY38910::Personality::AY38910, queue},
} {}
void advance() {
ays_[0].advance();
ays_[1].advance();
}
void set_sample_volume_range(std::int16_t range) {
ays_[0].set_sample_volume_range(range >> 1);
ays_[1].set_sample_volume_range(range >> 1);
}
bool is_zero_level() const {
return ays_[0].is_zero_level() && ays_[1].is_zero_level();
}
Outputs::Speaker::MonoSample level() const {
return ays_[0].level() + ays_[1].level();
}
GI::AY38910::AY38910SampleSource<false> &get(int index) {
return ays_[index];
}
private:
GI::AY38910::AY38910SampleSource<false> ays_[2];
};
class Mockingboard: public Card {
public:
Mockingboard() :
vias_{ {handlers_[0]}, {handlers_[1]} } {
Mockingboard(AYPair &ays) :
vias_{ {handlers_[0]}, {handlers_[1]} },
handlers_{ {*this, ays.get(0)}, {*this, ays.get(1)}} {
set_select_constraints(0);
handlers_[0].card = handlers_[1].card = this;
}
void perform_bus_operation(Select select, bool is_read, uint16_t address, uint8_t *value) final {
@ -55,13 +88,42 @@ class Mockingboard: public Card {
private:
struct AYVIA: public MOS::MOS6522::PortHandler {
AYVIA(Mockingboard &card, GI::AY38910::AY38910SampleSource<false> &ay) :
card(card), ay(ay) {}
void set_interrupt_status(bool status) {
interrupt = status;
card->did_change_interrupt_flags();
card.did_change_interrupt_flags();
}
void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) {
if(port) {
using ControlLines = GI::AY38910::ControlLines;
ay.set_control_lines(
ControlLines(
((value & 1) ? ControlLines::BC1 : 0) |
((value & 2) ? ControlLines::BDIR : 0) |
((value & 4) ? ControlLines::BC2 : 0)
)
);
// TODO: all lines disabled sees to map to reset? Possibly?
// Cf. https://gswv.apple2.org.za/a2zine/Docs/Mockingboard_MiniManual.html
} else {
ay.set_data_input(value);
}
}
uint8_t get_port_input(MOS::MOS6522::Port port) {
if(!port) {
return ay.get_data_output();
}
return 0xff;
}
bool interrupt;
Mockingboard *card = nullptr;
Mockingboard &card;
GI::AY38910::AY38910SampleSource<false> &ay;
};
MOS::MOS6522::MOS6522<AYVIA> vias_[2];