1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-23 20:29:42 +00:00

Adds a pipeline for audio output.

This commit is contained in:
Thomas Harte 2021-12-01 05:37:58 -05:00
parent eb3a0eb3c7
commit a8dd4660b2
5 changed files with 67 additions and 5 deletions

View File

@ -40,6 +40,7 @@ namespace Amiga {
class ConcreteMachine:
public Activity::Source,
public CPU::MC68000::BusHandler,
public MachineTypes::AudioProducer,
public MachineTypes::JoystickMachine,
public MachineTypes::MappedKeyboardMachine,
public MachineTypes::MediaTarget,
@ -183,10 +184,17 @@ class ConcreteMachine:
Chipset chipset_;
// MARK: - Activity Source
void set_activity_observer(Activity::Observer *observer) final {
chipset_.set_activity_observer(observer);
}
// MARK: - MachineTypes::AudioProducer.
Outputs::Speaker::Speaker *get_speaker() final {
return chipset_.get_speaker();
}
// MARK: - MachineTypes::ScanProducer.
void set_scan_target(Outputs::Display::ScanTarget *scan_target) final {

View File

@ -17,6 +17,17 @@
using namespace Amiga;
Audio::Audio(Chipset &chipset, uint16_t *ram, size_t word_size, float output_rate) :
DMADevice<4>(chipset, ram, word_size) {
// Mark all buffers as available.
for(auto &flag: buffer_available_) {
flag.store(true, std::memory_order::memory_order_relaxed);
}
speaker_.set_input_rate(output_rate);
}
bool Audio::advance_dma(int channel) {
switch(channels_[channel].state) {
case Channel::State::WaitingForDMA:
@ -90,6 +101,28 @@ void Audio::output() {
posit_interrupt(interrupts[c]);
}
}
// TEMPORARY: just fill the audio buffer with silence.
if(!sample_pointer_) {
while(!buffer_available_[buffer_pointer_].load(std::memory_order::memory_order_relaxed));
}
buffer_[buffer_pointer_][sample_pointer_] = 0;
++sample_pointer_;
if(sample_pointer_ == buffer_[buffer_pointer_].size()) {
const auto &buffer = buffer_[buffer_pointer_];
auto &flag = buffer_available_[buffer_pointer_];
flag.store(false, std::memory_order::memory_order_release);
queue_.enqueue([this, &buffer, &flag] {
speaker_.push(buffer.data(), buffer.size());
flag.store(true, std::memory_order::memory_order_relaxed);
});
buffer_pointer_ = (buffer_pointer_ + 1) % BufferCount;
sample_pointer_ = 0;
}
}
/*

View File

@ -9,18 +9,19 @@
#ifndef Audio_hpp
#define Audio_hpp
#include <atomic>
#include <cstdint>
#include "DMADevice.hpp"
#include "../../ClockReceiver/ClockReceiver.hpp"
#include "../../Concurrency/AsyncTaskQueue.hpp"
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
namespace Amiga {
class Audio: public DMADevice<4> {
public:
Audio(
Chipset &chipset, uint16_t *ram, size_t word_size,
[[maybe_unused]] double output_rate) :
DMADevice<4>(chipset, ram, word_size) {}
Audio(Chipset &chipset, uint16_t *ram, size_t word_size, float output_rate);
/// Idiomatic call-in for DMA scheduling; indicates that this class may
/// perform a DMA access for the stated channel now.
@ -56,6 +57,11 @@ class Audio: public DMADevice<4> {
/// Sets which interrupt requests are currently active.
void set_interrupt_requests(uint16_t);
/// Obtains the output source.
Outputs::Speaker::Speaker *get_speaker() {
return &speaker_;
}
private:
struct Channel {
// The data latch plus a count of unused samples
@ -98,6 +104,16 @@ class Audio: public DMADevice<4> {
template <State state> bool output();
template <State begin, State end> bool transit();
} channels_[4];
// Transient output state, and its destination.
Outputs::Speaker::PushLowpass<true> speaker_;
Concurrency::AsyncTaskQueue queue_;
using AudioBuffer = std::array<int16_t, 4096>;
static constexpr int BufferCount = 3;
AudioBuffer buffer_[BufferCount];
std::atomic<bool> buffer_available_[BufferCount];
size_t buffer_pointer_ = 0, sample_pointer_ = 0;
};
}

View File

@ -45,7 +45,7 @@ Chipset::Chipset(MemoryMap &map, int input_clock_rate) :
},
bitplanes_(DMA_CONSTRUCT),
copper_(DMA_CONSTRUCT),
audio_(DMA_CONSTRUCT, input_clock_rate),
audio_(DMA_CONSTRUCT, float(input_clock_rate / 2.0)),
crt_(908, 4, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::Red4Green4Blue4),
cia_a_handler_(map, disk_controller_, mouse_),
cia_b_handler_(disk_controller_),

View File

@ -115,6 +115,11 @@ class Chipset: private ClockingHint::Observer {
// Input for receiving collected bitplanes.
void post_bitplanes(const BitplaneData &data);
// Obtains the source of audio output.
Outputs::Speaker::Speaker *get_speaker() {
return audio_.get_speaker();
}
private:
friend class DMADeviceBase;