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:
parent
eb3a0eb3c7
commit
a8dd4660b2
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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_),
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user