diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 72b4c2bca..a0027f35d 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -791,133 +791,3 @@ void Machine::synchronise() update_audio(); } -Atari2600::Speaker::Speaker() -{ - _poly4_counter[0] = _poly4_counter[1] = 0x00f; - _poly5_counter[0] = _poly5_counter[1] = 0x01f; - _poly9_counter[0] = _poly9_counter[1] = 0x1ff; -} - -Atari2600::Speaker::~Speaker() -{ -} - -void Atari2600::Speaker::set_volume(int channel, uint8_t volume) -{ - enqueue([=]() { - _volume[channel] = volume & 0xf; - }); -} - -void Atari2600::Speaker::set_divider(int channel, uint8_t divider) -{ - enqueue([=]() { - _divider[channel] = divider & 0x1f; - _divider_counter[channel] = 0; - }); -} - -void Atari2600::Speaker::set_control(int channel, uint8_t control) -{ - enqueue([=]() { - _control[channel] = control & 0xf; - }); -} - -#define advance_poly4(c) _poly4_counter[channel] = (_poly4_counter[channel] >> 1) | (((_poly4_counter[channel] << 3) ^ (_poly4_counter[channel] << 2))&0x008) -#define advance_poly5(c) _poly5_counter[channel] = (_poly5_counter[channel] >> 1) | (((_poly5_counter[channel] << 4) ^ (_poly5_counter[channel] << 2))&0x010) -#define advance_poly9(c) _poly9_counter[channel] = (_poly9_counter[channel] >> 1) | (((_poly9_counter[channel] << 4) ^ (_poly9_counter[channel] << 8))&0x100) - -void Atari2600::Speaker::get_samples(unsigned int number_of_samples, int16_t *target) -{ - for(unsigned int c = 0; c < number_of_samples; c++) - { - target[c] = 0; - for(int channel = 0; channel < 2; channel++) - { - _divider_counter[channel] ++; - int level = 0; - switch(_control[channel]) - { - case 0x0: case 0xb: // constant 1 - level = 1; - break; - - case 0x4: case 0x5: // div2 tone - level = (_divider_counter[channel] / (_divider[channel]+1))&1; - break; - - case 0xc: case 0xd: // div6 tone - level = (_divider_counter[channel] / ((_divider[channel]+1)*3))&1; - break; - - case 0x6: case 0xa: // div31 tone - level = (_divider_counter[channel] / (_divider[channel]+1))%30 <= 18; - break; - - case 0xe: // div93 tone - level = (_divider_counter[channel] / ((_divider[channel]+1)*3))%30 <= 18; - break; - - case 0x1: // 4-bit poly - level = _poly4_counter[channel]&1; - if(_divider_counter[channel] == _divider[channel]+1) - { - _divider_counter[channel] = 0; - advance_poly4(channel); - } - break; - - case 0x2: // 4-bit poly div31 - level = _poly4_counter[channel]&1; - if(_divider_counter[channel]%(30*(_divider[channel]+1)) == 18) - { - advance_poly4(channel); - } - break; - - case 0x3: // 5/4-bit poly - level = _output_state[channel]; - if(_divider_counter[channel] == _divider[channel]+1) - { - if(_poly5_counter[channel]&1) - { - _output_state[channel] = _poly4_counter[channel]&1; - advance_poly4(channel); - } - advance_poly5(channel); - } - break; - - case 0x7: case 0x9: // 5-bit poly - level = _poly5_counter[channel]&1; - if(_divider_counter[channel] == _divider[channel]+1) - { - _divider_counter[channel] = 0; - advance_poly5(channel); - } - break; - - case 0xf: // 5-bit poly div6 - level = _poly5_counter[channel]&1; - if(_divider_counter[channel] == (_divider[channel]+1)*3) - { - _divider_counter[channel] = 0; - advance_poly5(channel); - } - break; - - case 0x8: // 9-bit poly - level = _poly9_counter[channel]&1; - if(_divider_counter[channel] == _divider[channel]+1) - { - _divider_counter[channel] = 0; - advance_poly9(channel); - } - break; - } - - target[c] += _volume[channel] * 1024 * level; - } - } -} diff --git a/Machines/Atari2600/Atari2600.hpp b/Machines/Atari2600/Atari2600.hpp index daeab499a..c0a883e60 100644 --- a/Machines/Atari2600/Atari2600.hpp +++ b/Machines/Atari2600/Atari2600.hpp @@ -14,6 +14,7 @@ #include "../../Processors/6502/CPU6502.hpp" #include "../../Components/6532/6532.hpp" #include "../CRTMachine.hpp" +#include "Speaker.hpp" #include "../ConfigurationTarget.hpp" #include "Atari2600Inputs.h" @@ -23,56 +24,28 @@ namespace Atari2600 { const unsigned int number_of_upcoming_events = 6; const unsigned int number_of_recorded_counters = 7; -class Speaker: public ::Outputs::Filter { - public: - Speaker(); - ~Speaker(); - - void set_volume(int channel, uint8_t volume); - void set_divider(int channel, uint8_t divider); - void set_control(int channel, uint8_t control); - - void get_samples(unsigned int number_of_samples, int16_t *target); - - private: - uint8_t _volume[2]; - uint8_t _divider[2]; - uint8_t _control[2]; - - int _poly4_counter[2]; - int _poly5_counter[2]; - int _poly9_counter[2]; - int _output_state[2]; - - int _divider_counter[2]; - - int _pattern_periods[16]; - int _patterns[16][512]; -}; - class PIA: public MOS::MOS6532 { public: inline uint8_t get_port_input(int port) { - return _portValues[port]; + return port_values_[port]; } inline void update_port_input(int port, uint8_t mask, bool set) { - if(set) _portValues[port] &= ~mask; else _portValues[port] |= mask; + if(set) port_values_[port] &= ~mask; else port_values_[port] |= mask; set_port_did_change(port); } PIA() : - _portValues{0xff, 0xff} + port_values_{0xff, 0xff} {} private: - uint8_t _portValues[2]; + uint8_t port_values_[2]; }; - class Machine: public CPU6502::Processor, public CRTMachine::Machine, diff --git a/Machines/Atari2600/Speaker.cpp b/Machines/Atari2600/Speaker.cpp new file mode 100644 index 000000000..a304fa29b --- /dev/null +++ b/Machines/Atari2600/Speaker.cpp @@ -0,0 +1,137 @@ +// +// Speaker.cpp +// Clock Signal +// +// Created by Thomas Harte on 03/12/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "Speaker.hpp" + +using namespace Atari2600; + +Atari2600::Speaker::Speaker() : + poly4_counter_{0x00f, 0x00f}, + poly5_counter_{0x01f, 0x01f}, + poly9_counter_{0x1ff, 0x1ff} +{} + +void Atari2600::Speaker::set_volume(int channel, uint8_t volume) +{ + enqueue([=]() { + volume_[channel] = volume & 0xf; + }); +} + +void Atari2600::Speaker::set_divider(int channel, uint8_t divider) +{ + enqueue([=]() { + divider_[channel] = divider & 0x1f; + divider_counter_[channel] = 0; + }); +} + +void Atari2600::Speaker::set_control(int channel, uint8_t control) +{ + enqueue([=]() { + control_[channel] = control & 0xf; + }); +} + +#define advance_poly4(c) poly4_counter_[channel] = (poly4_counter_[channel] >> 1) | (((poly4_counter_[channel] << 3) ^ (poly4_counter_[channel] << 2))&0x008) +#define advance_poly5(c) poly5_counter_[channel] = (poly5_counter_[channel] >> 1) | (((poly5_counter_[channel] << 4) ^ (poly5_counter_[channel] << 2))&0x010) +#define advance_poly9(c) poly9_counter_[channel] = (poly9_counter_[channel] >> 1) | (((poly9_counter_[channel] << 4) ^ (poly9_counter_[channel] << 8))&0x100) + +void Atari2600::Speaker::get_samples(unsigned int number_of_samples, int16_t *target) +{ + for(unsigned int c = 0; c < number_of_samples; c++) + { + target[c] = 0; + for(int channel = 0; channel < 2; channel++) + { + divider_counter_[channel] ++; + int level = 0; + switch(control_[channel]) + { + case 0x0: case 0xb: // constant 1 + level = 1; + break; + + case 0x4: case 0x5: // div2 tone + level = (divider_counter_[channel] / (divider_[channel]+1))&1; + break; + + case 0xc: case 0xd: // div6 tone + level = (divider_counter_[channel] / ((divider_[channel]+1)*3))&1; + break; + + case 0x6: case 0xa: // div31 tone + level = (divider_counter_[channel] / (divider_[channel]+1))%30 <= 18; + break; + + case 0xe: // div93 tone + level = (divider_counter_[channel] / ((divider_[channel]+1)*3))%30 <= 18; + break; + + case 0x1: // 4-bit poly + level = poly4_counter_[channel]&1; + if(divider_counter_[channel] == divider_[channel]+1) + { + divider_counter_[channel] = 0; + advance_poly4(channel); + } + break; + + case 0x2: // 4-bit poly div31 + level = poly4_counter_[channel]&1; + if(divider_counter_[channel]%(30*(divider_[channel]+1)) == 18) + { + advance_poly4(channel); + } + break; + + case 0x3: // 5/4-bit poly + level = output_state_[channel]; + if(divider_counter_[channel] == divider_[channel]+1) + { + if(poly5_counter_[channel]&1) + { + output_state_[channel] = poly4_counter_[channel]&1; + advance_poly4(channel); + } + advance_poly5(channel); + } + break; + + case 0x7: case 0x9: // 5-bit poly + level = poly5_counter_[channel]&1; + if(divider_counter_[channel] == divider_[channel]+1) + { + divider_counter_[channel] = 0; + advance_poly5(channel); + } + break; + + case 0xf: // 5-bit poly div6 + level = poly5_counter_[channel]&1; + if(divider_counter_[channel] == (divider_[channel]+1)*3) + { + divider_counter_[channel] = 0; + advance_poly5(channel); + } + break; + + case 0x8: // 9-bit poly + level = poly9_counter_[channel]&1; + if(divider_counter_[channel] == divider_[channel]+1) + { + divider_counter_[channel] = 0; + advance_poly9(channel); + } + break; + } + + target[c] += volume_[channel] * 1024 * level; + } + } +} diff --git a/Machines/Atari2600/Speaker.hpp b/Machines/Atari2600/Speaker.hpp new file mode 100644 index 000000000..b5bf42488 --- /dev/null +++ b/Machines/Atari2600/Speaker.hpp @@ -0,0 +1,41 @@ +// +// Speaker.hpp +// Clock Signal +// +// Created by Thomas Harte on 03/12/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef Atari2600_Speaker_hpp +#define Atari2600_Speaker_hpp + +#include "../../Outputs/Speaker.hpp" + +namespace Atari2600 { + +class Speaker: public ::Outputs::Filter { + public: + Speaker(); + + void set_volume(int channel, uint8_t volume); + void set_divider(int channel, uint8_t divider); + void set_control(int channel, uint8_t control); + + void get_samples(unsigned int number_of_samples, int16_t *target); + + private: + uint8_t volume_[2]; + uint8_t divider_[2]; + uint8_t control_[2]; + + int poly4_counter_[2]; + int poly5_counter_[2]; + int poly9_counter_[2]; + int output_state_[2]; + + int divider_counter_[2]; +}; + +} + +#endif /* Speaker_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 01a09b75b..acc5d7604 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -385,6 +385,7 @@ 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 */; }; + 4BEA52661DF3472B007E74F2 /* Speaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA52641DF3472B007E74F2 /* 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 */; }; @@ -899,6 +900,8 @@ 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 = ""; }; + 4BEA52641DF3472B007E74F2 /* Speaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Speaker.cpp; sourceTree = ""; }; + 4BEA52651DF3472B007E74F2 /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 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 = ""; }; @@ -1049,8 +1052,10 @@ isa = PBXGroup; children = ( 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */, - 4B2E2D981C3A06EC00138695 /* Atari2600.hpp */, + 4BEA52641DF3472B007E74F2 /* Speaker.cpp */, 4B2E2D991C3A06EC00138695 /* Atari2600Inputs.h */, + 4B2E2D981C3A06EC00138695 /* Atari2600.hpp */, + 4BEA52651DF3472B007E74F2 /* Speaker.hpp */, ); path = Atari2600; sourceTree = ""; @@ -2392,6 +2397,7 @@ 4B30512D1D989E2200B4FED8 /* Drive.cpp in Sources */, 4BCA6CC81D9DD9F000C2D7B2 /* CommodoreROM.cpp in Sources */, 4BA22B071D8817CE0008C640 /* Disk.cpp in Sources */, + 4BEA52661DF3472B007E74F2 /* Speaker.cpp in Sources */, 4BC3B7521CD1956900F86E85 /* OutputShader.cpp in Sources */, 4B4C83701D4F623200CD541F /* D64.cpp in Sources */, 4B5073071DDD3B9400C48FBD /* ArrayBuilder.cpp in Sources */,