- [NEW] [tia] áudio en el seu propi mòdul, pa no tornar-se loco - [NEW] Afegides frequències de rellotge per a NTSC, PAL, SECAM i PAL-M - [NEW] Mòdul Speaker conectat a tia-audio
188 lines
6.6 KiB
C++
188 lines
6.6 KiB
C++
#include "tia-audio.h"
|
|
|
|
namespace tia
|
|
{
|
|
namespace audio
|
|
{
|
|
static const uint16_t BIT_PATTERN_15 = 0x7556;
|
|
static const uint32_t BIT_PATTERN_31 = 0x74567254;
|
|
static const uint8_t LFSR511_TABLE[511] = {
|
|
1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,0,1,1,1,0,0,1,0,1,
|
|
0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,1,1,1,0,0,0,0,0,1,0,1,0,1,0,0,
|
|
1,0,0,1,0,0,0,1,0,0,1,1,0,0,0,1,0,1,1,1,0,0,1,1,1,0,1,0,1,1,0,
|
|
1,0,0,0,1,1,0,1,1,0,0,0,1,1,0,0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,
|
|
0,0,1,1,0,1,1,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,1,0,0,1,1,1,0,0,0,
|
|
1,0,0,0,0,1,0,0,1,0,1,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,0,1,
|
|
1,1,0,1,0,0,0,1,0,1,0,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,
|
|
1,0,0,1,1,1,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,0,0,1,1,1,0,1,1,0,1,
|
|
1,1,0,0,1,0,1,1,0,1,1,0,0,1,1,1,1,1,0,0,1,1,0,1,0,1,0,1,0,0,0,
|
|
1,0,1,1,1,1,0,0,1,0,1,0,0,0,1,0,1,1,0,1,0,1,1,1,0,1,1,0,0,0,0,
|
|
1,0,1,1,0,0,1,0,1,0,1,1,1,1,0,1,1,0,1,0,0,1,0,1,0,0,1,0,1,1,0,
|
|
0,0,0,0,1,0,0,0,1,1,1,1,1,1,0,1,0,0,0,0,0,1,1,1,0,0,0,1,0,1,0,
|
|
1,1,0,1,1,0,1,0,1,0,0,1,0,0,1,1,0,1,0,0,0,0,0,0,0,1,1,0,1,1,1,
|
|
0,1,1,0,1,0,0,1,1,0,0,1,0,1,0,0,0,1,1,1,1,0,1,1,1,1,0,0,1,1,1,
|
|
1,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,1,0,1,1,0,1,0,0,1,0,0,0,1,1,0,
|
|
1,0,1,1,0,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,0,0,1,1,0,1,1,1,0,1,0,
|
|
1,0,0,0,0,0,1,1
|
|
};
|
|
|
|
uint8_t get_lfsr511_bit(uint32_t step)
|
|
{
|
|
return LFSR511_TABLE[step % 511];
|
|
}
|
|
|
|
uint8_t get_poly_mode_bit(uint8_t audc, uint32_t step)
|
|
{
|
|
switch (audc & 0x0F) {
|
|
case 0:
|
|
case 11:
|
|
return 1; // Direct volume (PCM output)
|
|
|
|
case 1:
|
|
// 4-bit Poly (15 steps)
|
|
return (BIT_PATTERN_15 >> (step % 15)) & 1;
|
|
|
|
case 2:
|
|
// 5-bit Poly -> 4-bit Poly divisor (31 steps)
|
|
return (BIT_PATTERN_31 >> (step % 31)) & 1;
|
|
|
|
case 3: {
|
|
// 5-bit Poly XOR 4-bit Poly (465 steps)
|
|
uint8_t b5 = (BIT_PATTERN_31 >> (step % 31)) & 1;
|
|
uint8_t b4 = (BIT_PATTERN_15 >> (step % 15)) & 1;
|
|
return b5 ^ b4;
|
|
}
|
|
|
|
case 4:
|
|
case 5:
|
|
// Pure Tone: Divide frequency clock by 2
|
|
return (step & 1);
|
|
|
|
case 6:
|
|
case 10:
|
|
// Divide by 31 then divide by 2
|
|
return ((step / 31) & 1);
|
|
|
|
case 7:
|
|
case 9:
|
|
// 5-bit Poly output variant
|
|
return ((BIT_PATTERN_31 >> ((step / 2) % 31)) & 1);
|
|
|
|
case 8:
|
|
// White Noise (9-bit Poly / 511 steps)
|
|
return get_lfsr511_bit(step);
|
|
|
|
case 12:
|
|
case 13:
|
|
// Pure Tone: Divide frequency clock by 6
|
|
return ((step / 3) & 1);
|
|
|
|
case 14:
|
|
// Divide by 93 (31 * 3) then divide by 2
|
|
return ((step / 93) & 1);
|
|
|
|
case 15:
|
|
// 5-bit Poly clocked down by 6
|
|
return ((BIT_PATTERN_31 >> ((step / 6) % 31)) & 1);
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
struct channel
|
|
{
|
|
uint8_t control = 0;
|
|
uint8_t frequency = 0;
|
|
uint8_t volume = 0;
|
|
uint8_t freq_counter = 0;
|
|
uint32_t poly_counter = 0;
|
|
|
|
};
|
|
|
|
channel channels[2];
|
|
|
|
void tick()
|
|
{
|
|
for (int i=0; i<2; ++i) {
|
|
if (channels[i].freq_counter == 0) {
|
|
channels[i].freq_counter = channels[i].frequency + 1;
|
|
channels[i].poly_counter++;
|
|
} else {
|
|
channels[i].freq_counter--;
|
|
}
|
|
}
|
|
}
|
|
|
|
void write(uint16_t address, uint8_t value)
|
|
{
|
|
switch (address) {
|
|
case 0x15: // AUDC0
|
|
channels[0].control = value & 0x0f; break;
|
|
case 0x16: // AUDC1
|
|
channels[1].control = value & 0x0f; break;
|
|
case 0x17: // AUDF0
|
|
channels[0].frequency = value & 0x1f; break;
|
|
case 0x18: // AUDF1
|
|
channels[1].frequency = value & 0x1f; break;
|
|
case 0x19: // AUDV0
|
|
channels[0].volume = value & 0x0f; break;
|
|
case 0x1A: // AUDV1
|
|
channels[1].volume = value & 0x0f; break;
|
|
}
|
|
}
|
|
|
|
uint8_t get_sample0() { return get_sample(0); }
|
|
uint8_t get_sample1() { return get_sample(1); }
|
|
|
|
uint8_t get_sample(uint8_t channel)
|
|
{
|
|
if (channels[channel].volume == 0) return 0;
|
|
|
|
bool bit_out = false;
|
|
|
|
switch (channels[channel].control) {
|
|
case 0:
|
|
case 11:
|
|
// Set to 1: Direct volume output (PCM mode)
|
|
bit_out = true;
|
|
break;
|
|
|
|
case 1:
|
|
// 4-bit Poly (15-step repeating sequence)
|
|
bit_out = (BIT_PATTERN_15 >> (channels[channel].poly_counter % 15)) & 1;
|
|
break;
|
|
|
|
case 2:
|
|
// 5-bit Poly (31-step repeating sequence)
|
|
bit_out = (BIT_PATTERN_31 >> (channels[channel].poly_counter % 31)) & 1;
|
|
break;
|
|
|
|
case 4:
|
|
case 5:
|
|
// Pure tone (Divide by 2 square wave)
|
|
bit_out = (channels[channel].poly_counter & 1);
|
|
break;
|
|
|
|
case 8:
|
|
// White noise (9-bit Poly / 511-step sequence)
|
|
bit_out = get_lfsr511_bit(channels[channel].poly_counter % 511);
|
|
break;
|
|
|
|
case 12:
|
|
case 13:
|
|
// Pure tone (Divide by 6 square wave)
|
|
bit_out = ((channels[channel].poly_counter / 3) & 1);
|
|
break;
|
|
|
|
default:
|
|
// Handle remaining poly modes (3, 6, 7, 9, 10, 14, 15) via lookup table
|
|
bit_out = get_poly_mode_bit(channels[channel].control, channels[channel].poly_counter);
|
|
break;
|
|
}
|
|
|
|
return bit_out ? channels[channel].volume * 17 : 0;
|
|
}
|
|
|
|
}
|
|
} |