diff --git a/main.cpp b/main.cpp index f48f271..8a79da4 100644 --- a/main.cpp +++ b/main.cpp @@ -4,6 +4,7 @@ #include "z80dis.h" #include "z80debug.h" #include "zx_ula.h" +#include "zx_speaker.h" #include "zx_screen.h" #include "zx_tape.h" #include @@ -128,7 +129,8 @@ int main(int argc, char *argv[]) ui::menu::addbooloption(menu, "STOP ON INVALID OP", z80::getOption(Z80_OPTION_STOP_ON_INVALID), actions::decZoom); ui::menu::addoption(menu, "SHOW ANALYZER", actions::showAnalyzer); - zx_ula::sound_init(); + speaker::init(); + speaker::register_source(zx_ula::get_sample); zx_tape::load("ROBOCOP1.TAP"); @@ -228,7 +230,7 @@ int main(int argc, char *argv[]) time = SDL_GetTicks(); zx_tape::report(); } - //zx_ula::sound_update(dt); + //speaker::update(dt); //zxscreen::refresh(dt); } if (fastload) { printf("%i\n", SDL_GetTicks()-time); t_states=0; } @@ -243,7 +245,7 @@ int main(int argc, char *argv[]) t_states += dt; zx_tape::update(dt); - zx_ula::sound_update(dt); + speaker::update(dt); zxscreen::refresh(dt); if (z80debug::debugging()) break; } diff --git a/z80debug.cpp b/z80debug.cpp index f68c96b..c2652f2 100644 --- a/z80debug.cpp +++ b/z80debug.cpp @@ -5,6 +5,7 @@ #include "zx_mem.h" #include "z80analyze.h" #include "zx_ula.h" +#include "zx_speaker.h" #include "zx_tape.h" #include "ui.h" #include "ui_window.h" @@ -360,7 +361,7 @@ namespace z80debug void pause() { - zx_ula::sound_disable(); + speaker::disable(); is_paused = true; breakpoints[z80::getPC()] &= ~8; } @@ -383,7 +384,7 @@ namespace z80debug //hide(); refresh(); zxscreen::focus(); - zx_ula::sound_enable(); + speaker::enable(); } const bool debugging() { return is_debugging; } @@ -791,7 +792,7 @@ namespace z80debug if (strcmp(cmd, "s")==0 || strcmp(cmd, "step")==0) { uint8_t dt = z80::step(); zx_tape::update(dt); - zx_ula::sound_update(dt); + speaker::update(dt); zxscreen::fullrefresh(); z80analyze::refresh(); } else if (strcmp(cmd, "c")==0 || strcmp(cmd, "cont")==0) { diff --git a/zx_speaker.cpp b/zx_speaker.cpp new file mode 100644 index 0000000..3d71091 --- /dev/null +++ b/zx_speaker.cpp @@ -0,0 +1,60 @@ +#include "zx_speaker.h" +#include +#include "z80.h" +#include + +namespace speaker +{ + #define SAMPLING_FREQ 44100 + #define AUDIO_BUFFER_SIZE 2048 + SDL_AudioDeviceID sdlAudioDevice; + uint8_t sound_buffer[AUDIO_BUFFER_SIZE]; + uint16_t sound_pos=0; + uint16_t t_sound=0; + std::vector sources; + + float cycles_per_sample; + + void init() + { + SDL_AudioSpec audioSpec{SAMPLING_FREQ, AUDIO_U8, 1, 0, AUDIO_BUFFER_SIZE>>2, 0, 0, NULL, NULL}; + sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0); + cycles_per_sample = z80::getClock() / SAMPLING_FREQ; + enable(); + } + + void enable() + { + SDL_PauseAudioDevice(sdlAudioDevice, 0); + } + + void disable() + { + SDL_PauseAudioDevice(sdlAudioDevice, 1); + } + + void register_source(uint8_t(*callback)()) + { + sources.push_back(callback); + } + + void update(const uint8_t dt) + { + t_sound += dt; + if (t_sound>=cycles_per_sample) { + t_sound-=cycles_per_sample; + + uint32_t sample = 0; + for (auto callback : sources) sample += callback(); + sample /= sources.size(); + + sound_buffer[(sound_pos++)&(AUDIO_BUFFER_SIZE-1)] = sample; + } + if (sound_pos>=1000) { + SDL_QueueAudio(sdlAudioDevice, sound_buffer, sound_pos); + sound_pos = 0; + while (SDL_GetQueuedAudioSize(sdlAudioDevice) > 4096 ) {} + } + } + +} diff --git a/zx_speaker.h b/zx_speaker.h new file mode 100644 index 0000000..c1e3c01 --- /dev/null +++ b/zx_speaker.h @@ -0,0 +1,11 @@ +#pragma once +#include + +namespace speaker +{ + void init(); + void enable(); + void disable(); + void register_source(uint8_t(*callback)()); + void update(const uint8_t dt); +} diff --git a/zx_ula.cpp b/zx_ula.cpp index 8ee7747..4f6ef17 100644 --- a/zx_ula.cpp +++ b/zx_ula.cpp @@ -68,11 +68,6 @@ namespace zx_ula static uint8_t ear = 0; static uint8_t mic = 0; - // this variable keeps track of the last "1" written to the sound buffer, so when streaming it in the audio callback, if there - // are only zeros remaining in the buffer, we just discard it. It's a poor man's method of keeping the buffer size in control. - // This is useless when there are music, sounds, tape loading, etc... as 1's and 0's keep alternating - static uint16_t last_1 = 0; - void update_zx_keyboard() { const uint8_t *keys = SDL_GetKeyboardState(NULL); @@ -231,47 +226,9 @@ namespace zx_ula uint8_t get_ear() { return ear; } void set_ear(const uint8_t val) { ear = val; } - - #define SAMPLING_FREQ 44100 - #define AUDIO_BUFFER_SIZE 2048 - - float cycles_per_sample; - SDL_AudioDeviceID sdlAudioDevice; - uint8_t sound_buffer[AUDIO_BUFFER_SIZE]; - uint16_t sound_pos=0; - uint16_t t_sound=0; - - void sound_init() + uint8_t get_sample() { - SDL_AudioSpec audioSpec{SAMPLING_FREQ, AUDIO_U8, 1, 0, AUDIO_BUFFER_SIZE>>2, 0, 0, NULL, NULL}; - sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0); - cycles_per_sample = z80::getClock() / SAMPLING_FREQ; - sound_enable(); - } - - void sound_enable() - { - SDL_PauseAudioDevice(sdlAudioDevice, 0); - } - - void sound_disable() - { - SDL_PauseAudioDevice(sdlAudioDevice, 1); - } - - void sound_update(const uint8_t dt) - { - t_sound += dt; - if (t_sound>=cycles_per_sample) { - t_sound-=cycles_per_sample; - - sound_buffer[(sound_pos++)&(AUDIO_BUFFER_SIZE-1)] = ear*128; - } - if (sound_pos>=1000) { - SDL_QueueAudio(sdlAudioDevice, sound_buffer, sound_pos); - sound_pos = 0; - while (SDL_GetQueuedAudioSize(sdlAudioDevice) > 4096 ) {} - } + return ear*128; } const int getKey(const char key) diff --git a/zx_ula.h b/zx_ula.h index d11516c..bc39f4c 100644 --- a/zx_ula.h +++ b/zx_ula.h @@ -11,10 +11,7 @@ namespace zx_ula uint8_t get_ear(); void set_ear(const uint8_t val); - void sound_init(); - void sound_enable(); - void sound_disable(); - void sound_update(const uint8_t dt); + uint8_t get_sample(); void keydown(const char key); void keyup(const char key);