diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 145f4d8c3..a1555149e 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -31,8 +31,6 @@ namespace { static const unsigned int real_time_clock_interrupt_1 = 16704; static const unsigned int real_time_clock_interrupt_2 = 56704; - - static const unsigned int clock_rate_audio_divider = 8; } #define graphics_line(v) ((((v) >> 7) - first_graphics_line + field_divider_line) % field_divider_line) @@ -76,7 +74,7 @@ void Machine::setup_output(float aspect_ratio) // The maximum output frequency is 62500Hz and all other permitted output frequencies are integral divisions of that; // however setting the speaker on or off can happen on any 2Mhz cycle, and probably (?) takes effect immediately. So // run the speaker at a 2000000Hz input rate, at least for the time being. - _speaker->set_input_rate(2000000 / clock_rate_audio_divider); + _speaker->set_input_rate(2000000 / Speaker::clock_rate_divider); } void Machine::close_output() @@ -583,8 +581,8 @@ inline void Machine::update_audio() { unsigned int difference = _frameCycles - _audioOutputPosition; _audioOutputPosition = _frameCycles; - _speaker->run_for_cycles(difference / clock_rate_audio_divider); - _audioOutputPositionError = difference % clock_rate_audio_divider; + _speaker->run_for_cycles(difference / Speaker::clock_rate_divider); + _audioOutputPositionError = difference % Speaker::clock_rate_divider; } inline void Machine::start_pixel_line() @@ -931,45 +929,3 @@ void Machine::set_key_state(uint16_t key, bool isPressed) _key_states[key >> 4] &= ~(key&0xf); } } - -/* - Speaker -*/ - -void Speaker::get_samples(unsigned int number_of_samples, int16_t *target) -{ - if(_is_enabled) - { - while(number_of_samples--) - { - *target = (int16_t)((_counter / (_divider+1)) * 8192); - target++; - _counter = (_counter + 1) % ((_divider+1) * 2); - } - } - else - { - memset(target, 0, sizeof(int16_t) * number_of_samples); - } -} - -void Speaker::skip_samples(unsigned int number_of_samples) -{ - _counter = (_counter + number_of_samples) % ((_divider+1) * 2); -} - -void Speaker::set_divider(uint8_t divider) -{ - enqueue([=]() { - _divider = divider * 32 / clock_rate_audio_divider; - }); -} - -void Speaker::set_is_enabled(bool is_enabled) -{ - enqueue([=]() { - _is_enabled = is_enabled; - _counter = 0; - }); -} - diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp index 31556a037..8de9128ff 100644 --- a/Machines/Electron/Electron.hpp +++ b/Machines/Electron/Electron.hpp @@ -16,6 +16,7 @@ #include "../CRTMachine.hpp" #include "../Typer.hpp" #include "Plus3.hpp" +#include "Speaker.hpp" #include "Tape.hpp" #include "Interrupts.hpp" @@ -58,21 +59,6 @@ enum Key: uint16_t { TerminateSequence = 0xffff, NotMapped = 0xfffe, }; -class Speaker: public ::Outputs::Filter { - public: - void set_divider(uint8_t divider); - - void set_is_enabled(bool is_enabled); - - void get_samples(unsigned int number_of_samples, int16_t *target); - void skip_samples(unsigned int number_of_samples); - - private: - unsigned int _counter; - unsigned int _divider; - bool _is_enabled; -}; - /*! @abstract Represents an Acorn Electron. diff --git a/Machines/Electron/Speaker.cpp b/Machines/Electron/Speaker.cpp new file mode 100644 index 000000000..05442f564 --- /dev/null +++ b/Machines/Electron/Speaker.cpp @@ -0,0 +1,48 @@ +// +// Speaker.cpp +// Clock Signal +// +// Created by Thomas Harte on 03/12/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "Speaker.hpp" + +using namespace Electron; + +void Speaker::get_samples(unsigned int number_of_samples, int16_t *target) +{ + if(is_enabled_) + { + while(number_of_samples--) + { + *target = (int16_t)((counter_ / (divider_+1)) * 8192); + target++; + counter_ = (counter_ + 1) % ((divider_+1) * 2); + } + } + else + { + memset(target, 0, sizeof(int16_t) * number_of_samples); + } +} + +void Speaker::skip_samples(unsigned int number_of_samples) +{ + counter_ = (counter_ + number_of_samples) % ((divider_+1) * 2); +} + +void Speaker::set_divider(uint8_t divider) +{ + enqueue([=]() { + divider_ = divider * 32 / clock_rate_divider; + }); +} + +void Speaker::set_is_enabled(bool is_enabled) +{ + enqueue([=]() { + is_enabled_ = is_enabled; + counter_ = 0; + }); +} diff --git a/Machines/Electron/Speaker.hpp b/Machines/Electron/Speaker.hpp new file mode 100644 index 000000000..f61052371 --- /dev/null +++ b/Machines/Electron/Speaker.hpp @@ -0,0 +1,35 @@ +// +// Speaker.hpp +// Clock Signal +// +// Created by Thomas Harte on 03/12/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef Electron_Speaker_hpp +#define Electron_Speaker_hpp + +#include "../../Outputs/Speaker.hpp" + +namespace Electron { + +class Speaker: public ::Outputs::Filter { + public: + void set_divider(uint8_t divider); + + void set_is_enabled(bool is_enabled); + + void get_samples(unsigned int number_of_samples, int16_t *target); + void skip_samples(unsigned int number_of_samples); + + static const unsigned int clock_rate_divider = 8; + + private: + unsigned int counter_; + unsigned int divider_; + bool is_enabled_; +}; + +} + +#endif /* Speaker_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index b9cb4ff94..01a09b75b 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -384,6 +384,7 @@ 4BD69F941D98760000243FE1 /* AcornADF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD69F921D98760000243FE1 /* AcornADF.cpp */; }; 4BE77A2E1D84ADFB00BC3827 /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BE77A2C1D84ADFB00BC3827 /* File.cpp */; }; 4BEA525E1DF33323007E74F2 /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA525D1DF33323007E74F2 /* Tape.cpp */; }; + 4BEA52631DF339D7007E74F2 /* Speaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA52611DF339D7007E74F2 /* Speaker.cpp */; }; 4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6A1D72496600532C7B /* Cartridge.cpp */; }; 4BEE0A701D72496600532C7B /* PRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6D1D72496600532C7B /* PRG.cpp */; }; 4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */; }; @@ -896,6 +897,8 @@ 4BEA525D1DF33323007E74F2 /* Tape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Tape.cpp; path = Electron/Tape.cpp; sourceTree = ""; }; 4BEA525F1DF333D8007E74F2 /* Tape.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Tape.hpp; path = Electron/Tape.hpp; sourceTree = ""; }; 4BEA52601DF3343A007E74F2 /* Interrupts.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Interrupts.hpp; path = Electron/Interrupts.hpp; sourceTree = ""; }; + 4BEA52611DF339D7007E74F2 /* Speaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Speaker.cpp; path = Electron/Speaker.cpp; sourceTree = ""; }; + 4BEA52621DF339D7007E74F2 /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Speaker.hpp; path = Electron/Speaker.hpp; sourceTree = ""; }; 4BEE0A6A1D72496600532C7B /* Cartridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cartridge.cpp; sourceTree = ""; }; 4BEE0A6B1D72496600532C7B /* Cartridge.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = ""; }; 4BEE0A6D1D72496600532C7B /* PRG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PRG.cpp; sourceTree = ""; }; @@ -1057,11 +1060,13 @@ children = ( 4B2E2D9B1C3A070400138695 /* Electron.cpp */, 4B30512E1D98ACC600B4FED8 /* Plus3.cpp */, + 4BEA52611DF339D7007E74F2 /* Speaker.cpp */, 4BEA525D1DF33323007E74F2 /* Tape.cpp */, 4BC8A62B1DCE60E000DAC693 /* Typer.cpp */, 4B2E2D9C1C3A070400138695 /* Electron.hpp */, 4BEA52601DF3343A007E74F2 /* Interrupts.hpp */, 4B30512F1D98ACC600B4FED8 /* Plus3.hpp */, + 4BEA52621DF339D7007E74F2 /* Speaker.hpp */, 4BEA525F1DF333D8007E74F2 /* Tape.hpp */, ); name = Electron; @@ -2343,6 +2348,7 @@ 4B2A332F1DB86869002876E3 /* OricOptionsPanel.swift in Sources */, 4B2A53A11D117D36003C6002 /* CSAtari2600.mm in Sources */, 4BF829661D8F732B001BAE39 /* Disk.cpp in Sources */, + 4BEA52631DF339D7007E74F2 /* Speaker.cpp in Sources */, 4BC5E4921D7ED365008CF980 /* StaticAnalyser.cpp in Sources */, 4BC830D11D6E7C690000A26F /* Tape.cpp in Sources */, 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */,