mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-16 18:30:32 +00:00
Made an attempt to implement noise and envelopes. Not quite right yet.
This commit is contained in:
parent
5a808d789a
commit
ada37abe23
@ -10,9 +10,59 @@
|
||||
|
||||
using namespace GI;
|
||||
|
||||
AY38910::AY38910() : _selected_register(0), _channel_ouput{0, 0, 0}, _channel_dividers{0, 0, 0}, _tone_generator_controls{0, 0, 0}
|
||||
AY38910::AY38910() :
|
||||
_selected_register(0),
|
||||
_channel_output{0, 0, 0}, _channel_dividers{0, 0, 0}, _tone_generator_controls{0, 0, 0},
|
||||
_noise_shift_register(0xffff), _noise_divider(0), _noise_output(0),
|
||||
_envelope_divider(0), _envelope_period(0)
|
||||
{
|
||||
_output_registers[8] = _output_registers[9] = _output_registers[10] = 0;
|
||||
|
||||
// set up envelope lookup tables
|
||||
for(int c = 0; c < 16; c++)
|
||||
{
|
||||
for(int p = 0; p < 32; p++)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case 0: case 1: case 2: case 3: case 9:
|
||||
_envelope_shapes[c][p] = (p < 16) ? (p^0xf) : 0;
|
||||
_envelope_overflow_masks[c] = 0x1f;
|
||||
break;
|
||||
case 4: case 5: case 6: case 7: case 15:
|
||||
_envelope_shapes[c][p] = (p < 16) ? p : 0;
|
||||
_envelope_overflow_masks[c] = 0x1f;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
_envelope_shapes[c][p] = (p & 0xf) ^ 0xf;
|
||||
_envelope_overflow_masks[c] = 0x00;
|
||||
break;
|
||||
case 12:
|
||||
_envelope_shapes[c][p] = (p & 0xf);
|
||||
_envelope_overflow_masks[c] = 0x00;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
_envelope_shapes[c][p] = (p & 0xf) ^ ((p < 16) ? 0xf : 0x0);
|
||||
_envelope_overflow_masks[c] = 0x00;
|
||||
break;
|
||||
case 14:
|
||||
_envelope_shapes[c][p] = (p & 0xf) ^ ((p < 16) ? 0x0 : 0xf);
|
||||
_envelope_overflow_masks[c] = 0x00;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
_envelope_shapes[c][p] = (p < 16) ? (p^0xf) : 0xf;
|
||||
_envelope_overflow_masks[c] = 0x1f;
|
||||
break;
|
||||
case 13:
|
||||
_envelope_shapes[c][p] = (p < 16) ? p : 0xf;
|
||||
_envelope_overflow_masks[c] = 0x1f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AY38910::set_clock_rate(double clock_rate)
|
||||
@ -30,12 +80,12 @@ void AY38910::get_samples(unsigned int number_of_samples, int16_t *target)
|
||||
int resulting_steps = ((_master_divider ^ former_master_divider) >> 4) & 1;
|
||||
|
||||
// from that the three channels count down
|
||||
#define step(c) {\
|
||||
int did_underflow;
|
||||
#define step(c) \
|
||||
_channel_dividers[c] -= resulting_steps; \
|
||||
int did_underflow = (_channel_dividers[c] >> 15)&1; \
|
||||
_channel_ouput[c] ^= did_underflow; \
|
||||
_channel_dividers[c] = did_underflow * _tone_generator_controls[c] + (did_underflow^1) * _channel_dividers[c]; \
|
||||
}
|
||||
did_underflow = (_channel_dividers[c] >> 15)&1; \
|
||||
_channel_output[c] ^= did_underflow; \
|
||||
_channel_dividers[c] = did_underflow * _tone_generator_controls[c] + (did_underflow^1) * _channel_dividers[c];
|
||||
|
||||
step(0);
|
||||
step(1);
|
||||
@ -43,19 +93,51 @@ void AY38910::get_samples(unsigned int number_of_samples, int16_t *target)
|
||||
|
||||
#undef step
|
||||
|
||||
// ... as does the envelope generator
|
||||
// _envelope_divider -= resulting_steps;
|
||||
// if(!_envelope_divider)
|
||||
// ... as does the noise generator
|
||||
_noise_divider -= resulting_steps;
|
||||
did_underflow = (_noise_divider >> 15)&1;
|
||||
_noise_divider = did_underflow * (_output_registers[6]&0x1f) + (did_underflow^1) * _noise_divider;
|
||||
_noise_output ^= did_underflow&_noise_shift_register&1;
|
||||
_noise_shift_register |= ((_noise_shift_register ^ (_noise_shift_register >> 3))&1) << 17;
|
||||
_noise_shift_register >>= did_underflow;
|
||||
|
||||
// ... and the envelope generator
|
||||
_envelope_divider -= resulting_steps;
|
||||
did_underflow = (_envelope_divider >> 15)&1;
|
||||
_envelope_divider = did_underflow * _envelope_period + (did_underflow^1) * _envelope_divider;
|
||||
_envelope_position += did_underflow;
|
||||
|
||||
// if(_output_registers[13] == 13)
|
||||
// {
|
||||
// _envelope_divider = _envelope_period;
|
||||
// printf("[%d] %d", _envelope_divider, _envelope_position);
|
||||
// }
|
||||
|
||||
// if(_output_registers[9]) printf("%d %d / %d\n", _channel_ouput[1], _channel_dividers[1], _tone_generator_controls[1]);
|
||||
int refill = _envelope_overflow_masks[_output_registers[13]] * (_envelope_position >> 5);
|
||||
_envelope_position = (_envelope_position & 0x1f) | refill;
|
||||
|
||||
int envelope_volume = _envelope_shapes[_output_registers[13]][_envelope_position & 0xf];
|
||||
|
||||
// if(_output_registers[13] == 13)
|
||||
// {
|
||||
// printf(": %d\n", envelope_volume);
|
||||
// }
|
||||
|
||||
int channel_levels[3] = {
|
||||
(((((_output_registers[7] >> 0)&1)^1) & _channel_output[0]) | ((((_output_registers[7] >> 1)&1)^1) & _noise_output)) ^ 1,
|
||||
(((((_output_registers[7] >> 2)&1)^1) & _channel_output[1]) | ((((_output_registers[7] >> 3)&1)^1) & _noise_output)) ^ 1,
|
||||
(((((_output_registers[7] >> 4)&1)^1) & _channel_output[2]) | ((((_output_registers[7] >> 5)&1)^1) & _noise_output)) ^ 1,
|
||||
};
|
||||
|
||||
int volumes[3] = {
|
||||
((_output_registers[8] >> 4)&1) * envelope_volume + (((_output_registers[8] >> 4)&1)^1) * (_output_registers[8]&0x1f),
|
||||
((_output_registers[9] >> 4)&1) * envelope_volume + (((_output_registers[9] >> 4)&1)^1) * (_output_registers[9]&0x1f),
|
||||
((_output_registers[10] >> 4)&1) * envelope_volume + (((_output_registers[10] >> 4)&1)^1) * (_output_registers[10]&0x1f),
|
||||
};
|
||||
|
||||
target[c] = (int16_t)((
|
||||
(_output_registers[8]&0xf) * _channel_ouput[0] +
|
||||
(_output_registers[9]&0xf) * _channel_ouput[1] +
|
||||
(_output_registers[10]&0xf) * _channel_ouput[2]
|
||||
volumes[0] * channel_levels[0] +
|
||||
volumes[1] * channel_levels[1] +
|
||||
volumes[2] * channel_levels[2]
|
||||
) * 512);
|
||||
}
|
||||
}
|
||||
@ -78,6 +160,7 @@ void AY38910::set_register_value(uint8_t value)
|
||||
{
|
||||
int selected_register = _selected_register;
|
||||
enqueue([=] () {
|
||||
uint8_t masked_value = value;
|
||||
switch(selected_register)
|
||||
{
|
||||
case 0: case 2: case 4:
|
||||
@ -92,13 +175,21 @@ void AY38910::set_register_value(uint8_t value)
|
||||
|
||||
case 11:
|
||||
_envelope_period = (_envelope_period & ~0xff) | value;
|
||||
// printf("e: %d", _envelope_period);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
_envelope_period = (_envelope_period & 0xff) | (uint16_t)(value << 8);
|
||||
_envelope_period = (_envelope_period & 0xff) | (int)(value << 8);
|
||||
// printf("e: %d", _envelope_period);
|
||||
break;
|
||||
|
||||
case 13:
|
||||
masked_value &= 0xf;
|
||||
_envelope_position = 0;
|
||||
// printf("envelope %d\n", masked_value);
|
||||
break;
|
||||
}
|
||||
_output_registers[selected_register] = value;
|
||||
_output_registers[selected_register] = masked_value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -37,13 +37,22 @@ class AY38910: public ::Outputs::Filter<AY38910> {
|
||||
uint8_t _registers[16], _output_registers[16];
|
||||
|
||||
uint16_t _tone_generator_controls[3];
|
||||
uint16_t _envelope_period;
|
||||
int _channel_dividers[3];
|
||||
int _channel_output[3];
|
||||
|
||||
|
||||
int _master_divider;
|
||||
int _channel_dividers[3];
|
||||
|
||||
int _noise_divider;
|
||||
int _noise_shift_register;
|
||||
int _noise_output;
|
||||
|
||||
int _envelope_period;
|
||||
int _envelope_divider;
|
||||
int _evelope_volume;
|
||||
int _channel_ouput[3];
|
||||
|
||||
int _envelope_position;
|
||||
int _envelope_shapes[16][32];
|
||||
int _envelope_overflow_masks[16];
|
||||
|
||||
enum ControlState {
|
||||
Inactive,
|
||||
|
Loading…
x
Reference in New Issue
Block a user