mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-19 23:32:28 +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.
|
// * ... 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;
|
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,
|
/// 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.
|
/// allowing for stretched CPU clock cycles.
|
||||||
struct StretchedAYPair:
|
struct StretchedAYPair:
|
||||||
AYPair,
|
Apple::II::AYPair,
|
||||||
public Outputs::Speaker::BufferSource<StretchedAYPair, false> {
|
public Outputs::Speaker::BufferSource<StretchedAYPair, false> {
|
||||||
|
|
||||||
using AYPair::AYPair;
|
using AYPair::AYPair;
|
||||||
@ -681,7 +651,7 @@ template <Analyser::Static::AppleII::Target::Model model, bool has_mockingboard>
|
|||||||
if(target.has_mockingboard) {
|
if(target.has_mockingboard) {
|
||||||
// The Mockingboard has a parasitic relationship with this class due to the way
|
// The Mockingboard has a parasitic relationship with this class due to the way
|
||||||
// that audio outputs are implemented in this emulator.
|
// 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);
|
rom_ = std::move(roms.find(system)->second);
|
||||||
|
@ -12,15 +12,48 @@
|
|||||||
|
|
||||||
#include "../../../Components/6522/6522.hpp"
|
#include "../../../Components/6522/6522.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace Apple::II {
|
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 {
|
class Mockingboard: public Card {
|
||||||
public:
|
public:
|
||||||
Mockingboard() :
|
Mockingboard(AYPair &ays) :
|
||||||
vias_{ {handlers_[0]}, {handlers_[1]} } {
|
vias_{ {handlers_[0]}, {handlers_[1]} },
|
||||||
|
handlers_{ {*this, ays.get(0)}, {*this, ays.get(1)}} {
|
||||||
set_select_constraints(0);
|
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 {
|
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:
|
private:
|
||||||
struct AYVIA: public MOS::MOS6522::PortHandler {
|
struct AYVIA: public MOS::MOS6522::PortHandler {
|
||||||
|
AYVIA(Mockingboard &card, GI::AY38910::AY38910SampleSource<false> &ay) :
|
||||||
|
card(card), ay(ay) {}
|
||||||
|
|
||||||
void set_interrupt_status(bool status) {
|
void set_interrupt_status(bool status) {
|
||||||
interrupt = 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;
|
bool interrupt;
|
||||||
Mockingboard *card = nullptr;
|
Mockingboard &card;
|
||||||
|
GI::AY38910::AY38910SampleSource<false> &ay;
|
||||||
};
|
};
|
||||||
|
|
||||||
MOS::MOS6522::MOS6522<AYVIA> vias_[2];
|
MOS::MOS6522::MOS6522<AYVIA> vias_[2];
|
||||||
|
Loading…
Reference in New Issue
Block a user