- Adaptat el mòdul 'ay-3-8912' per a usar zx_speaker, pero encara no fa roidets, a vore si demà trobe el perquè
This commit is contained in:
175
ay-3-8912.cpp
175
ay-3-8912.cpp
@@ -1,6 +1,7 @@
|
|||||||
#include "ay-3-8912.h"
|
#include "ay-3-8912.h"
|
||||||
#include "z80.h"
|
#include "z80.h"
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
#include "zx_ula.h"
|
||||||
|
|
||||||
#define MIXER_REG_A_TONE 0x01
|
#define MIXER_REG_A_TONE 0x01
|
||||||
#define MIXER_REG_B_TONE 0x02
|
#define MIXER_REG_B_TONE 0x02
|
||||||
@@ -70,33 +71,34 @@ namespace audio
|
|||||||
case 0:
|
case 0:
|
||||||
case 1: {
|
case 1: {
|
||||||
uint16_t freq = registers[0] | ((registers[1] & 0xf) << 8);
|
uint16_t freq = registers[0] | ((registers[1] & 0xf) << 8);
|
||||||
channel_a_tone_freq = clock / freq;
|
channel_a_tone_freq = clock / freq==0?1:freq;
|
||||||
channel_a_tone_freq_counter = 0;
|
channel_a_tone_freq_counter = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
case 3: {
|
case 3: {
|
||||||
uint16_t freq = registers[2] | ((registers[3] & 0xf) << 8);
|
uint16_t freq = registers[2] | ((registers[3] & 0xf) << 8);
|
||||||
channel_b_tone_freq = clock / freq;
|
channel_b_tone_freq = clock / freq==0?1:freq;
|
||||||
channel_b_tone_freq_counter = 0;
|
channel_b_tone_freq_counter = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
case 5: {
|
case 5: {
|
||||||
uint16_t freq = registers[4] | ((registers[5] & 0xf) << 8);
|
uint16_t freq = registers[4] | ((registers[5] & 0xf) << 8);
|
||||||
channel_c_tone_freq = clock / freq;
|
channel_c_tone_freq = clock / freq==0?1:freq;
|
||||||
channel_c_tone_freq_counter = 0;
|
channel_c_tone_freq_counter = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 6: {
|
case 6: {
|
||||||
noise_freq = clock / (registers[6] & 0x1f);
|
uint8_t freq = (registers[6] & 0x1f);
|
||||||
|
noise_freq = clock / freq==0?1:freq;
|
||||||
noise_freq_counter = 0;
|
noise_freq_counter = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 11:
|
case 11:
|
||||||
case 12: {
|
case 12: {
|
||||||
uint16_t freq = registers[11] | (registers[12] << 8);
|
uint16_t freq = registers[11] | (registers[12] << 8);
|
||||||
envelope_freq = clock / freq;
|
envelope_freq = clock / freq==0?1:freq;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 13:
|
case 13:
|
||||||
@@ -112,13 +114,9 @@ namespace audio
|
|||||||
|
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
SDL_AudioSpec audioSpec{SAMPLING_FREQ, AUDIO_U8, 1, 0, AUDIO_BUFFER_SIZE, 0, 0, NULL, NULL};
|
|
||||||
sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
|
|
||||||
cycles_per_sample = z80::getClock() / SAMPLING_FREQ;
|
|
||||||
reset();
|
reset();
|
||||||
z80::connect_port(0xfffd, 0xffff, audio::read_register, audio::select_register);
|
z80::connect_port(0xfffd, 0xffff, audio::read_register, audio::select_register);
|
||||||
z80::connect_port(0xbffd, 0xffff, nullptr, audio::write_register);
|
z80::connect_port(0xbffd, 0xffff, nullptr, audio::write_register);
|
||||||
resume();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset()
|
void reset()
|
||||||
@@ -127,97 +125,96 @@ namespace audio
|
|||||||
for (int i=0; i<16;++i) registers[i]=0;
|
for (int i=0; i<16;++i) registers[i]=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void silence()
|
|
||||||
{
|
|
||||||
SDL_PauseAudioDevice(sdlAudioDevice, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void resume()
|
|
||||||
{
|
|
||||||
SDL_PauseAudioDevice(sdlAudioDevice, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void update(uint32_t dt)
|
void update(uint32_t dt)
|
||||||
{
|
{
|
||||||
for (int i=0;i<dt;i+=2)
|
dt = dt >> 1;
|
||||||
{
|
|
||||||
// Oscillate (0-1) channel A tone level given its frequency
|
|
||||||
channel_a_tone_freq_counter++;
|
|
||||||
if (channel_a_tone_freq_counter == channel_a_tone_freq) {
|
|
||||||
channel_a_tone_freq_counter = 0;
|
|
||||||
channel_a_tone_level = channel_a_tone_level ^ 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Oscillate (0-1) channel B tone level given its frequency
|
// Oscillate (0-1) channel A tone level given its frequency
|
||||||
channel_b_tone_freq_counter++;
|
channel_a_tone_freq_counter+=dt;
|
||||||
if (channel_b_tone_freq_counter == channel_b_tone_freq) {
|
if (channel_a_tone_freq_counter >= channel_a_tone_freq) {
|
||||||
channel_b_tone_freq_counter = 0;
|
channel_a_tone_freq_counter -= channel_a_tone_freq;
|
||||||
channel_b_tone_level = channel_b_tone_level ^ 1;
|
channel_a_tone_level = channel_a_tone_level ^ 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Oscillate (0-1) channel C tone level given its frequency
|
// Oscillate (0-1) channel B tone level given its frequency
|
||||||
channel_c_tone_freq_counter++;
|
channel_b_tone_freq_counter+=dt;
|
||||||
if (channel_c_tone_freq_counter == channel_c_tone_freq) {
|
if (channel_b_tone_freq_counter >= channel_b_tone_freq) {
|
||||||
channel_c_tone_freq_counter = 0;
|
channel_b_tone_freq_counter -= channel_b_tone_freq;
|
||||||
channel_c_tone_level = channel_c_tone_level ^ 1;
|
channel_b_tone_level = channel_b_tone_level ^ 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Oscillate (0-1) noise level given its frequency and shift register
|
// Oscillate (0-1) channel C tone level given its frequency
|
||||||
noise_freq_counter++;
|
channel_c_tone_freq_counter+=dt;
|
||||||
if (noise_freq_counter == noise_freq) {
|
if (channel_c_tone_freq_counter >= channel_c_tone_freq) {
|
||||||
noise_freq_counter = 0;
|
channel_c_tone_freq_counter -= channel_c_tone_freq;
|
||||||
noise_level = noise_level ^ shiftreg;
|
channel_c_tone_level = channel_c_tone_level ^ 1;
|
||||||
uint32_t newbit = shiftreg ^ (shiftreg >> 3);
|
}
|
||||||
shiftreg = ((shiftreg >> 1) & 0xff) | ((newbit << 16) & 0x100);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mix tone and noise on channel A given register 7 values
|
// Oscillate (0-1) noise level given its frequency and shift register
|
||||||
channel_a_level = 1;
|
noise_freq_counter+=dt;
|
||||||
if (registers[7] & MIXER_REG_A_TONE) channel_a_level &= channel_a_tone_level;
|
if (noise_freq_counter >= noise_freq) {
|
||||||
if (registers[7] & MIXER_REG_A_NOISE) channel_a_level &= noise_level;
|
noise_freq_counter -= noise_freq;
|
||||||
|
noise_level = noise_level ^ shiftreg;
|
||||||
// Mix tone and noise on channel B given register 7 values
|
uint32_t newbit = shiftreg ^ (shiftreg >> 3);
|
||||||
channel_b_level = 1;
|
shiftreg = ((shiftreg >> 1) & 0xff) | ((newbit << 16) & 0x100);
|
||||||
if (registers[7] & MIXER_REG_B_TONE) channel_b_level &= channel_b_tone_level;
|
}
|
||||||
if (registers[7] & MIXER_REG_B_NOISE) 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) channel_c_level &= channel_c_tone_level;
|
|
||||||
if (registers[7] & MIXER_REG_C_NOISE) channel_c_level &= noise_level;
|
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
// Develop (0-15) envelope volume given its frequency and shape
|
envelope_volume += envelope_direction;
|
||||||
envelope_freq_counter++;
|
if ( (envelope_volume > 15) || (envelope_volume < 0) ) {
|
||||||
if (envelope_freq_counter == envelope_freq) {
|
switch(registers[13]&0xf) {
|
||||||
envelope_freq_counter = 0;
|
case 8:
|
||||||
|
case 12:
|
||||||
envelope_volume += envelope_direction;
|
envelope_volume &= 0x0f;
|
||||||
if ( (envelope_volume > 15) || (envelope_volume < 0) ) {
|
break;
|
||||||
switch(registers[13]&0xf) {
|
case 10:
|
||||||
case 8:
|
case 14:
|
||||||
case 12:
|
envelope_direction = -envelope_direction;
|
||||||
envelope_volume &= 0x0f;
|
envelope_volume += envelope_direction;
|
||||||
break;
|
case 11:
|
||||||
case 10:
|
case 13:
|
||||||
case 14:
|
envelope_direction = 0;
|
||||||
envelope_direction = -envelope_direction;
|
envelope_volume = 15;
|
||||||
envelope_volume += envelope_direction;
|
default:
|
||||||
case 11:
|
envelope_direction = 0;
|
||||||
case 13:
|
envelope_volume = 0;
|
||||||
envelope_direction = 0;
|
|
||||||
envelope_volume = 15;
|
|
||||||
default:
|
|
||||||
envelope_direction = 0;
|
|
||||||
envelope_volume = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t channel_a_volume = (registers[8]&0x10) ? envelope_volume : registers[8]&0xf;
|
|
||||||
uint8_t channel_b_volume = (registers[9]&0x10) ? envelope_volume : registers[9]&0xf;
|
|
||||||
uint8_t channel_c_volume = (registers[10]&0x10) ? envelope_volume : registers[10]&0xf;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) channel_a_level &= channel_a_tone_level;
|
||||||
|
if (registers[7] & MIXER_REG_A_NOISE) 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) channel_b_level &= channel_b_tone_level;
|
||||||
|
if (registers[7] & MIXER_REG_B_NOISE) 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) channel_c_level &= channel_c_tone_level;
|
||||||
|
if (registers[7] & MIXER_REG_C_NOISE) channel_c_level &= noise_level;
|
||||||
|
|
||||||
|
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;
|
||||||
|
zx_ula::set_border_color(sample&0xf);
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace audio
|
|||||||
|
|
||||||
void init();
|
void init();
|
||||||
void reset();
|
void reset();
|
||||||
void silence();
|
|
||||||
void resume();
|
|
||||||
void update(uint32_t dt);
|
void update(uint32_t dt);
|
||||||
|
|
||||||
|
uint8_t get_sample();
|
||||||
}
|
}
|
||||||
|
|||||||
15
main.cpp
15
main.cpp
@@ -19,6 +19,7 @@
|
|||||||
#include "z80viewer.h"
|
#include "z80viewer.h"
|
||||||
//#include "zx_128bankviewer.h"
|
//#include "zx_128bankviewer.h"
|
||||||
//#include "zx_128pageviewer.h"
|
//#include "zx_128pageviewer.h"
|
||||||
|
#include "ay-3-8912.h"
|
||||||
|
|
||||||
//uint8_t memory[65536];
|
//uint8_t memory[65536];
|
||||||
uint32_t time = 0;
|
uint32_t time = 0;
|
||||||
@@ -78,23 +79,24 @@ namespace actions
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
const uint32_t clock = 3500000;
|
//const uint32_t clock = 3500000;
|
||||||
//const uint32_t clock = 3546900;
|
const uint32_t clock = 3546900;
|
||||||
const uint32_t update_freq = clock / 10;
|
const uint32_t update_freq = clock / 10;
|
||||||
|
|
||||||
//new zx_48mem();
|
//new zx_48mem();
|
||||||
//new zx_128mem();
|
//new zx_128mem();
|
||||||
mem::init(ZX_48K);
|
mem::init(ZX_128K);
|
||||||
|
|
||||||
z80dis::loadSymbols();
|
z80dis::loadSymbols();
|
||||||
z80::setClock(clock);
|
z80::setClock(clock);
|
||||||
z80::reset();
|
z80::reset();
|
||||||
z80::connect_port(0xfe, 0x0001, zx_ula::port_in, zx_ula::port_out);
|
z80::connect_port(0xfe, 0x0001, zx_ula::port_in, zx_ula::port_out);
|
||||||
|
audio::init();
|
||||||
|
|
||||||
SDL_Init(SDL_INIT_EVERYTHING);
|
SDL_Init(SDL_INIT_EVERYTHING);
|
||||||
z80debug::init();
|
z80debug::init();
|
||||||
zxscreen::init(SCREEN_MODE_48K);
|
//zxscreen::init(SCREEN_MODE_48K);
|
||||||
//zxscreen::init(SCREEN_MODE_128K);
|
zxscreen::init(SCREEN_MODE_128K);
|
||||||
|
|
||||||
//z80viewer *v = new zx_128bankviewer();
|
//z80viewer *v = new zx_128bankviewer();
|
||||||
//v->show();
|
//v->show();
|
||||||
@@ -131,6 +133,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
speaker::init();
|
speaker::init();
|
||||||
speaker::register_source(zx_ula::get_sample);
|
speaker::register_source(zx_ula::get_sample);
|
||||||
|
speaker::register_source(audio::get_sample);
|
||||||
|
|
||||||
zx_tape::load("ROBOCOP1.TAP");
|
zx_tape::load("ROBOCOP1.TAP");
|
||||||
|
|
||||||
@@ -244,7 +247,7 @@ int main(int argc, char *argv[])
|
|||||||
uint8_t dt = z80::step();
|
uint8_t dt = z80::step();
|
||||||
t_states += dt;
|
t_states += dt;
|
||||||
zx_tape::update(dt);
|
zx_tape::update(dt);
|
||||||
|
audio::update(dt);
|
||||||
speaker::update(dt);
|
speaker::update(dt);
|
||||||
zxscreen::refresh(dt);
|
zxscreen::refresh(dt);
|
||||||
if (z80debug::debugging()) break;
|
if (z80debug::debugging()) break;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "ui_window.h"
|
#include "ui_window.h"
|
||||||
#include "zx_screen.h"
|
#include "zx_screen.h"
|
||||||
|
#include "ay-3-8912.h"
|
||||||
|
|
||||||
#define RESIZING_NONE 0
|
#define RESIZING_NONE 0
|
||||||
#define RESIZING_MEMORY 1
|
#define RESIZING_MEMORY 1
|
||||||
@@ -792,6 +793,7 @@ namespace z80debug
|
|||||||
if (strcmp(cmd, "s")==0 || strcmp(cmd, "step")==0) {
|
if (strcmp(cmd, "s")==0 || strcmp(cmd, "step")==0) {
|
||||||
uint8_t dt = z80::step();
|
uint8_t dt = z80::step();
|
||||||
zx_tape::update(dt);
|
zx_tape::update(dt);
|
||||||
|
audio::update(dt);
|
||||||
speaker::update(dt);
|
speaker::update(dt);
|
||||||
zxscreen::fullrefresh();
|
zxscreen::fullrefresh();
|
||||||
z80analyze::refresh();
|
z80analyze::refresh();
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ namespace zx_ula
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t get_border_color() { return border_color; }
|
uint8_t get_border_color() { return border_color; }
|
||||||
|
void set_border_color(uint8_t col) { border_color = col; }
|
||||||
uint8_t get_ear() { return ear; }
|
uint8_t get_ear() { return ear; }
|
||||||
void set_ear(const uint8_t val) { ear = val; }
|
void set_ear(const uint8_t val) { ear = val; }
|
||||||
|
|
||||||
|
|||||||
1
zx_ula.h
1
zx_ula.h
@@ -8,6 +8,7 @@ namespace zx_ula
|
|||||||
void port_out(int port, int val);
|
void port_out(int port, int val);
|
||||||
|
|
||||||
uint8_t get_border_color();
|
uint8_t get_border_color();
|
||||||
|
void set_border_color(uint8_t col);
|
||||||
uint8_t get_ear();
|
uint8_t get_ear();
|
||||||
void set_ear(const uint8_t val);
|
void set_ear(const uint8_t val);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user