1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Makes first attempt at actually implementing the SCC.

This commit is contained in:
Thomas Harte 2018-01-06 23:15:42 -05:00
parent 655b971976
commit fc16e8eb8c
2 changed files with 87 additions and 5 deletions

View File

@ -25,14 +25,83 @@ void SCC::get_samples(std::size_t number_of_samples, std::int16_t *target) {
return;
}
// TODO
std::size_t c = 0;
while((master_divider_&7) && c < number_of_samples) {
target[c] = output_volume_;
master_divider_++;
c++;
}
while(c < number_of_samples) {
for(int channel = 0; channel < 5; ++channel) {
if(channels_[channel].tone_counter) channels_[channel].tone_counter--;
else {
channels_[channel].offset = (channels_[channel].offset + 1) & 0x1f;
channels_[channel].tone_counter = channels_[channel].period;
}
}
evaluate_output_volume();
for(int ic = 0; ic < 8 && c < number_of_samples; ++ic) {
target[c] = output_volume_;
c++;
master_divider_++;
}
}
}
void SCC::write(uint16_t address, uint8_t value) {
// TODO
address &= 0xff;
if(address < 0x80) ram_[address] = value;
task_queue_.defer([=] {
// Check for a write into waveform memory.
if(address < 0x80) {
waves_[address >> 5].samples[address & 0x1f] = value;
} else switch(address) {
default: break;
case 0x80: case 0x82: case 0x84: case 0x86: case 0x88: {
int channel = (address - 0x80) >> 1;
channels_[channel].period = (channels_[channel].period & ~0xff) | value;
} break;
case 0x81: case 0x83: case 0x85: case 0x87: case 0x89: {
int channel = (address - 0x80) >> 1;
channels_[channel].period = (channels_[channel].period & 0xff) | ((value & 0xf) << 8);
} break;
case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e:
channels_[address - 0x8a].amplitude = value;
break;
case 0x8f:
channel_enable_ = value;
break;
}
evaluate_output_volume();
});
}
void SCC::evaluate_output_volume() {
output_volume_ =
static_cast<int16_t>(
((
(channel_enable_ & 0x01) ? static_cast<int8_t>(waves_[0].samples[channels_[0].offset]) * channels_[0].amplitude : 0 +
(channel_enable_ & 0x02) ? static_cast<int8_t>(waves_[1].samples[channels_[1].offset]) * channels_[1].amplitude : 0 +
(channel_enable_ & 0x04) ? static_cast<int8_t>(waves_[2].samples[channels_[2].offset]) * channels_[2].amplitude : 0 +
(channel_enable_ & 0x08) ? static_cast<int8_t>(waves_[3].samples[channels_[3].offset]) * channels_[3].amplitude : 0 +
(channel_enable_ & 0x10) ? static_cast<int8_t>(waves_[3].samples[channels_[4].offset]) * channels_[4].amplitude : 0
) * 16) / 5
);
}
uint8_t SCC::read(uint16_t address) {
// TODO
address &= 0xff;
if(address < 0x80) {
return ram_[address];
}
return 0xff;
}

View File

@ -39,19 +39,32 @@ class SCC: public ::Outputs::Speaker::SampleSource {
uint8_t read(uint16_t address);
private:
Concurrency::DeferringAsyncTaskQueue &task_queue_;
// State from here on down is accessed ony from the audio thread.
int master_divider_ = 0;
int16_t output_volume_ = 0;
struct Channel {
int period = 0;
int amplitude = 0;
int tone_counter = 0;
int offset = 0;
} channels_[5];
struct Wavetable {
std::int16_t samples[32];
std::uint8_t samples[32];
} waves_[4];
std::uint8_t channel_enable_ = 0;
std::uint8_t test_register_ = 0;
Concurrency::DeferringAsyncTaskQueue &task_queue_;
void evaluate_output_volume();
// This keeps a copy of wave memory that is accessed from the
// main emulation thread.
std::uint8_t ram_[128];
};
}