mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +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:
commit
f937e08c91
@ -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)
|
||||
{
|
||||
|
@ -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; }
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user