mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-27 18:55:48 +00:00
Attempt full audio output.
This commit is contained in:
parent
972d1d1ddd
commit
3da3401125
@ -32,20 +32,57 @@
|
|||||||
|
|
||||||
namespace PCCompatible {
|
namespace PCCompatible {
|
||||||
|
|
||||||
|
struct PCSpeaker {
|
||||||
|
PCSpeaker() :
|
||||||
|
toggle(queue),
|
||||||
|
speaker(toggle) {}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
speaker.run_for(queue, cycles_since_update);
|
||||||
|
cycles_since_update = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_pit(bool pit_input) {
|
||||||
|
pit_input_ = pit_input;
|
||||||
|
set_level();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_control(bool pit_mask, bool level) {
|
||||||
|
pit_mask_ = pit_mask;
|
||||||
|
level_ = level;
|
||||||
|
set_level();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_level() {
|
||||||
|
toggle.set_output(pit_mask_ ? pit_input_ : level_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Concurrency::AsyncTaskQueue<false> queue;
|
||||||
|
Audio::Toggle toggle;
|
||||||
|
Outputs::Speaker::PullLowpass<Audio::Toggle> speaker;
|
||||||
|
Cycles cycles_since_update = 0;
|
||||||
|
|
||||||
|
bool pit_input_ = false;
|
||||||
|
bool pit_mask_ = false;
|
||||||
|
bool level_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
class PITObserver {
|
class PITObserver {
|
||||||
public:
|
public:
|
||||||
PITObserver(PIC &pic) : pic_(pic) {}
|
PITObserver(PIC &pic, PCSpeaker &speaker) : pic_(pic), speaker_(speaker) {}
|
||||||
|
|
||||||
template <int channel>
|
template <int channel>
|
||||||
void update_output(bool new_level) {
|
void update_output(bool new_level) {
|
||||||
switch(channel) {
|
switch(channel) {
|
||||||
default: break;
|
default: break;
|
||||||
case 0: pic_.apply_edge<0>(new_level); break;
|
case 0: pic_.apply_edge<0>(new_level); break;
|
||||||
|
case 2: speaker_.set_pit(new_level); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PIC &pic_;
|
PIC &pic_;
|
||||||
|
PCSpeaker &speaker_;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
//
|
//
|
||||||
@ -58,10 +95,13 @@ using PIT = i8237<false, PITObserver>;
|
|||||||
class i8255PortHandler : public Intel::i8255::PortHandler {
|
class i8255PortHandler : public Intel::i8255::PortHandler {
|
||||||
// Likely to be helpful: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol
|
// Likely to be helpful: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol
|
||||||
public:
|
public:
|
||||||
|
i8255PortHandler(PCSpeaker &speaker) : speaker_(speaker) {}
|
||||||
|
|
||||||
void set_value(int port, uint8_t value) {
|
void set_value(int port, uint8_t value) {
|
||||||
switch(port) {
|
switch(port) {
|
||||||
case 1:
|
case 1:
|
||||||
high_switches_ = value & 0x08;
|
high_switches_ = value & 0x08;
|
||||||
|
speaker_.set_control(value & 0x01, value & 0x02);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
printf("PPI: %02x to %d\n", value, port);
|
printf("PPI: %02x to %d\n", value, port);
|
||||||
@ -93,6 +133,7 @@ class i8255PortHandler : public Intel::i8255::PortHandler {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool high_switches_ = false;
|
bool high_switches_ = false;
|
||||||
|
PCSpeaker &speaker_;
|
||||||
|
|
||||||
// Provisionally, possibly:
|
// Provisionally, possibly:
|
||||||
//
|
//
|
||||||
@ -537,17 +578,16 @@ class ConcreteMachine:
|
|||||||
[[maybe_unused]] const Analyser::Static::Target &target,
|
[[maybe_unused]] const Analyser::Static::Target &target,
|
||||||
const ROMMachine::ROMFetcher &rom_fetcher
|
const ROMMachine::ROMFetcher &rom_fetcher
|
||||||
) :
|
) :
|
||||||
pit_observer_(pic_),
|
pit_observer_(pic_, speaker_),
|
||||||
|
ppi_handler_(speaker_),
|
||||||
pit_(pit_observer_),
|
pit_(pit_observer_),
|
||||||
ppi_(ppi_handler_),
|
ppi_(ppi_handler_),
|
||||||
context(pit_, dma_, ppi_, pic_),
|
context(pit_, dma_, ppi_, pic_)
|
||||||
audio_toggle_(audio_queue_),
|
|
||||||
speaker_(audio_toggle_)
|
|
||||||
{
|
{
|
||||||
// Use clock rate as a MIPS count; keeping it as a multiple or divisor of the PIT frequency is easy.
|
// Use clock rate as a MIPS count; keeping it as a multiple or divisor of the PIT frequency is easy.
|
||||||
static constexpr int pit_frequency = 1'193'182;
|
static constexpr int pit_frequency = 1'193'182;
|
||||||
set_clock_rate(double(pit_frequency));
|
set_clock_rate(double(pit_frequency));
|
||||||
speaker_.set_input_rate(double(pit_frequency));
|
speaker_.speaker.set_input_rate(double(pit_frequency));
|
||||||
|
|
||||||
// Fetch the BIOS. [8088 only, for now]
|
// Fetch the BIOS. [8088 only, for now]
|
||||||
const auto bios = ROM::Name::PCCompatibleGLaBIOS;
|
const auto bios = ROM::Name::PCCompatibleGLaBIOS;
|
||||||
@ -563,7 +603,7 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
~ConcreteMachine() {
|
~ConcreteMachine() {
|
||||||
audio_queue_.flush();
|
speaker_.queue.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - TimedMachine.
|
// MARK: - TimedMachine.
|
||||||
@ -579,8 +619,8 @@ class ConcreteMachine:
|
|||||||
// Advance the PIT.
|
// Advance the PIT.
|
||||||
pit_.run_for(1);
|
pit_.run_for(1);
|
||||||
|
|
||||||
// Advance audio.
|
// Advance audio clock.
|
||||||
++cycles_since_audio_update_;
|
++speaker_.cycles_since_update;
|
||||||
|
|
||||||
// Advance the CPU.
|
// Advance the CPU.
|
||||||
cpu_divisor_ += CPUMultiplier;
|
cpu_divisor_ += CPUMultiplier;
|
||||||
@ -652,23 +692,20 @@ class ConcreteMachine:
|
|||||||
|
|
||||||
// MARK: - AudioProducer.
|
// MARK: - AudioProducer.
|
||||||
Outputs::Speaker::Speaker *get_speaker() override {
|
Outputs::Speaker::Speaker *get_speaker() override {
|
||||||
return &speaker_;
|
return &speaker_.speaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush_output(int outputs) final {
|
void flush_output(int outputs) final {
|
||||||
if(outputs & Output::Audio) {
|
if(outputs & Output::Audio) {
|
||||||
update_audio();
|
speaker_.update();
|
||||||
audio_queue_.perform();
|
speaker_.queue.perform();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_audio() {
|
|
||||||
speaker_.run_for(audio_queue_, cycles_since_audio_update_);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PIC pic_;
|
PIC pic_;
|
||||||
DMA dma_;
|
DMA dma_;
|
||||||
|
PCSpeaker speaker_;
|
||||||
|
|
||||||
PITObserver pit_observer_;
|
PITObserver pit_observer_;
|
||||||
i8255PortHandler ppi_handler_;
|
i8255PortHandler ppi_handler_;
|
||||||
@ -709,12 +746,6 @@ class ConcreteMachine:
|
|||||||
std::pair<int, InstructionSet::x86::Instruction<false>> decoded;
|
std::pair<int, InstructionSet::x86::Instruction<false>> decoded;
|
||||||
|
|
||||||
int cpu_divisor_ = 0;
|
int cpu_divisor_ = 0;
|
||||||
|
|
||||||
// PC speaker.
|
|
||||||
Concurrency::AsyncTaskQueue<false> audio_queue_;
|
|
||||||
Audio::Toggle audio_toggle_;
|
|
||||||
Outputs::Speaker::PullLowpass<Audio::Toggle> speaker_;
|
|
||||||
Cycles cycles_since_audio_update_ = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user