1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-05 10:28:58 +00:00

Made a very basic stab at a couple of the tone generators, added straight-through path for the speaker when input rate exactly equals output rate.

This commit is contained in:
Thomas Harte 2016-06-01 19:53:16 -04:00
parent 40c4544fb7
commit 1e0fcbbee8
3 changed files with 76 additions and 32 deletions

View File

@ -802,6 +802,7 @@ void Atari2600::Speaker::set_volume(int channel, uint8_t volume)
void Atari2600::Speaker::set_divider(int channel, uint8_t divider)
{
_divider[channel] = divider & 0x1f;
_divider_counter[channel] = 0;
}
void Atari2600::Speaker::set_control(int channel, uint8_t control)
@ -816,12 +817,21 @@ void Atari2600::Speaker::get_samples(unsigned int number_of_samples, int16_t *ta
target[c] = 0;
for(int channel = 0; channel < 2; channel++)
{
if(!_control[channel])
{
target[c] += _volume[channel] * 1024;
}
else
switch(_control[channel])
{
case 0x0: case 0xb:
target[c] += _volume[channel] * 1024;
break;
case 0x4: case 0x5:
_divider_counter[channel] ++;
target[c] += _volume[channel] * 1024 * ((_divider_counter[channel] / (_divider[channel]+1))&1);
break;
case 0xc: case 0xd:
_divider_counter[channel] ++;
target[c] += _volume[channel] * 1024 * ((_divider_counter[channel] / ((_divider[channel]+1)*3))&1);
break;
}
}
}

View File

@ -32,7 +32,9 @@ class Speaker: public ::Outputs::Filter<Speaker> {
uint8_t _volume[2];
uint8_t _divider[2];
uint8_t _control[2];
int _shift_counters[2];
int _shift_counter[2];
int _divider_counter[2];
int _output_state[2];
};
class Machine: public CPU6502::Processor<Machine>, public CRTMachine::Machine {

View File

@ -88,20 +88,16 @@ template <class T> class Filter: public Speaker {
{
if(_coefficients_are_dirty) update_filter_coefficients();
// TODO: what if output rate is greater than input rate?
// fill up as much of the input buffer as possible
while(input_cycles)
// if input and output rates exactly match, just accumulate results and pass on
if(_input_cycles_per_second == _output_cycles_per_second)
{
unsigned int cycles_to_read = (unsigned int)std::min((int)input_cycles, _number_of_taps - _input_buffer_depth);
static_cast<T *>(this)->get_samples(cycles_to_read, &_input_buffer.get()[_input_buffer_depth]);
input_cycles -= cycles_to_read;
_input_buffer_depth += cycles_to_read;
if(_input_buffer_depth == _number_of_taps)
while(input_cycles)
{
_buffer_in_progress.get()[_buffer_in_progress_pointer] = _filter->apply(_input_buffer.get());
_buffer_in_progress_pointer++;
unsigned int cycles_to_read = (unsigned int)(_buffer_size - _buffer_in_progress_pointer);
if(cycles_to_read > input_cycles) cycles_to_read = input_cycles;
static_cast<T *>(this)->get_samples(cycles_to_read, &_buffer_in_progress.get()[_buffer_in_progress_pointer]);
_buffer_in_progress_pointer += cycles_to_read;
// announce to delegate if full
if(_buffer_in_progress_pointer == _buffer_size)
@ -113,24 +109,60 @@ template <class T> class Filter: public Speaker {
}
}
// If the next loop around is going to reuse some of the samples just collected, use a memmove to
// preserve them in the correct locations (TODO: use a longer buffer to fix that) and don't skip
// anything. Otherwise skip as required to get to the next sample batch and don't expect to reuse.
uint64_t steps = _stepper->step();
if(steps < _number_of_taps)
input_cycles -= cycles_to_read;
}
return;
}
// if the output rate is less than the input rate, use the filter
if(_input_cycles_per_second > _output_cycles_per_second)
{
while(input_cycles)
{
unsigned int cycles_to_read = (unsigned int)std::min((int)input_cycles, _number_of_taps - _input_buffer_depth);
static_cast<T *>(this)->get_samples(cycles_to_read, &_input_buffer.get()[_input_buffer_depth]);
input_cycles -= cycles_to_read;
_input_buffer_depth += cycles_to_read;
if(_input_buffer_depth == _number_of_taps)
{
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;
}
else
{
if(steps > _number_of_taps)
static_cast<T *>(this)->skip_samples((unsigned int)steps - (unsigned int)_number_of_taps);
_input_buffer_depth = 0;
_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)
{
_buffer_in_progress_pointer = 0;
if(_delegate)
{
_delegate->speaker_did_complete_samples(this, _buffer_in_progress.get(), _buffer_size);
}
}
// If the next loop around is going to reuse some of the samples just collected, use a memmove to
// preserve them in the correct locations (TODO: use a longer buffer to fix that) and don't skip
// anything. Otherwise skip as required to get to the next sample batch and don't expect to reuse.
uint64_t steps = _stepper->step();
if(steps < _number_of_taps)
{
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;
}
else
{
if(steps > _number_of_taps)
static_cast<T *>(this)->skip_samples((unsigned int)steps - (unsigned int)_number_of_taps);
_input_buffer_depth = 0;
}
}
}
return;
}
// TODO: input rate is less than output rate
}
private: