mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-18 01:30:56 +00:00
111 lines
2.6 KiB
C++
111 lines
2.6 KiB
C++
//
|
|
// AY-3-8910.cpp
|
|
// Clock Signal
|
|
//
|
|
// Created by Thomas Harte on 14/10/2016.
|
|
// Copyright © 2016 Thomas Harte. All rights reserved.
|
|
//
|
|
|
|
#include "AY38910.hpp"
|
|
|
|
using namespace GI;
|
|
|
|
AY38910::AY38910() : _selected_register(0), _channel_ouput{0, 0, 0}, _channel_dividers{0, 0, 0}, _tone_generator_controls{0, 0, 0}
|
|
{
|
|
_output_registers[8] = _output_registers[9] = _output_registers[10] = 0;
|
|
}
|
|
|
|
void AY38910::set_clock_rate(double clock_rate)
|
|
{
|
|
set_input_rate((float)clock_rate);
|
|
}
|
|
|
|
|
|
void AY38910::get_samples(unsigned int number_of_samples, int16_t *target)
|
|
{
|
|
for(int c = 0; c < number_of_samples; c++)
|
|
{
|
|
// a master divider divides the clock by 16
|
|
int former_master_divider = _master_divider;
|
|
_master_divider++;
|
|
int resulting_steps = ((_master_divider ^ former_master_divider) >> 4) & 1;
|
|
|
|
// from that the three channels count down
|
|
#define step(c) \
|
|
_channel_dividers[c] -= resulting_steps; \
|
|
_channel_ouput[c] ^= (_channel_dividers[c] >> 15); \
|
|
_channel_dividers[c] = ((_channel_dividers[c] >> 15) * _tone_generator_controls[c]) + ((_channel_dividers[c] >> 15)^1) * _channel_dividers[c];
|
|
|
|
step(0);
|
|
step(1);
|
|
step(2);
|
|
|
|
#undef step
|
|
|
|
// ... as does the envelope generator
|
|
_envelope_divider -= resulting_steps;
|
|
if(!_envelope_divider)
|
|
{
|
|
_envelope_divider = _envelope_period;
|
|
}
|
|
|
|
*target++ = (int16_t)((
|
|
((_output_registers[8]&0xf) * _channel_ouput[0]) +
|
|
((_output_registers[9]&0xf) * _channel_ouput[1]) +
|
|
((_output_registers[10]&0xf) * _channel_ouput[2])
|
|
) * 512);
|
|
}
|
|
}
|
|
|
|
void AY38910::skip_samples(unsigned int number_of_samples)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void AY38910::select_register(uint8_t r)
|
|
{
|
|
_selected_register = r & 0xf;
|
|
}
|
|
|
|
void AY38910::set_register_value(uint8_t value)
|
|
{
|
|
_registers[_selected_register] = value;
|
|
if(value < 14)
|
|
{
|
|
int selected_register = _selected_register;
|
|
enqueue([=] () {
|
|
_output_registers[selected_register] = value;
|
|
switch(selected_register)
|
|
{
|
|
case 0: case 2: case 4:
|
|
_tone_generator_controls[selected_register >> 1] =
|
|
(_tone_generator_controls[selected_register >> 1] & ~0xff) | value;
|
|
break;
|
|
|
|
case 1: case 3: case 5:
|
|
_tone_generator_controls[selected_register >> 1] =
|
|
(_tone_generator_controls[selected_register >> 1] & 0xff) | (uint16_t)((value&0xf) << 8);
|
|
break;
|
|
|
|
case 11:
|
|
_envelope_period = (_envelope_period & ~0xff) | value;
|
|
break;
|
|
|
|
case 12:
|
|
_envelope_period = (_envelope_period & 0xff) | (uint16_t)(value << 8);
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
uint8_t AY38910::get_register_value()
|
|
{
|
|
return _registers[_selected_register];
|
|
}
|
|
|
|
uint8_t AY38910::get_port_output(bool port_b)
|
|
{
|
|
return _registers[port_b ? 15 : 14];
|
|
}
|