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:
parent
1e877c7563
commit
3ac5fdafab
@ -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);
|
||||
|
@ -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];
|
||||
|
Loading…
Reference in New Issue
Block a user