From 4cd0aa34165e500ce43cce0683b9144e90f4f3b1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 15 Mar 2016 23:37:35 -0400 Subject: [PATCH] Completed FIR filter based audio output. --- Machines/Electron/Electron.cpp | 11 ++-- .../Clock Signal.xcodeproj/project.pbxproj | 4 ++ Outputs/Speaker.hpp | 51 +++++++++++-------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 3754011df..a342b0c2a 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -786,15 +786,12 @@ void Machine::set_key_state(Key key, bool isPressed) void Speaker::get_samples(unsigned int number_of_samples, int16_t *target) { - if(!_is_enabled) + while(number_of_samples--) { - *target = 0; + *target = _is_enabled ? _output_level : 0; + target++; + skip_samples(1); } - else - { - *target = _output_level; - } - skip_samples(number_of_samples); } void Speaker::skip_samples(unsigned int number_of_samples) diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 6ea4d6d7a..141821bc2 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -309,6 +309,7 @@ 4BBF99171C8FBA6F0075DAFB /* Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF99101C8FBA6F0075DAFB /* Shader.cpp */; }; 4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF99121C8FBA6F0075DAFB /* TextureTarget.cpp */; }; 4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */; }; + 4BC76E6B1C98F43700E6EF73 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */; }; 4BCB70B41C947DDC005B1712 /* plus1.rom in Resources */ = {isa = PBXBuildFile; fileRef = 4BCB70B31C947DDC005B1712 /* plus1.rom */; }; 4BE5F85E1C3E1C2500C43F01 /* basic.rom in Resources */ = {isa = PBXBuildFile; fileRef = 4BE5F85C1C3E1C2500C43F01 /* basic.rom */; }; 4BE5F85F1C3E1C2500C43F01 /* os.rom in Resources */ = {isa = PBXBuildFile; fileRef = 4BE5F85D1C3E1C2500C43F01 /* os.rom */; }; @@ -669,6 +670,7 @@ 4BBF99191C8FC2750075DAFB /* CRTTypes.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CRTTypes.hpp; sourceTree = ""; }; 4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FIRFilter.cpp; sourceTree = ""; }; 4BC76E681C98E31700E6EF73 /* FIRFilter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FIRFilter.hpp; sourceTree = ""; }; + 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 4BCB70B31C947DDC005B1712 /* plus1.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = plus1.rom; sourceTree = ""; }; 4BE5F85C1C3E1C2500C43F01 /* basic.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = basic.rom; sourceTree = ""; }; 4BE5F85D1C3E1C2500C43F01 /* os.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = os.rom; sourceTree = ""; }; @@ -679,6 +681,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 4BC76E6B1C98F43700E6EF73 /* Accelerate.framework in Frameworks */, 4B69FB461C4D950F00B5F0AA /* libz.tbd in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1115,6 +1118,7 @@ 4BB73E951B587A5100552FC2 = { isa = PBXGroup; children = ( + 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */, 4BB73EA01B587A5100552FC2 /* Clock Signal */, 4BB73EB51B587A5100552FC2 /* Clock SignalTests */, 4BB73EC01B587A5100552FC2 /* Clock SignalUITests */, diff --git a/Outputs/Speaker.hpp b/Outputs/Speaker.hpp index 9f57a9cc3..98b2d00c6 100644 --- a/Outputs/Speaker.hpp +++ b/Outputs/Speaker.hpp @@ -76,39 +76,45 @@ template class Filter: public Speaker { { if(_coefficients_are_dirty) update_filter_coefficients(); - // point sample for now, as a temporary measure - input_cycles += _input_cycles_carry; - while(input_cycles > 0) + // TODO: what if output rate is greater than input rate? + + // fill up as much of the input buffer as possible + while(input_cycles) { - // get a sample for the current location - static_cast(this)->get_samples(1, &_buffer_in_progress.get()[_buffer_in_progress_pointer]); - _buffer_in_progress_pointer++; + unsigned int cycles_to_read = (unsigned int)std::min(input_cycles, _number_of_taps - _input_buffer_depth); + static_cast(this)->get_samples(cycles_to_read, &_input_buffer.get()[_input_buffer_depth]); + input_cycles -= cycles_to_read; + _input_buffer_depth += cycles_to_read; - // announce to delegate if full - if(_buffer_in_progress_pointer == _buffer_size) + if(_input_buffer_depth == _number_of_taps) { - _buffer_in_progress_pointer = 0; - if(_delegate) + _buffer_in_progress.get()[_buffer_in_progress_pointer] = _filter->apply(_input_buffer.get()); + _buffer_in_progress_pointer++; + + // announce to delegate if full + if(_buffer_in_progress_pointer == _buffer_size) { - _delegate->speaker_did_complete_samples(this, _buffer_in_progress.get(), _buffer_size); + _buffer_in_progress_pointer = 0; + if(_delegate) + { + _delegate->speaker_did_complete_samples(this, _buffer_in_progress.get(), _buffer_size); + } } + + uint64_t steps = _stepper->step(); + int16_t *input_buffer = _input_buffer.get(); + memmove(input_buffer, &input_buffer[steps], sizeof(int16_t) * ((size_t)_number_of_taps - (size_t)steps)); + _input_buffer_depth -= steps; } - - // determine how many source samples to step - uint64_t steps = _stepper->step(); - if(steps > 1) - static_cast(this)->skip_samples((unsigned int)(steps-1)); - input_cycles -= steps; } - _input_cycles_carry = input_cycles; } - Filter() {} // _periodic_cycles(0), _periodic_start(0) - private: std::unique_ptr _stepper; std::unique_ptr _filter; - int _input_cycles_carry; + + std::unique_ptr _input_buffer; + int _input_buffer_depth; void update_filter_coefficients() { @@ -117,6 +123,9 @@ template class Filter: public Speaker { _stepper = std::unique_ptr(new SignalProcessing::Stepper((uint64_t)_input_cycles_per_second, (uint64_t)_output_cycles_per_second)); _filter = std::unique_ptr(new SignalProcessing::FIRFilter((unsigned int)_number_of_taps, (unsigned int)_input_cycles_per_second, 0.0, (float)_output_cycles_per_second / 2.0f, SignalProcessing::FIRFilter::DefaultAttenuation)); + + _input_buffer = std::unique_ptr(new int16_t[_number_of_taps]); + _input_buffer_depth = 0; } };