From 782ef960e16b94d3c8006eda37214079169c8dc9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 21 Oct 2016 20:05:38 -0400 Subject: [PATCH 1/8] Sought both to [start to] optimise the AY and correct divider reloads. It turns out that conditionals aren't that troubling. But I can probably eliminate the counters. --- Components/AY38910/AY38910.cpp | 119 +++++++++++++++++---------------- Components/AY38910/AY38910.hpp | 3 + 2 files changed, 66 insertions(+), 56 deletions(-) diff --git a/Components/AY38910/AY38910.cpp b/Components/AY38910/AY38910.cpp index 8595db8d9..f9c347f71 100644 --- a/Components/AY38910/AY38910.cpp +++ b/Components/AY38910/AY38910.cpp @@ -82,86 +82,90 @@ void AY38910::set_clock_rate(double clock_rate) void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) { - for(int c = 0; c < number_of_samples; c++) + int offset = _master_divider; + int c = _master_divider; + _master_divider += number_of_samples; + + for(; c < 16 && c < _master_divider; c++) target[c - offset] = _output_volume; + while(c < _master_divider) { - // a master divider divides the clock by 16; - // resulting_steps will be 1 if a tick occurred, 0 otherwise - int former_master_divider = _master_divider; - _master_divider++; - int resulting_steps = ((_master_divider ^ former_master_divider) >> 4) & 1; - - // Bluffer's guide to the stuff below: I wanted to avoid branches. If I avoid branches then - // I avoid stalls. - // - // Repeating patterns are: - // (1) decrement, then shift a high-order bit right and mask to get 1 for did underflow, 0 otherwise; - // (2) did_underflow * a + (did_underflow ^ 1) * b to pick between reloading and not reloading - int did_underflow; -#define shift(x, r, steps) \ - x -= steps; \ - did_underflow = (x >> 16)&1; \ - x = did_underflow * r + (did_underflow^1) * x; - #define step_channel(c) \ - shift(_channel_dividers[c], _tone_generator_controls[c], resulting_steps); \ - _channel_output[c] ^= did_underflow; + if(_channel_dividers[c]) _channel_dividers[c] --; \ + else { _channel_dividers[c] = _tone_generator_controls[c]; _channel_output[c] ^= 1; } // update the tone channels step_channel(0); step_channel(1); step_channel(2); +#undef step_channel + // ... the noise generator. This recomputes the new bit repeatedly but harmlessly, only shifting // it into the official 17 upon divider underflow. - shift(_noise_divider, _output_registers[6]&0x1f, resulting_steps); - _noise_output ^= did_underflow&_noise_shift_register&1; - _noise_shift_register |= ((_noise_shift_register ^ (_noise_shift_register >> 3))&1) << 17; - _noise_shift_register >>= did_underflow; + if(_noise_divider) _noise_divider--; + else + { + _noise_divider = _output_registers[6]&0x1f; + _noise_output ^= _noise_shift_register&1; + _noise_shift_register |= ((_noise_shift_register ^ (_noise_shift_register >> 3))&1) << 17; + _noise_shift_register >>= 1; + } // ... and the envelope generator. Table based for pattern lookup, with a 'refill' step — a way of // implementing non-repeating patterns by locking them to table position 0x1f. -// int envelope_divider = ((_master_divider ^ former_master_divider) >> 8) & 1; - shift(_envelope_divider, _envelope_period, resulting_steps); - _envelope_position += did_underflow; - int refill = _envelope_overflow_masks[_output_registers[13]] * (_envelope_position >> 5); - _envelope_position = (_envelope_position & 0x1f) | refill; - int envelope_volume = _envelope_shapes[_output_registers[13]][_envelope_position]; + if(_envelope_divider) _envelope_divider--; + else + { + _envelope_divider = _envelope_period; + _envelope_position ++; + if(_envelope_position == 32) _envelope_position = _envelope_overflow_masks[_output_registers[13]]; + } -#undef step_channel -#undef shift + 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) + for(int ic = 0; ic < 16 && c < _master_divider; ic++) + { + target[c - offset] = _output_volume; + c++; + } + } +} + +void AY38910::evaluate_output_volume() +{ + int envelope_volume = _envelope_shapes[_output_registers[13]][_envelope_position]; + + // 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) & _channel_output[c]) | ((((_output_registers[7] >> nb)&1)^1) & _noise_output)) ^ 1 - int channel_levels[3] = { - level(0, 0, 3), - level(1, 1, 4), - level(2, 2, 5), - }; + int channel_levels[3] = { + level(0, 0, 3), + level(1, 1, 4), + level(2, 2, 5), + }; #undef level // Channel volume is a simple selection: if the bit at 0x10 is set, use the envelope volume; otherwise use the lower four bits #define channel_volume(c) \ ((_output_registers[c] >> 4)&1) * envelope_volume + (((_output_registers[c] >> 4)&1)^1) * (_output_registers[c]&0xf) - int volumes[3] = { - channel_volume(8), - channel_volume(9), - channel_volume(10) - }; + int volumes[3] = { + channel_volume(8), + channel_volume(9), + channel_volume(10) + }; #undef channel_volume - // Mix additively. TODO: non-linear volume. - target[c] = (int16_t)( - _volumes[volumes[0]] * channel_levels[0] + - _volumes[volumes[1]] * channel_levels[1] + - _volumes[volumes[2]] * channel_levels[2] - ); - } + // Mix additively. + _output_volume = (int16_t)( + _volumes[volumes[0]] * channel_levels[0] + + _volumes[volumes[1]] * channel_levels[1] + + _volumes[volumes[2]] * channel_levels[2] + ); } void AY38910::skip_samples(unsigned int number_of_samples) @@ -188,21 +192,23 @@ void AY38910::set_register_value(uint8_t value) case 0: case 2: case 4: _tone_generator_controls[selected_register >> 1] = (_tone_generator_controls[selected_register >> 1] & ~0xff) | value; + _channel_dividers[selected_register >> 1] = _tone_generator_controls[selected_register >> 1]; break; case 1: case 3: case 5: _tone_generator_controls[selected_register >> 1] = (_tone_generator_controls[selected_register >> 1] & 0xff) | (uint16_t)((value&0xf) << 8); + _channel_dividers[selected_register >> 1] = _tone_generator_controls[selected_register >> 1]; break; case 11: _envelope_period = (_envelope_period & ~0xff) | value; -// printf("e: %d", _envelope_period); + _envelope_divider = _envelope_period; break; case 12: _envelope_period = (_envelope_period & 0xff) | (int)(value << 8); -// printf("e: %d", _envelope_period); + _envelope_divider = _envelope_period; break; case 13: @@ -211,6 +217,7 @@ void AY38910::set_register_value(uint8_t value) break; } _output_registers[selected_register] = masked_value; + evaluate_output_volume(); }); } } diff --git a/Components/AY38910/AY38910.hpp b/Components/AY38910/AY38910.hpp index c6b5f7f78..ad9ef59f1 100644 --- a/Components/AY38910/AY38910.hpp +++ b/Components/AY38910/AY38910.hpp @@ -86,6 +86,9 @@ class AY38910: public ::Outputs::Filter { uint8_t get_register_value(); uint8_t _data_input, _data_output; + + int16_t _output_volume; + void evaluate_output_volume(); }; }; From d7c0c4971581cac10a3eb434f7d8e72c148ba185 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 21 Oct 2016 20:07:14 -0400 Subject: [PATCH 2/8] Might as well be consistent with divider loads. --- Components/AY38910/AY38910.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Components/AY38910/AY38910.cpp b/Components/AY38910/AY38910.cpp index f9c347f71..0145dc300 100644 --- a/Components/AY38910/AY38910.cpp +++ b/Components/AY38910/AY38910.cpp @@ -105,7 +105,7 @@ void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) if(_noise_divider) _noise_divider--; else { - _noise_divider = _output_registers[6]&0x1f; + _noise_divider = _output_registers[6]; _noise_output ^= _noise_shift_register&1; _noise_shift_register |= ((_noise_shift_register ^ (_noise_shift_register >> 3))&1) << 17; _noise_shift_register >>= 1; @@ -201,6 +201,11 @@ void AY38910::set_register_value(uint8_t value) _channel_dividers[selected_register >> 1] = _tone_generator_controls[selected_register >> 1]; break; + case 6: + masked_value &= 0x1f; + _noise_divider = masked_value; + break; + case 11: _envelope_period = (_envelope_period & ~0xff) | value; _envelope_divider = _envelope_period; From 46a3c0922fd3ebc46d41e373bbf775effa0f1a5a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 21 Oct 2016 22:12:44 -0400 Subject: [PATCH 3/8] Slightly simplified code, fixed divider. --- Components/AY38910/AY38910.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Components/AY38910/AY38910.cpp b/Components/AY38910/AY38910.cpp index 0145dc300..a4837c6ab 100644 --- a/Components/AY38910/AY38910.cpp +++ b/Components/AY38910/AY38910.cpp @@ -129,6 +129,8 @@ void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) c++; } } + + _master_divider &= 15; } void AY38910::evaluate_output_volume() @@ -190,15 +192,15 @@ void AY38910::set_register_value(uint8_t value) switch(selected_register) { case 0: case 2: case 4: - _tone_generator_controls[selected_register >> 1] = - (_tone_generator_controls[selected_register >> 1] & ~0xff) | value; - _channel_dividers[selected_register >> 1] = _tone_generator_controls[selected_register >> 1]; - break; - case 1: case 3: case 5: - _tone_generator_controls[selected_register >> 1] = - (_tone_generator_controls[selected_register >> 1] & 0xff) | (uint16_t)((value&0xf) << 8); - _channel_dividers[selected_register >> 1] = _tone_generator_controls[selected_register >> 1]; + { + int channel = selected_register >> 1; + if(selected_register & 1) + _tone_generator_controls[channel] = (_tone_generator_controls[channel] & 0xff) | (uint16_t)((value&0xf) << 8); + else + _tone_generator_controls[channel] = (_tone_generator_controls[channel] & ~0xff) | value; + _channel_dividers[channel] = _tone_generator_controls[channel]; + } break; case 6: From 33e628a0969144d459bb555596495ff053b5ca7e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 21 Oct 2016 22:16:44 -0400 Subject: [PATCH 4/8] Made an attempt to eliminate what amounts to manual division. --- Components/AY38910/AY38910.cpp | 16 ++++++++-------- Components/AY38910/AY38910.hpp | 5 ++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Components/AY38910/AY38910.cpp b/Components/AY38910/AY38910.cpp index a4837c6ab..fc6c2fd3a 100644 --- a/Components/AY38910/AY38910.cpp +++ b/Components/AY38910/AY38910.cpp @@ -12,7 +12,7 @@ using namespace GI; AY38910::AY38910() : _selected_register(0), - _channel_output{0, 0, 0}, _channel_dividers{0, 0, 0}, _tone_generator_controls{0, 0, 0}, + _tone_counters{0, 0, 0}, _tone_dividers{0, 0, 0}, _noise_shift_register(0xffff), _noise_divider(0), _noise_output(0), _envelope_divider(0), _envelope_period(0), _envelope_position(0), _output_registers{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -89,9 +89,7 @@ void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) for(; c < 16 && c < _master_divider; c++) target[c - offset] = _output_volume; while(c < _master_divider) { -#define step_channel(c) \ - if(_channel_dividers[c]) _channel_dividers[c] --; \ - else { _channel_dividers[c] = _tone_generator_controls[c]; _channel_output[c] ^= 1; } +#define step_channel(c) _tone_counters[c] = (_tone_counters[c] + 1) % (2 * (_tone_dividers[c] + 1)) // update the tone channels step_channel(0); @@ -142,7 +140,7 @@ void AY38910::evaluate_output_volume() // 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) & _channel_output[c]) | ((((_output_registers[7] >> nb)&1)^1) & _noise_output)) ^ 1 + (((((_output_registers[7] >> tb)&1)^1) & (_tone_counters[c] / (_tone_dividers[c] + 1))) | ((((_output_registers[7] >> nb)&1)^1) & _noise_output)) ^ 1 int channel_levels[3] = { level(0, 0, 3), @@ -195,11 +193,13 @@ void AY38910::set_register_value(uint8_t value) case 1: case 3: case 5: { int channel = selected_register >> 1; + + _tone_counters[channel] /= _tone_dividers[channel] + 1; if(selected_register & 1) - _tone_generator_controls[channel] = (_tone_generator_controls[channel] & 0xff) | (uint16_t)((value&0xf) << 8); + _tone_dividers[channel] = (_tone_dividers[channel] & 0xff) | (uint16_t)((value&0xf) << 8); else - _tone_generator_controls[channel] = (_tone_generator_controls[channel] & ~0xff) | value; - _channel_dividers[channel] = _tone_generator_controls[channel]; + _tone_dividers[channel] = (_tone_dividers[channel] & ~0xff) | value; + _tone_counters[channel] *= _tone_dividers[channel] + 1; } break; diff --git a/Components/AY38910/AY38910.hpp b/Components/AY38910/AY38910.hpp index ad9ef59f1..96d3724c1 100644 --- a/Components/AY38910/AY38910.hpp +++ b/Components/AY38910/AY38910.hpp @@ -55,9 +55,8 @@ class AY38910: public ::Outputs::Filter { int _selected_register; uint8_t _registers[16], _output_registers[16]; - int _tone_generator_controls[3]; - int _channel_dividers[3]; - int _channel_output[3]; + int _tone_dividers[3]; + int _tone_counters[3]; int _volumes[16]; From 583db88299bff9b95cd147e4340cf2f5227494d2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 22 Oct 2016 21:58:45 -0400 Subject: [PATCH 5/8] Added a dispatch queue-powered Apple implementation of the async task queue, removed any mention of skip_samples in the AY since it isn't implemented. --- Components/AY38910/AY38910.cpp | 6 ------ Components/AY38910/AY38910.hpp | 1 - Concurrency/AsyncTaskQueue.cpp | 21 ++++++++++++++++++++- Concurrency/AsyncTaskQueue.hpp | 8 ++++++++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Components/AY38910/AY38910.cpp b/Components/AY38910/AY38910.cpp index fc6c2fd3a..9e2aec75d 100644 --- a/Components/AY38910/AY38910.cpp +++ b/Components/AY38910/AY38910.cpp @@ -168,12 +168,6 @@ void AY38910::evaluate_output_volume() ); } -void AY38910::skip_samples(unsigned int number_of_samples) -{ - // TODO -// printf("Skip %d\n", number_of_samples); -} - void AY38910::select_register(uint8_t r) { _selected_register = r & 0xf; diff --git a/Components/AY38910/AY38910.hpp b/Components/AY38910/AY38910.hpp index 96d3724c1..82dc913af 100644 --- a/Components/AY38910/AY38910.hpp +++ b/Components/AY38910/AY38910.hpp @@ -49,7 +49,6 @@ class AY38910: public ::Outputs::Filter { // to satisfy ::Outputs::Speaker (included via ::Outputs::Filter; not for public consumption void get_samples(unsigned int number_of_samples, int16_t *target); - void skip_samples(unsigned int number_of_samples); private: int _selected_register; diff --git a/Concurrency/AsyncTaskQueue.cpp b/Concurrency/AsyncTaskQueue.cpp index 1aa544c5e..939cd016a 100644 --- a/Concurrency/AsyncTaskQueue.cpp +++ b/Concurrency/AsyncTaskQueue.cpp @@ -10,8 +10,14 @@ using namespace Concurrency; -AsyncTaskQueue::AsyncTaskQueue() : should_destruct_(false) +AsyncTaskQueue::AsyncTaskQueue() +#ifndef __APPLE__ + : should_destruct_(false) +#endif { +#ifdef __APPLE__ + serial_dispatch_queue_ = dispatch_queue_create("com.thomasharte.clocksignal.asyntaskqueue", DISPATCH_QUEUE_SERIAL); +#else thread_.reset(new std::thread([this]() { while(!should_destruct_) { @@ -39,25 +45,37 @@ AsyncTaskQueue::AsyncTaskQueue() : should_destruct_(false) } } })); +#endif } AsyncTaskQueue::~AsyncTaskQueue() { +#ifdef __APPLE__ + dispatch_release(serial_dispatch_queue_); +#else should_destruct_ = true; enqueue([](){}); thread_->join(); thread_.reset(); +#endif } void AsyncTaskQueue::enqueue(std::function function) { +#ifdef __APPLE__ + dispatch_async(serial_dispatch_queue_, ^{function();}); +#else std::lock_guard lock(queue_mutex_); pending_tasks_.push_back(function); processing_condition_.notify_all(); +#endif } void AsyncTaskQueue::flush() { +#ifdef __APPLE__ + dispatch_sync(serial_dispatch_queue_, ^{}); +#else std::shared_ptr flush_mutex(new std::mutex); std::shared_ptr flush_condition(new std::condition_variable); std::unique_lock lock(*flush_mutex); @@ -66,4 +84,5 @@ void AsyncTaskQueue::flush() flush_condition->notify_all(); }); flush_condition->wait(lock); +#endif } diff --git a/Concurrency/AsyncTaskQueue.hpp b/Concurrency/AsyncTaskQueue.hpp index 77485265a..aa53dd954 100644 --- a/Concurrency/AsyncTaskQueue.hpp +++ b/Concurrency/AsyncTaskQueue.hpp @@ -14,6 +14,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + namespace Concurrency { /*! @@ -42,12 +46,16 @@ class AsyncTaskQueue { void flush(); private: +#ifdef __APPLE__ + dispatch_queue_t serial_dispatch_queue_; +#else std::unique_ptr thread_; std::mutex queue_mutex_; std::list> pending_tasks_; std::condition_variable processing_condition_; std::atomic_bool should_destruct_; +#endif }; } From b12f2f27968c8f3300f34f80a40a1fbbd70d4cb4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 23 Oct 2016 20:32:48 -0400 Subject: [PATCH 6/8] Switched to more straightforward version of two-step loop, dealing with my mistaken dealing of when _master_divider&15 == 0 upon entry without adding an extra sanity check. Am also temporarily on non-modulo logic for tone generation, for a profiling test. --- Components/AY38910/AY38910.cpp | 41 +++++++++++++++++++++------------- Components/AY38910/AY38910.hpp | 1 + 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Components/AY38910/AY38910.cpp b/Components/AY38910/AY38910.cpp index 9e2aec75d..695d40242 100644 --- a/Components/AY38910/AY38910.cpp +++ b/Components/AY38910/AY38910.cpp @@ -12,7 +12,7 @@ using namespace GI; AY38910::AY38910() : _selected_register(0), - _tone_counters{0, 0, 0}, _tone_dividers{0, 0, 0}, + _tone_counters{0, 0, 0}, _tone_dividers{0, 0, 0}, _tone_outputs{0, 0, 0}, _noise_shift_register(0xffff), _noise_divider(0), _noise_output(0), _envelope_divider(0), _envelope_period(0), _envelope_position(0), _output_registers{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -82,14 +82,25 @@ void AY38910::set_clock_rate(double clock_rate) void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) { - int offset = _master_divider; - int c = _master_divider; - _master_divider += number_of_samples; - - for(; c < 16 && c < _master_divider; c++) target[c - offset] = _output_volume; - while(c < _master_divider) + int c = 0; + while((_master_divider&15) && c < number_of_samples) { -#define step_channel(c) _tone_counters[c] = (_tone_counters[c] + 1) % (2 * (_tone_dividers[c] + 1)) + target[c] = _output_volume; + _master_divider++; + c++; + } + + while(c < number_of_samples) + { +#define step_channel(c) \ + if(_tone_counters[c]) _tone_counters[c]--;\ + else\ + {\ + _tone_outputs[c] ^= 1;\ + _tone_counters[c] = _tone_dividers[c];\ + } + +// _tone_counters[c] = (_tone_counters[c] + 1) % (2 * (_tone_dividers[c] + 1)) // update the tone channels step_channel(0); @@ -121,14 +132,13 @@ void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) evaluate_output_volume(); - for(int ic = 0; ic < 16 && c < _master_divider; ic++) + for(int ic = 0; ic < 16 && c < number_of_samples; ic++) { - target[c - offset] = _output_volume; + target[c] = _output_volume; c++; + _master_divider++; } } - - _master_divider &= 15; } void AY38910::evaluate_output_volume() @@ -140,7 +150,7 @@ void AY38910::evaluate_output_volume() // 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_counters[c] / (_tone_dividers[c] + 1))) | ((((_output_registers[7] >> nb)&1)^1) & _noise_output)) ^ 1 + (((((_output_registers[7] >> tb)&1)^1) & _tone_outputs[c]) | ((((_output_registers[7] >> nb)&1)^1) & _noise_output)) ^ 1 int channel_levels[3] = { level(0, 0, 3), @@ -188,12 +198,13 @@ void AY38910::set_register_value(uint8_t value) { int channel = selected_register >> 1; - _tone_counters[channel] /= _tone_dividers[channel] + 1; +// _tone_counters[channel] /= _tone_dividers[channel] + 1; if(selected_register & 1) _tone_dividers[channel] = (_tone_dividers[channel] & 0xff) | (uint16_t)((value&0xf) << 8); else _tone_dividers[channel] = (_tone_dividers[channel] & ~0xff) | value; - _tone_counters[channel] *= _tone_dividers[channel] + 1; +// _tone_counters[channel] *= _tone_dividers[channel] + 1; + _tone_counters[channel] = _tone_dividers[channel]; } break; diff --git a/Components/AY38910/AY38910.hpp b/Components/AY38910/AY38910.hpp index 82dc913af..ad95738f4 100644 --- a/Components/AY38910/AY38910.hpp +++ b/Components/AY38910/AY38910.hpp @@ -56,6 +56,7 @@ class AY38910: public ::Outputs::Filter { int _tone_dividers[3]; int _tone_counters[3]; + int _tone_outputs[3]; int _volumes[16]; From 7c33c34b0cb7e6049f8aa66fadef2bd0ca93baf2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 23 Oct 2016 20:33:59 -0400 Subject: [PATCH 7/8] Have withdrawn attempt to be clever with client notification here, as it was having no effect in the current environment, making it hard to build up any confidence. --- OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m index a99fdf3b5..1153e0686 100644 --- a/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m +++ b/OSBindings/Mac/Clock Signal/Audio/CSAudioQueue.m @@ -14,22 +14,13 @@ @implementation CSAudioQueue { AudioQueueRef _audioQueue; - size_t _queuedSamples; - BOOL _hasHad256; } #pragma mark - AudioQueue callbacks - (void)audioQueue:(AudioQueueRef)theAudioQueue didCallbackWithBuffer:(AudioQueueBufferRef)buffer { - size_t samplesInBuffer = (size_t)(buffer->mAudioDataByteSize / sizeof(int16_t)); - if(_queuedSamples >= 128 && _queuedSamples - samplesInBuffer < 128 && _hasHad256) - { - _hasHad256 = NO; - [self.delegate audioQueueIsRunningDry:self]; - } - _queuedSamples -= samplesInBuffer; - + [self.delegate audioQueueIsRunningDry:self]; AudioQueueFreeBuffer(_audioQueue, buffer); } @@ -106,8 +97,6 @@ static void audioOutputCallback( { AudioQueueBufferRef newBuffer; size_t bufferBytes = lengthInSamples * sizeof(int16_t); - _queuedSamples += lengthInSamples; - _hasHad256 |= (_queuedSamples >= 256); AudioQueueAllocateBuffer(_audioQueue, (UInt32)bufferBytes, &newBuffer); memcpy(newBuffer->mAudioData, buffer, bufferBytes); From fd823dc222624a8caf4122f3cccf3051f04335fb Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 23 Oct 2016 20:42:49 -0400 Subject: [PATCH 8/8] Settled on terminology. --- Components/AY38910/AY38910.cpp | 24 ++++++++++-------------- Components/AY38910/AY38910.hpp | 16 ++++++++-------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/Components/AY38910/AY38910.cpp b/Components/AY38910/AY38910.cpp index 695d40242..c0db5eebb 100644 --- a/Components/AY38910/AY38910.cpp +++ b/Components/AY38910/AY38910.cpp @@ -12,8 +12,8 @@ using namespace GI; AY38910::AY38910() : _selected_register(0), - _tone_counters{0, 0, 0}, _tone_dividers{0, 0, 0}, _tone_outputs{0, 0, 0}, - _noise_shift_register(0xffff), _noise_divider(0), _noise_output(0), + _tone_counters{0, 0, 0}, _tone_periods{0, 0, 0}, _tone_outputs{0, 0, 0}, + _noise_shift_register(0xffff), _noise_period(0), _noise_counter(0), _noise_output(0), _envelope_divider(0), _envelope_period(0), _envelope_position(0), _output_registers{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} { @@ -97,11 +97,9 @@ void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) else\ {\ _tone_outputs[c] ^= 1;\ - _tone_counters[c] = _tone_dividers[c];\ + _tone_counters[c] = _tone_periods[c];\ } -// _tone_counters[c] = (_tone_counters[c] + 1) % (2 * (_tone_dividers[c] + 1)) - // update the tone channels step_channel(0); step_channel(1); @@ -111,10 +109,10 @@ void AY38910::get_samples(unsigned int number_of_samples, int16_t *target) // ... the noise generator. This recomputes the new bit repeatedly but harmlessly, only shifting // it into the official 17 upon divider underflow. - if(_noise_divider) _noise_divider--; + if(_noise_counter) _noise_counter--; else { - _noise_divider = _output_registers[6]; + _noise_counter = _noise_period; _noise_output ^= _noise_shift_register&1; _noise_shift_register |= ((_noise_shift_register ^ (_noise_shift_register >> 3))&1) << 17; _noise_shift_register >>= 1; @@ -198,19 +196,17 @@ void AY38910::set_register_value(uint8_t value) { int channel = selected_register >> 1; -// _tone_counters[channel] /= _tone_dividers[channel] + 1; if(selected_register & 1) - _tone_dividers[channel] = (_tone_dividers[channel] & 0xff) | (uint16_t)((value&0xf) << 8); + _tone_periods[channel] = (_tone_periods[channel] & 0xff) | (uint16_t)((value&0xf) << 8); else - _tone_dividers[channel] = (_tone_dividers[channel] & ~0xff) | value; -// _tone_counters[channel] *= _tone_dividers[channel] + 1; - _tone_counters[channel] = _tone_dividers[channel]; + _tone_periods[channel] = (_tone_periods[channel] & ~0xff) | value; + _tone_counters[channel] = _tone_periods[channel]; } break; case 6: - masked_value &= 0x1f; - _noise_divider = masked_value; + _noise_period = value & 0x1f; + _noise_counter = _noise_period; break; case 11: diff --git a/Components/AY38910/AY38910.hpp b/Components/AY38910/AY38910.hpp index ad95738f4..11f0045c6 100644 --- a/Components/AY38910/AY38910.hpp +++ b/Components/AY38910/AY38910.hpp @@ -54,25 +54,25 @@ class AY38910: public ::Outputs::Filter { int _selected_register; uint8_t _registers[16], _output_registers[16]; - int _tone_dividers[3]; + int _master_divider; + + int _tone_periods[3]; int _tone_counters[3]; int _tone_outputs[3]; - int _volumes[16]; - - int _master_divider; - - int _noise_divider; + int _noise_period; + int _noise_counter; int _noise_shift_register; int _noise_output; int _envelope_period; int _envelope_divider; - int _envelope_position; int _envelope_shapes[16][32]; int _envelope_overflow_masks[16]; + int _volumes[16]; + enum ControlState { Inactive, LatchAddress, @@ -87,7 +87,7 @@ class AY38910: public ::Outputs::Filter { uint8_t _data_input, _data_output; int16_t _output_volume; - void evaluate_output_volume(); + inline void evaluate_output_volume(); }; };