From 17635da81295c15e0b8a47b01361b71178f82bde Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 1 Jun 2019 15:18:27 -0400 Subject: [PATCH] Pushes Mac audio further towards being able to function. --- Machines/Apple/Macintosh/Audio.cpp | 28 +++++++++++++++++++------- Machines/Apple/Macintosh/Audio.hpp | 9 ++++++--- Machines/Apple/Macintosh/Macintosh.cpp | 2 +- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Machines/Apple/Macintosh/Audio.cpp b/Machines/Apple/Macintosh/Audio.cpp index 7f476db0b..016c81f73 100644 --- a/Machines/Apple/Macintosh/Audio.cpp +++ b/Machines/Apple/Macintosh/Audio.cpp @@ -10,41 +10,55 @@ using namespace Apple::Macintosh; +namespace { +const HalfCycles sample_length(704); +} + Audio::Audio(Concurrency::DeferringAsyncTaskQueue &task_queue) : task_queue_(task_queue) {} // MARK: - Inputs void Audio::post_sample(uint8_t sample) { + // Grab the read and write pointers, ensure there's room for a new sample and, if not, + // drop this one. const auto write_pointer = sample_queue_.write_pointer.load(); -// const auto pointers - const auto read_pointer = sample_queue_.read_pointer.load(); + const decltype(write_pointer) next_write_pointer = (write_pointer + 1) % sample_queue_.buffer.size(); + if(next_write_pointer == read_pointer) return; + + sample_queue_.buffer[write_pointer] = sample; + sample_queue_.write_pointer.store(next_write_pointer); } void Audio::set_volume(int volume) { + // Post the volume change as a deferred event. task_queue_.defer([=] () { volume_ = volume; }); } void Audio::set_enabled(bool on) { + // Post the enabled mask change as a deferred event. task_queue_.defer([=] () { - is_enabled_ = on; + enabled_mask_ = on ? 1 : 0; }); } // MARK: - Output generation bool Audio::is_zero_level() { - return !volume_ || !is_enabled_; + return !volume_ || !enabled_mask_; } void Audio::set_sample_volume_range(std::int16_t range) { + // Some underflow here doesn't really matter. volume_multiplier_ = range / 7; } void Audio::get_samples(std::size_t number_of_samples, int16_t *target) { -// if(is_zero_level()) { -// memset(target, 0, number_of_samples * sizeof(int16_t)); -// } + // TODO. +} + +void Audio::skip_samples(std::size_t number_of_samples) { + // TODO. } diff --git a/Machines/Apple/Macintosh/Audio.hpp b/Machines/Apple/Macintosh/Audio.hpp index ea3c035cb..375d1c247 100644 --- a/Machines/Apple/Macintosh/Audio.hpp +++ b/Machines/Apple/Macintosh/Audio.hpp @@ -9,9 +9,9 @@ #ifndef Audio_hpp #define Audio_hpp -#include "../../../Outputs/Speaker/Implementation/SampleSource.hpp" #include "../../../Concurrency/AsyncTaskQueue.hpp" #include "../../../ClockReceiver/ClockReceiver.hpp" +#include "../../../Outputs/Speaker/Implementation/SampleSource.hpp" #include #include @@ -51,6 +51,7 @@ class Audio: public ::Outputs::Speaker::SampleSource { // to satisfy ::Outputs::Speaker (included via ::Outputs::Filter. void get_samples(std::size_t number_of_samples, int16_t *target); + void skip_samples(std::size_t number_of_samples); bool is_zero_level(); void set_sample_volume_range(std::int16_t range); @@ -61,15 +62,17 @@ class Audio: public ::Outputs::Speaker::SampleSource { // written to by another. struct { std::array buffer; - std::atomic read_pointer, write_pointer; + std::atomic read_pointer, write_pointer; } sample_queue_; // Stateful variables, modified from the audio generation // thread only. int volume_ = 0; - bool is_enabled_ = false; + int enabled_mask_ = 0; std::int16_t volume_multiplier_ = 0; + + HalfCycles subcycle_offset_; }; } diff --git a/Machines/Apple/Macintosh/Macintosh.cpp b/Machines/Apple/Macintosh/Macintosh.cpp index 6d1946211..7f282086d 100644 --- a/Machines/Apple/Macintosh/Macintosh.cpp +++ b/Machines/Apple/Macintosh/Macintosh.cpp @@ -236,7 +236,7 @@ class ConcreteMachine: // video_.run_for(time_since_video_update_.flush()); // As above: flush audio after video. - audio_.queue.flush(); + audio_.queue.perform(); } void set_rom_is_overlay(bool rom_is_overlay) {