#include "ay-3-8912.h" #include "z80.h" #include #include "zx_ula.h" #define MIXER_REG_A_TONE 0x01 #define MIXER_REG_B_TONE 0x02 #define MIXER_REG_C_TONE 0x04 #define MIXER_REG_A_NOISE 0x08 #define MIXER_REG_B_NOISE 0x10 #define MIXER_REG_C_NOISE 0x20 #define MIXER_REG_PORT_A 0x40 #define MIXER_REG_PORT_B 0x80 #define ENVELOPE_HOLD 0x01 #define ENVELOPE_ALTERNATE 0x02 #define ENVELOPE_ATTACK 0x04 #define ENVELOPE_CONTINUE 0x08 namespace audio { #define SAMPLING_FREQ 44100 #define AUDIO_BUFFER_SIZE 2048 float cycles_per_sample; uint8_t volume_table[16] {0,2,3,4,6,8,11,16,23,32,45,64,90,128,180,255}; SDL_AudioDeviceID sdlAudioDevice; uint8_t selected_register {0}; uint8_t registers[16]; uint32_t channel_a_tone_freq; uint32_t channel_a_tone_freq_counter; uint8_t channel_a_tone_level; uint8_t channel_a_level; uint32_t channel_b_tone_freq; uint32_t channel_b_tone_freq_counter; uint8_t channel_b_tone_level; uint8_t channel_b_level; uint32_t channel_c_tone_freq; uint32_t channel_c_tone_freq_counter; uint8_t channel_c_tone_level; uint8_t channel_c_level; uint32_t noise_freq; uint32_t noise_freq_counter; uint8_t noise_level; uint32_t shiftreg; uint32_t envelope_freq; uint32_t envelope_freq_counter; int8_t envelope_volume; int8_t envelope_direction; void select_register(int port, int val) { selected_register = val & 0xf; } int read_register(int port) { return registers[selected_register]; } void write_register(int port, int val) { registers[selected_register] = val; switch (selected_register) { case 0: case 1: { uint32_t freq = uint32_t(registers[0]) + (uint32_t(registers[1]) * 256); channel_a_tone_freq = (freq==0?1:freq)<<4; channel_a_tone_freq_counter = 0; break; } case 2: case 3: { uint32_t freq = uint32_t(registers[2]) + (uint32_t(registers[3]) * 256); channel_b_tone_freq = (freq==0?1:freq)<<4; channel_b_tone_freq_counter = 0; break; } case 4: case 5: { uint32_t freq = uint32_t(registers[4]) + (uint32_t(registers[5]) * 256); channel_c_tone_freq = (freq==0?1:freq)<<4; channel_c_tone_freq_counter = 0; break; } case 6: { uint32_t freq = (registers[6] & 0x1f); noise_freq = (freq==0?1:freq)<<4; noise_freq_counter = 0; break; } case 11: case 12: { uint32_t freq = registers[11] | (registers[12] << 8); envelope_freq = (freq==0?1:freq)<<4; break; } case 13: if (registers[13]&ENVELOPE_ATTACK) { envelope_volume = 0; envelope_direction = 1; } else { envelope_volume = 15; envelope_direction = -1; } } } void init() { reset(); z80::connect_port(0xfffd, 0xffff, audio::read_register, audio::select_register); z80::connect_port(0xbffd, 0xffff, nullptr, audio::write_register); } void reset() { selected_register = 0; for (int i=0; i<16;++i) registers[i]=0; } void update(uint32_t dt) { //dt = dt >> 1; // Oscillate (0-1) channel A tone level given its frequency channel_a_tone_freq_counter+=dt; if (channel_a_tone_freq_counter >= channel_a_tone_freq) { channel_a_tone_freq_counter -= channel_a_tone_freq; channel_a_tone_level = channel_a_tone_level ^ 1; } // Oscillate (0-1) channel B tone level given its frequency channel_b_tone_freq_counter+=dt; if (channel_b_tone_freq_counter >= channel_b_tone_freq) { channel_b_tone_freq_counter -= channel_b_tone_freq; channel_b_tone_level = channel_b_tone_level ^ 1; } // Oscillate (0-1) channel C tone level given its frequency channel_c_tone_freq_counter+=dt; if (channel_c_tone_freq_counter >= channel_c_tone_freq) { channel_c_tone_freq_counter -= channel_c_tone_freq; channel_c_tone_level = channel_c_tone_level ^ 1; } // Oscillate (0-1) noise level given its frequency and shift register noise_freq_counter+=dt; if (noise_freq_counter >= noise_freq) { noise_freq_counter -= noise_freq; //noise_level = noise_level ^ shiftreg; //uint32_t newbit = shiftreg ^ (shiftreg >> 3); //shiftreg = ((shiftreg >> 1) & 0xffff) | ((newbit << 16) & 0x10000); shiftreg = (shiftreg * 2 + 1) ^ (((shiftreg >> 16) ^ (shiftreg >> 13)) & 1); noise_level = ((shiftreg >> 16) & 1); } // Develop (0-15) envelope volume given its frequency and shape envelope_freq_counter+=dt; if (envelope_freq_counter >= envelope_freq) { envelope_freq_counter -= envelope_freq; envelope_volume += envelope_direction; if ( (envelope_volume > 15) || (envelope_volume < 0) ) { switch(registers[13]&0xf) { case 8: case 12: envelope_volume &= 0x0f; break; case 10: case 14: envelope_direction = -envelope_direction; envelope_volume += envelope_direction; case 11: case 13: envelope_direction = 0; envelope_volume = 15; default: envelope_direction = 0; envelope_volume = 0; } } } } uint8_t get_sample() { // Mix tone and noise on channel A given register 7 values channel_a_level = 1; if ((registers[7] & MIXER_REG_A_TONE)==0) channel_a_level &= channel_a_tone_level; if ((registers[7] & MIXER_REG_A_NOISE)==0) channel_a_level &= noise_level; // Mix tone and noise on channel B given register 7 values channel_b_level = 1; if ((registers[7] & MIXER_REG_B_TONE)==0) channel_b_level &= channel_b_tone_level; if ((registers[7] & MIXER_REG_B_NOISE)==0) channel_b_level &= noise_level; // Mix tone and noise on channel C given register 7 values channel_c_level = 1; if ((registers[7] & MIXER_REG_C_TONE)==0) channel_c_level &= channel_c_tone_level; if ((registers[7] & MIXER_REG_C_NOISE)==0) channel_c_level &= noise_level; //zx_ula::set_border_color(channel_a_tone_level&0xf); const uint8_t channel_a_volume = (registers[8]&0x10) ? envelope_volume : registers[8]&0xf; const uint8_t channel_b_volume = (registers[9]&0x10) ? envelope_volume : registers[9]&0xf; const uint8_t channel_c_volume = (registers[10]&0x10) ? envelope_volume : registers[10]&0xf; const uint8_t channel_a_sample = volume_table[(channel_a_level&1) * channel_a_volume] >> 1; const uint8_t channel_b_sample = volume_table[(channel_b_level&1) * channel_b_volume] >> 1; const uint8_t channel_c_sample = volume_table[(channel_c_level&1) * channel_c_volume] >> 1; uint8_t sample = (channel_a_sample+channel_b_sample+channel_c_sample)&0xff; return sample; } namespace debug { uint8_t get_register(uint8_t num) { return registers[num]; } uint32_t get_channel_a_tone_freq() { return channel_a_tone_freq; } uint32_t get_channel_a_tone_freq_counter() { return channel_a_tone_freq_counter; } uint8_t get_channel_a_tone_level() { return channel_a_tone_level; } uint8_t get_channel_a_level() { return channel_a_level; } uint32_t get_channel_b_tone_freq() { return channel_b_tone_freq; } uint32_t get_channel_b_tone_freq_counter() { return channel_b_tone_freq_counter; } uint8_t get_channel_b_tone_level() { return channel_b_tone_level; } uint8_t get_channel_b_level() { return channel_b_level; } uint32_t get_channel_c_tone_freq() { return channel_c_tone_freq; } uint32_t get_channel_c_tone_freq_counter() { return channel_c_tone_freq_counter; } uint8_t get_channel_c_tone_level() { return channel_c_tone_level; } uint8_t get_channel_c_level() { return channel_c_level; } uint32_t get_noise_freq() { return noise_freq; } uint32_t get_noise_freq_counter() { return noise_freq_counter; } uint8_t get_noise_level() { return noise_level; } uint32_t get_shiftreg() { return shiftreg; } uint32_t get_envelope_freq() { return envelope_freq; } uint32_t get_envelope_freq_counter() { return envelope_freq_counter; } int8_t get_envelope_volume() { return envelope_volume; } int8_t get_envelope_direction() { return envelope_direction; } } }