1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-04 18:29:40 +00:00

Merge pull request #47 from TomHarte/PALAudioFrequency

Corrects Vic audio output (i) in PAL mode; and (ii) generally as concerns all but the highest-frequency channel
This commit is contained in:
Thomas Harte 2016-08-21 20:45:09 -04:00 committed by GitHub
commit f937e08c91
4 changed files with 47 additions and 9 deletions

View File

@ -95,9 +95,14 @@ static uint8_t noise_pattern[] = {
0xf0, 0xe1, 0xe0, 0x78, 0x70, 0x38, 0x3c, 0x3e, 0x1e, 0x3c, 0x1e, 0x1c, 0x70, 0x3c, 0x38, 0x3f,
};
#define shift(r) _shift_registers[r] = (_shift_registers[r] << 1) | (((_shift_registers[r]^0x80)&_control_registers[r]) >> 7);
#define increment(r) _shift_registers[r] = (_shift_registers[r]+1)%8191;
#define update(r, m, up) _counters[r]++; if((_counters[r] >> m) == 0x7f) { up(r); _counters[r] = _control_registers[r]&0x7f; }
#define shift(r) _shift_registers[r] = (_shift_registers[r] << 1) | (((_shift_registers[r]^0x80)&_control_registers[r]) >> 7)
#define increment(r) _shift_registers[r] = (_shift_registers[r]+1)%8191
#define update(r, m, up) _counters[r]++; if((_counters[r] >> m) == 0x80) { up(r); _counters[r] = (unsigned int)(_control_registers[r]&0x7f) << m; }
// Note on slightly askew test: as far as I can make out, if the value in the register is 0x7f then what's supposed to happen
// is that the 0x7f is loaded, on the next clocked cycle the Vic spots a 0x7f, pumps the output, reloads, etc. No increment
// ever occurs. It's conditional. I don't really want two conditionals if I can avoid it so I'm incrementing regardless and
// testing against 0x80. The effect should be the same: loading with 0x7f means an output update every cycle, loading with 0x7e
// means every second cycle, etc.
void Speaker::get_samples(unsigned int number_of_samples, int16_t *target)
{

View File

@ -68,7 +68,11 @@ template <class T> class MOS6560 {
// show only the centre
_crt->set_visible_area(_crt->get_rect_for_area(16, 237, 11*4, 55*4, 4.0f / 3.0f));
_speaker->set_input_rate(255681.75); // assuming NTSC; clock rate / 4
}
void set_clock_rate(double clock_rate)
{
_speaker->set_input_rate((float)(clock_rate / 4.0));
}
std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _crt; }

View File

@ -181,11 +181,19 @@ void Machine::set_region(Commodore::Vic20::Region region)
{
case PAL:
set_clock_rate(1108404);
if(_mos6560) _mos6560->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::PAL);
if(_mos6560)
{
_mos6560->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::PAL);
_mos6560->set_clock_rate(1108404);
}
break;
case NTSC:
set_clock_rate(1022727);
if(_mos6560) _mos6560->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::NTSC);
if(_mos6560)
{
_mos6560->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::NTSC);
_mos6560->set_clock_rate(1022727);
}
break;
}
}
@ -193,6 +201,7 @@ void Machine::set_region(Commodore::Vic20::Region region)
void Machine::setup_output(float aspect_ratio)
{
_mos6560.reset(new Vic6560());
_mos6560->get_speaker()->set_high_frequency_cut_off(1600); // There is a 1.6Khz low-pass filter in the Vic-20.
set_region(_region);
memset(_mos6560->_videoMemoryMap, 0, sizeof(_mos6560->_videoMemoryMap));

View File

@ -72,10 +72,20 @@ class Speaker {
set_needs_updated_filter_coefficients();
}
Speaker() : _buffer_in_progress_pointer(0), _requested_number_of_taps(0) {}
/*!
Sets the cut-off frequency for a low-pass filter attached to the output of this speaker; optional.
*/
void set_high_frequency_cut_off(float high_frequency)
{
_high_frequency_cut_off = high_frequency;
set_needs_updated_filter_coefficients();
}
Speaker() : _buffer_in_progress_pointer(0), _requested_number_of_taps(0), _high_frequency_cut_off(-1.0) {}
protected:
std::unique_ptr<int16_t> _buffer_in_progress;
float _high_frequency_cut_off;
int _buffer_size;
int _buffer_in_progress_pointer;
int _number_of_taps, _requested_number_of_taps;
@ -114,7 +124,7 @@ template <class T> class Filter: public Speaker {
if(_coefficients_are_dirty) update_filter_coefficients();
// if input and output rates exactly match, just accumulate results and pass on
if(_input_cycles_per_second == _output_cycles_per_second)
if(_input_cycles_per_second == _output_cycles_per_second && _high_frequency_cut_off < 0.0)
{
while(input_cycles)
{
@ -215,7 +225,17 @@ template <class T> class Filter: public Speaker {
_buffer_in_progress_pointer = 0;
_stepper.reset(new SignalProcessing::Stepper((uint64_t)_input_cycles_per_second, (uint64_t)_output_cycles_per_second));
_filter.reset(new SignalProcessing::FIRFilter((unsigned int)_number_of_taps, (float)_input_cycles_per_second, 0.0, (float)_output_cycles_per_second / 2.0f, SignalProcessing::FIRFilter::DefaultAttenuation));
float high_pass_frequency;
if(_high_frequency_cut_off > 0.0)
{
high_pass_frequency = std::min((float)_output_cycles_per_second / 2.0f, _high_frequency_cut_off);
}
else
{
high_pass_frequency = (float)_output_cycles_per_second / 2.0f;
}
_filter.reset(new SignalProcessing::FIRFilter((unsigned int)_number_of_taps, (float)_input_cycles_per_second, 0.0, high_pass_frequency, SignalProcessing::FIRFilter::DefaultAttenuation));
_input_buffer.reset(new int16_t[_number_of_taps]);
_input_buffer_depth = 0;