From 9c550c594acc52a028873889a9b847acfe160fc2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 9 Nov 2016 21:17:50 -0500 Subject: [PATCH 1/3] Moved audio work back into its own thread, but this time it queues up an all happens only upon a flush. Hopefully to resolve synchronisation cost concerns. --- Machines/Oric/Oric.cpp | 1 + Outputs/Speaker.hpp | 30 +++++++++++++++++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index a3a5b7b3c..fc06421a8 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -213,6 +213,7 @@ uint8_t Machine::VIA::get_port_input(Port port) void Machine::VIA::synchronise() { ay8910->run_for_cycles(_cycles_since_ay_update); + ay8910->flush(); _cycles_since_ay_update = 0; } diff --git a/Outputs/Speaker.hpp b/Outputs/Speaker.hpp index bceeb1d5b..f2830908f 100644 --- a/Outputs/Speaker.hpp +++ b/Outputs/Speaker.hpp @@ -12,6 +12,10 @@ #include #include #include + +#include +#include + #include "../SignalProcessing/Stepper.hpp" #include "../SignalProcessing/FIRFilter.hpp" #include "../Concurrency/AsyncTaskQueue.hpp" @@ -87,16 +91,28 @@ class Speaker { Speaker() : _buffer_in_progress_pointer(0), _requested_number_of_taps(0), _high_frequency_cut_off(-1.0), _queue(new Concurrency::AsyncTaskQueue) {} + /*! + Ensures any deferred processing occurs now. + */ + void flush() + { + std::shared_ptr>> queued_functions = _queued_functions; + _queued_functions.reset(); + _queue->enqueue([queued_functions] { + for(auto function : *queued_functions) + { + function(); + } + }); + } + protected: void enqueue(std::function function) { - function(); -// _queue->enqueue(function); - } - void flush() - { -// _queue->flush(); + if(!_queued_functions) _queued_functions.reset(new std::list>); + _queued_functions->push_back(function); } + std::shared_ptr>> _queued_functions; std::unique_ptr _buffer_in_progress; float _high_frequency_cut_off; @@ -137,7 +153,7 @@ template class Filter: public Speaker { public: ~Filter() { - flush(); + _queue->flush(); } void run_for_cycles(unsigned int input_cycles) From 77ce200fbb80e8780641894da98733d93a8a80c5 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 9 Nov 2016 21:21:17 -0500 Subject: [PATCH 2/3] Simplified/corrected AY tone/noise mixer logic, and made a new guess at the effect of reading registers that are smaller than 8 bits. --- Components/AY38910/AY38910.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Components/AY38910/AY38910.cpp b/Components/AY38910/AY38910.cpp index 787d27abf..b5a0641b4 100644 --- a/Components/AY38910/AY38910.cpp +++ b/Components/AY38910/AY38910.cpp @@ -149,11 +149,12 @@ void AY38910::evaluate_output_volume() // The output level for a channel is: // 1 if neither tone nor noise is enabled; // 0 if either tone or noise is enabled and its value is low. - // (which is implemented here with reverse logic, assuming _channel_output and _noise_output are already inverted) -#define level(c, tb, nb) \ - (((((_output_registers[7] >> tb)&1)^1) & _tone_outputs[c]) | ((((_output_registers[7] >> nb)&1)^1) & _noise_output)) ^ 1 + // The tone/noise enable bits use inverse logic — 0 = on, 1 = off — permitting the OR logic below. +#define tone_level(c, tone_bit) (_tone_outputs[c] | (_output_registers[7] >> tone_bit)) +#define noise_level(c, noise_bit) (_noise_output | (_output_registers[7] >> noise_bit)) - int channel_levels[3] = { +#define level(c, tone_bit, noise_bit) tone_level(c, tone_bit) & noise_level(c, noise_bit) & 1 + const int channel_levels[3] = { level(0, 0, 3), level(1, 1, 4), level(2, 2, 5), @@ -164,7 +165,7 @@ void AY38910::evaluate_output_volume() #define channel_volume(c) \ ((_output_registers[c] >> 4)&1) * envelope_volume + (((_output_registers[c] >> 4)&1)^1) * (_output_registers[c]&0xf) - int volumes[3] = { + const int volumes[3] = { channel_volume(8), channel_volume(9), channel_volume(10) @@ -235,7 +236,15 @@ void AY38910::set_register_value(uint8_t value) uint8_t AY38910::get_register_value() { - return _registers[_selected_register]; + // This table ensures that bits that aren't defined within the AY are returned as 1s + // when read. I can't find documentation on this and don't have a machine to test, so + // this is provisionally a guess. TODO: investigate. + const uint8_t register_masks[16] = { + 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0xe0, 0x00, + 0xe0, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0x00, 0x00 + }; + + return _registers[_selected_register] | register_masks[_selected_register]; } uint8_t AY38910::get_port_output(bool port_b) From 77987bf31e51f841519c0c5006dc2df500675cba Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 9 Nov 2016 21:51:56 -0500 Subject: [PATCH 3/3] Decided to go with divide by 256 for the envelope counter after all. --- Components/AY38910/AY38910.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Components/AY38910/AY38910.cpp b/Components/AY38910/AY38910.cpp index b5a0641b4..db8249cf1 100644 --- a/Components/AY38910/AY38910.cpp +++ b/Components/AY38910/AY38910.cpp @@ -124,7 +124,7 @@ void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) if(_envelope_divider) _envelope_divider--; else { - _envelope_divider = _envelope_period; + _envelope_divider = _envelope_period * 16; _envelope_position ++; if(_envelope_position == 32) _envelope_position = _envelope_overflow_masks[_output_registers[13]]; } @@ -215,12 +215,12 @@ void AY38910::set_register_value(uint8_t value) case 11: _envelope_period = (_envelope_period & ~0xff) | value; - _envelope_divider = _envelope_period; + _envelope_divider = _envelope_period * 16; break; case 12: _envelope_period = (_envelope_period & 0xff) | (int)(value << 8); - _envelope_divider = _envelope_period; + _envelope_divider = _envelope_period * 16; break; case 13: