mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-09 06:29:33 +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:
parent
40c4544fb7
commit
1e0fcbbee8
@ -802,6 +802,7 @@ void Atari2600::Speaker::set_volume(int channel, uint8_t volume)
|
|||||||
void Atari2600::Speaker::set_divider(int channel, uint8_t divider)
|
void Atari2600::Speaker::set_divider(int channel, uint8_t divider)
|
||||||
{
|
{
|
||||||
_divider[channel] = divider & 0x1f;
|
_divider[channel] = divider & 0x1f;
|
||||||
|
_divider_counter[channel] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Atari2600::Speaker::set_control(int channel, uint8_t control)
|
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;
|
target[c] = 0;
|
||||||
for(int channel = 0; channel < 2; channel++)
|
for(int channel = 0; channel < 2; channel++)
|
||||||
{
|
{
|
||||||
if(!_control[channel])
|
switch(_control[channel])
|
||||||
{
|
|
||||||
target[c] += _volume[channel] * 1024;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,9 @@ class Speaker: public ::Outputs::Filter<Speaker> {
|
|||||||
uint8_t _volume[2];
|
uint8_t _volume[2];
|
||||||
uint8_t _divider[2];
|
uint8_t _divider[2];
|
||||||
uint8_t _control[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 {
|
class Machine: public CPU6502::Processor<Machine>, public CRTMachine::Machine {
|
||||||
|
@ -88,20 +88,16 @@ template <class T> class Filter: public Speaker {
|
|||||||
{
|
{
|
||||||
if(_coefficients_are_dirty) update_filter_coefficients();
|
if(_coefficients_are_dirty) update_filter_coefficients();
|
||||||
|
|
||||||
// TODO: what if output rate is greater than input rate?
|
// if input and output rates exactly match, just accumulate results and pass on
|
||||||
|
if(_input_cycles_per_second == _output_cycles_per_second)
|
||||||
// fill up as much of the input buffer as possible
|
|
||||||
while(input_cycles)
|
|
||||||
{
|
{
|
||||||
unsigned int cycles_to_read = (unsigned int)std::min((int)input_cycles, _number_of_taps - _input_buffer_depth);
|
while(input_cycles)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
_buffer_in_progress.get()[_buffer_in_progress_pointer] = _filter->apply(_input_buffer.get());
|
unsigned int cycles_to_read = (unsigned int)(_buffer_size - _buffer_in_progress_pointer);
|
||||||
_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
|
// announce to delegate if full
|
||||||
if(_buffer_in_progress_pointer == _buffer_size)
|
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
|
input_cycles -= cycles_to_read;
|
||||||
// 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();
|
return;
|
||||||
if(steps < _number_of_taps)
|
}
|
||||||
|
|
||||||
|
// 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();
|
_buffer_in_progress.get()[_buffer_in_progress_pointer] = _filter->apply(_input_buffer.get());
|
||||||
memmove(input_buffer, &input_buffer[steps], sizeof(int16_t) * ((size_t)_number_of_taps - (size_t)steps));
|
_buffer_in_progress_pointer++;
|
||||||
_input_buffer_depth -= steps;
|
|
||||||
}
|
// announce to delegate if full
|
||||||
else
|
if(_buffer_in_progress_pointer == _buffer_size)
|
||||||
{
|
{
|
||||||
if(steps > _number_of_taps)
|
_buffer_in_progress_pointer = 0;
|
||||||
static_cast<T *>(this)->skip_samples((unsigned int)steps - (unsigned int)_number_of_taps);
|
if(_delegate)
|
||||||
_input_buffer_depth = 0;
|
{
|
||||||
|
_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:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user