summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--blastem.c26
-rw-r--r--blastem.h2
-rw-r--r--psg.c112
-rw-r--r--psg.h32
-rw-r--r--render.h6
-rw-r--r--render_sdl.c330
7 files changed, 381 insertions, 131 deletions
diff --git a/Makefile b/Makefile
index 3df5c1d..9c73393 100644
--- a/Makefile
+++ b/Makefile
@@ -7,8 +7,8 @@ endif
all : dis trans stateview blastem
-blastem : blastem.o 68kinst.o gen_x86.o m68k_to_x86.o z80inst.o z80_to_x86.o x86_backend.o runtime.o zruntime.o mem.o vdp.o ym2612.o render_sdl.o
- $(CC) -o blastem blastem.o 68kinst.o gen_x86.o m68k_to_x86.o z80inst.o z80_to_x86.o x86_backend.o runtime.o zruntime.o mem.o vdp.o ym2612.o render_sdl.o `pkg-config --libs $(LIBS)`
+blastem : blastem.o 68kinst.o gen_x86.o m68k_to_x86.o z80inst.o z80_to_x86.o x86_backend.o runtime.o zruntime.o mem.o vdp.o ym2612.o psg.o render_sdl.o
+ $(CC) -o blastem blastem.o 68kinst.o gen_x86.o m68k_to_x86.o z80inst.o z80_to_x86.o x86_backend.o runtime.o zruntime.o mem.o vdp.o ym2612.o psg.o render_sdl.o `pkg-config --libs $(LIBS)`
dis : dis.o 68kinst.o
$(CC) -o dis dis.o 68kinst.o
diff --git a/blastem.c b/blastem.c
index c3b8b09..9f81b13 100644
--- a/blastem.c
+++ b/blastem.c
@@ -14,6 +14,7 @@
#define Z80_RAM_BYTES 8 * 1024
#define MCLKS_PER_68K 7
#define MCLKS_PER_Z80 15
+#define MCLKS_PER_PSG (MCLKS_PER_Z80*16)
//TODO: Figure out the exact value for this
#define CYCLE_NEVER 0xFFFFFFFF
#define LINES_NTSC 262
@@ -200,6 +201,8 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
gen->ym->current_cycle -= mclks_per_frame/MCLKS_PER_68K;
//printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks);
vdp_run_context(v_context, mclks_per_frame);
+ psg_run(gen->psg, mclks/MCLKS_PER_PSG);
+ gen->psg->cycles -= mclks_per_frame/MCLKS_PER_PSG;
if (!headless) {
break_on_sync |= wait_render_frame(v_context, frame_limit);
}
@@ -228,6 +231,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
} else {
//printf("running VDP for %d cycles\n", mclks - v_context->cycles);
vdp_run_context(v_context, mclks);
+ psg_run(gen->psg, mclks/MCLKS_PER_PSG);
}
if (context->int_ack) {
vdp_int_ack(v_context, context->int_ack);
@@ -318,7 +322,9 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_
context->current_cycle = v_context->cycles / MCLKS_PER_68K;
}
} else if (vdp_port < 0x18) {
- //TODO: Implement PSG
+ genesis_context * gen = context->system;
+ psg_run(gen->psg, (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_PSG);
+ psg_write(gen->psg, value);
} else {
//TODO: Implement undocumented test register(s)
}
@@ -327,7 +333,7 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_
m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8_t value)
{
- return vdp_port_write(vdp_port, context, value | value << 8);
+ return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : value);
}
uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context)
@@ -1385,6 +1391,9 @@ void detect_region()
}
}
+#define PSG_CLKS_NTSC (3579545/16)
+#define PSG_CLKS_PAL (3546893/16)
+
int main(int argc, char ** argv)
{
if (argc < 2) {
@@ -1456,12 +1465,13 @@ int main(int argc, char ** argv)
update_title();
width = width < 320 ? 320 : width;
height = height < 240 ? (width/320) * 240 : height;
- if (!headless) {
- render_init(width, height, title);
- }
+ uint32_t fps = 60;
if (version_reg & 0x40) {
mclks_per_frame = MCLKS_LINE * LINES_PAL;
- render_fps(50);
+ fps = 50;
+ }
+ if (!headless) {
+ render_init(width, height, title, fps);
}
vdp_context v_context;
@@ -1470,6 +1480,9 @@ int main(int argc, char ** argv)
ym2612_context y_context;
ym_init(&y_context);
+ psg_context p_context;
+ psg_init(&p_context, render_sample_rate(), fps == 60 ? PSG_CLKS_NTSC : PSG_CLKS_PAL, render_audio_buffer());
+
z80_context z_context;
x86_z80_options z_opts;
init_x86_z80_opts(&z_opts);
@@ -1486,6 +1499,7 @@ int main(int argc, char ** argv)
gen.z80 = &z_context;
gen.vdp = &v_context;
gen.ym = &y_context;
+ gen.psg = &p_context;
genesis = &gen;
int fname_size = strlen(argv[1]);
diff --git a/blastem.h b/blastem.h
index 7a4f707..351ad9f 100644
--- a/blastem.h
+++ b/blastem.h
@@ -6,6 +6,7 @@
#include "z80_to_x86.h"
#include "ym2612.h"
#include "vdp.h"
+#include "psg.h"
typedef struct {
uint32_t th_counter;
@@ -24,6 +25,7 @@ typedef struct {
z80_context *z80;
vdp_context *vdp;
ym2612_context *ym;
+ psg_context *psg;
uint8_t *save_ram;
uint32_t save_ram_mask;
uint32_t save_flags;
diff --git a/psg.c b/psg.c
new file mode 100644
index 0000000..81c5754
--- /dev/null
+++ b/psg.c
@@ -0,0 +1,112 @@
+#include "psg.h"
+#include "render.h"
+#include <string.h>
+#include <stdlib.h>
+
+void psg_init(psg_context * context, uint32_t sample_rate, uint32_t clock_rate, uint32_t samples_frame)
+{
+ memset(context, 0, sizeof(*context));
+ context->audio_buffer = malloc(sizeof(*context->audio_buffer) * samples_frame);
+ context->back_buffer = malloc(sizeof(*context->audio_buffer) * samples_frame);
+ context->buffer_inc = (double)sample_rate / (double)clock_rate;
+ context->samples_frame = samples_frame;
+ for (int i = 0; i < 4; i++) {
+ context->volume[i] = 0xF;
+ }
+}
+
+void psg_write(psg_context * context, uint8_t value)
+{
+ if (value & 0x80) {
+ context->latch = value & 0x70;
+ uint8_t channel = value >> 5 & 0x3;
+ if (value & 0x10) {
+ context->volume[channel] = value & 0xF;
+ } else {
+ if (channel == 3) {
+ switch(value & 0x3)
+ {
+ case 0:
+ case 1:
+ case 2:
+ context->counter_load[3] = 0x10 << (value & 0x3);
+ context->noise_use_tone = 0;
+ break;
+ default:
+ context->counter_load[3] = context->counter_load[2];
+ context->noise_use_tone = 1;
+ }
+ context->noise_type = value & 0x4;
+ context->lsfr = 0x8000;
+ } else {
+ context->counter_load[channel] = (context->counter_load[channel] & 0x3F0) | (value & 0xF);
+ if (channel == 2 && context->noise_use_tone) {
+ context->counter_load[3] = context->counter_load[2];
+ }
+ }
+ }
+ } else {
+ if (!(context->latch & 0x10)) {
+ uint8_t channel = context->latch >> 5 & 0x3;
+ if (channel != 3) {
+ context->counter_load[channel] = (value << 4 & 0x3F0) | (context->counter_load[channel] & 0xF);
+ if (channel == 2 && context->noise_use_tone) {
+ context->counter_load[3] = context->counter_load[2];
+ }
+ }
+ }
+ }
+}
+
+#define PSG_VOL_DIV 2
+
+//table shamelessly swiped from PSG doc from smspower.org
+int16_t volume_table[16] = {
+ 32767/PSG_VOL_DIV, 26028/PSG_VOL_DIV, 20675/PSG_VOL_DIV, 16422/PSG_VOL_DIV, 13045/PSG_VOL_DIV, 10362/PSG_VOL_DIV,
+ 8231/PSG_VOL_DIV, 6568/PSG_VOL_DIV, 5193/PSG_VOL_DIV, 4125/PSG_VOL_DIV, 3277/PSG_VOL_DIV, 2603/PSG_VOL_DIV,
+ 2067/PSG_VOL_DIV, 1642/PSG_VOL_DIV, 1304/PSG_VOL_DIV, 0
+};
+
+void psg_run(psg_context * context, uint32_t cycles)
+{
+ while (context->cycles < cycles) {
+ for (int i = 0; i < 4; i++) {
+ if (context->counters[i]) {
+ context->counters[i] -= 1;
+ }
+ if (!context->counters[i]) {
+ context->counters[i] = context->counter_load[i];
+ context->output_state[i] = !context->output_state[i];
+ if (i == 3 && context->output_state[i]) {
+ context->noise_out = context->lsfr & 1;
+ context->lsfr = (context->lsfr >> 1) | (context->lsfr << 15);
+ if (context->noise_type) {
+ //white noise
+ if (context->lsfr & 0x40) {
+ context->lsfr ^= 0x8000;
+ }
+ }
+ }
+ }
+ }
+ context->buffer_fraction += context->buffer_inc;
+ if (context->buffer_fraction >= 1.0) {
+ context->buffer_fraction -= 1.0;
+ int16_t acc = 0;
+ for (int i = 0; i < 3; i++) {
+ if (context->output_state[i]) {
+ acc += volume_table[context->volume[i]];
+ }
+ }
+ if (context->noise_out) {
+ acc += volume_table[context->volume[3]];
+ }
+ context->audio_buffer[context->buffer_pos++] = acc;
+ if (context->buffer_pos == context->samples_frame) {
+ render_wait_audio(context);
+ }
+ }
+ context->cycles++;
+ }
+}
+
diff --git a/psg.h b/psg.h
new file mode 100644
index 0000000..7d36f5c
--- /dev/null
+++ b/psg.h
@@ -0,0 +1,32 @@
+#ifndef PSG_CONTEXT_H_
+#define PSG_CONTEXT_H_
+
+#include <stdint.h>
+
+typedef struct {
+ int16_t *audio_buffer;
+ int16_t *back_buffer;
+ double buffer_fraction;
+ double buffer_inc;
+ uint32_t buffer_pos;
+ uint32_t back_pos;
+ uint32_t cycles;
+ uint32_t samples_frame;
+ uint16_t lsfr;
+ uint16_t counter_load[4];
+ uint16_t counters[4];
+ uint8_t volume[4];
+ uint8_t output_state[4];
+ uint8_t noise_out;
+ uint8_t noise_use_tone;
+ uint8_t noise_type;
+ uint8_t latch;
+} psg_context;
+
+
+void psg_init(psg_context * context, uint32_t sample_rate, uint32_t clock_rate, uint32_t samples_frame);
+void psg_write(psg_context * context, uint8_t value);
+void psg_run(psg_context * context, uint32_t cycles);
+
+#endif //PSG_CONTEXT_H_
+
diff --git a/render.h b/render.h
index 55eebf3..d366ebb 100644
--- a/render.h
+++ b/render.h
@@ -2,11 +2,15 @@
#define RENDER_SDL_H_
#include "vdp.h"
-void render_init(int width, int height, char * title);
+#include "psg.h"
+void render_init(int width, int height, char * title, uint32_t fps);
void render_context(vdp_context * context);
void render_wait_quit(vdp_context * context);
+void render_wait_audio(psg_context * context);
int wait_render_frame(vdp_context * context, int frame_limit);
void render_fps(uint32_t fps);
+uint32_t render_audio_buffer();
+uint32_t render_sample_rate();
#endif //RENDER_SDL_H_
diff --git a/render_sdl.c b/render_sdl.c
index 3d342ed..3742be4 100644
--- a/render_sdl.c
+++ b/render_sdl.c
@@ -16,9 +16,41 @@ uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 2
uint32_t min_delay;
uint32_t frame_delay = 1000/60;
-void render_init(int width, int height, char * title)
+int16_t * current_audio = NULL;
+int16_t * next_audio = NULL;
+
+uint32_t buffer_samples, sample_rate;
+uint32_t missing_count;
+
+SDL_mutex * audio_mutex;
+SDL_cond * audio_ready;
+SDL_cond * audio_cond;
+
+void audio_callback(void * userdata, uint8_t *byte_stream, int len)
+{
+ //puts("audio_callback");
+ int16_t * stream = (int16_t *)byte_stream;
+ int samples = len/(sizeof(int16_t)*2);
+ int16_t * source_buf;
+
+ SDL_LockMutex(audio_mutex);
+ while (!current_audio) {
+ SDL_CondWait(audio_ready, audio_mutex);
+ }
+ source_buf = current_audio;
+ current_audio = NULL;
+ SDL_CondSignal(audio_cond);
+ SDL_UnlockMutex(audio_mutex);
+
+ for (int i = 0; i < samples; i++) {
+ *(stream++) = source_buf[i];
+ *(stream++) = source_buf[i];
+ }
+}
+
+void render_init(int width, int height, char * title, uint32_t fps)
{
- if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
exit(1);
}
@@ -64,6 +96,29 @@ void render_init(int width, int height, char * title)
min_delay = 1;
}
printf("minimum delay: %d\n", min_delay);
+
+ frame_delay = 1000/fps;
+
+ audio_mutex = SDL_CreateMutex();
+ audio_cond = SDL_CreateCond();
+ audio_ready = SDL_CreateCond();
+
+ SDL_AudioSpec desired, actual;
+ desired.freq = 48000;
+ desired.format = AUDIO_S16SYS;
+ desired.channels = 2;
+ desired.samples = 1024;
+ desired.callback = audio_callback;
+ desired.userdata = NULL;
+
+ if (SDL_OpenAudio(&desired, &actual) < 0) {
+ fprintf(stderr, "Unable to open SDL audio: %s\n", SDL_GetError());
+ exit(1);
+ }
+ buffer_samples = actual.samples;
+ sample_rate = actual.freq;
+ printf("Initialized audio at frequency %d with a %d sample buffer\n", actual.freq, actual.samples);
+ SDL_PauseAudio(0);
}
void render_context(vdp_context * context)
@@ -230,135 +285,141 @@ void render_wait_quit(vdp_context * context)
#define BUTTON_START 0x20
#define BUTTON_C 0x20
-uint32_t frame_counter = 0;
-uint32_t start = 0;
-int wait_render_frame(vdp_context * context, int frame_limit)
+int32_t handle_event(SDL_Event *event)
{
FILE * outfile;
- SDL_Event event;
- int ret = 0;
- while(SDL_PollEvent(&event)) {
- switch (event.type) {
- case SDL_KEYDOWN:
- switch(event.key.keysym.sym)
- {
- case SDLK_LEFTBRACKET:
- render_dbg++;
- if (render_dbg == 4) {
- render_dbg = 0;
- }
- break;
- case SDLK_RIGHTBRACKET:
- debug_pal++;
- if (debug_pal == 4) {
- debug_pal = 0;
- }
- break;
- case SDLK_t:
- outfile = fopen("state.gst", "wb");
- fwrite("GST\0\0\0\xE0\x40", 1, 8, outfile);
- vdp_save_state(context, outfile);
- fclose(outfile);
- puts("state saved to state.gst");
- break;
- case SDLK_u:
- ret = 1;
- break;
- case SDLK_RETURN:
- gamepad_1.input[GAMEPAD_TH0] |= BUTTON_START;
- break;
- case SDLK_UP:
- gamepad_1.input[GAMEPAD_TH0] |= DPAD_UP;
- gamepad_1.input[GAMEPAD_TH1] |= DPAD_UP;
- break;
- case SDLK_DOWN:
- gamepad_1.input[GAMEPAD_TH0] |= DPAD_DOWN;
- gamepad_1.input[GAMEPAD_TH1] |= DPAD_DOWN;
- break;
- case SDLK_LEFT:
- gamepad_1.input[GAMEPAD_TH1] |= DPAD_LEFT;
- break;
- case SDLK_RIGHT:
- gamepad_1.input[GAMEPAD_TH1] |= DPAD_RIGHT;
- break;
- case SDLK_a:
- gamepad_1.input[GAMEPAD_TH0] |= BUTTON_A;
- //printf("BUTTON_A Dn | GAMEPAD_TH0: %X\n", gamepad_1.input[GAMEPAD_TH0]);
- break;
- case SDLK_s:
- gamepad_1.input[GAMEPAD_TH1] |= BUTTON_B;
- gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_B;
- break;
- case SDLK_d:
- gamepad_1.input[GAMEPAD_TH1] |= BUTTON_C;
- gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_C;
- break;
- case SDLK_q:
- gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_X;
- break;
- case SDLK_w:
- gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_Y;
- break;
- case SDLK_e:
- gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_Z;
- break;
- case SDLK_f:
- gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_MODE;
- break;
+ switch (event->type) {
+ case SDL_KEYDOWN:
+ switch(event->key.keysym.sym)
+ {
+ case SDLK_LEFTBRACKET:
+ render_dbg++;
+ if (render_dbg == 4) {
+ render_dbg = 0;
}
break;
- case SDL_KEYUP:
- switch(event.key.keysym.sym)
- {
- case SDLK_RETURN:
- gamepad_1.input[GAMEPAD_TH0] &= ~BUTTON_START;
- break;
- case SDLK_UP:
- gamepad_1.input[GAMEPAD_TH0] &= ~DPAD_UP;
- gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_UP;
- break;
- case SDLK_DOWN:
- gamepad_1.input[GAMEPAD_TH0] &= ~DPAD_DOWN;
- gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_DOWN;
- break;
- case SDLK_LEFT:
- gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_LEFT;
- break;
- case SDLK_RIGHT:
- gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_RIGHT;
- break;
- case SDLK_a:
- gamepad_1.input[GAMEPAD_TH0] &= ~BUTTON_A;
- //printf("BUTTON_A Up | GAMEPAD_TH0: %X\n", gamepad_1.input[GAMEPAD_TH0]);
- break;
- case SDLK_s:
- gamepad_1.input[GAMEPAD_TH1] &= ~BUTTON_B;
- gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_B;
- break;
- case SDLK_d:
- gamepad_1.input[GAMEPAD_TH1] &= ~BUTTON_C;
- gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_C;
- break;
- case SDLK_q:
- gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_X;
- break;
- case SDLK_w:
- gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_Y;
- break;
- case SDLK_e:
- gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_Z;
- break;
- case SDLK_f:
- gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_MODE;
- break;
+ case SDLK_RIGHTBRACKET:
+ debug_pal++;
+ if (debug_pal == 4) {
+ debug_pal = 0;
}
break;
- case SDL_QUIT:
- puts("");
- exit(0);
+ case SDLK_t:
+ /*outfile = fopen("state.gst", "wb");
+ fwrite("GST\0\0\0\xE0\x40", 1, 8, outfile);
+ vdp_save_state(context, outfile);
+ fclose(outfile);
+ puts("state saved to state.gst");*/
+ break;
+ case SDLK_u:
+ return 1;
+ case SDLK_RETURN:
+ gamepad_1.input[GAMEPAD_TH0] |= BUTTON_START;
+ break;
+ case SDLK_UP:
+ gamepad_1.input[GAMEPAD_TH0] |= DPAD_UP;
+ gamepad_1.input[GAMEPAD_TH1] |= DPAD_UP;
+ break;
+ case SDLK_DOWN:
+ gamepad_1.input[GAMEPAD_TH0] |= DPAD_DOWN;
+ gamepad_1.input[GAMEPAD_TH1] |= DPAD_DOWN;
+ break;
+ case SDLK_LEFT:
+ gamepad_1.input[GAMEPAD_TH1] |= DPAD_LEFT;
+ break;
+ case SDLK_RIGHT:
+ gamepad_1.input[GAMEPAD_TH1] |= DPAD_RIGHT;
+ break;
+ case SDLK_a:
+ gamepad_1.input[GAMEPAD_TH0] |= BUTTON_A;
+ //printf("BUTTON_A Dn | GAMEPAD_TH0: %X\n", gamepad_1.input[GAMEPAD_TH0]);
+ break;
+ case SDLK_s:
+ gamepad_1.input[GAMEPAD_TH1] |= BUTTON_B;
+ gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_B;
+ break;
+ case SDLK_d:
+ gamepad_1.input[GAMEPAD_TH1] |= BUTTON_C;
+ gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_C;
+ break;
+ case SDLK_q:
+ gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_X;
+ break;
+ case SDLK_w:
+ gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_Y;
+ break;
+ case SDLK_e:
+ gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_Z;
+ break;
+ case SDLK_f:
+ gamepad_1.input[GAMEPAD_EXTRA] |= BUTTON_MODE;
+ break;
+ }
+ break;
+ case SDL_KEYUP:
+ switch(event->key.keysym.sym)
+ {
+ case SDLK_RETURN:
+ gamepad_1.input[GAMEPAD_TH0] &= ~BUTTON_START;
+ break;
+ case SDLK_UP:
+ gamepad_1.input[GAMEPAD_TH0] &= ~DPAD_UP;
+ gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_UP;
+ break;
+ case SDLK_DOWN:
+ gamepad_1.input[GAMEPAD_TH0] &= ~DPAD_DOWN;
+ gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_DOWN;
+ break;
+ case SDLK_LEFT:
+ gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_LEFT;
+ break;
+ case SDLK_RIGHT:
+ gamepad_1.input[GAMEPAD_TH1] &= ~DPAD_RIGHT;
+ break;
+ case SDLK_a:
+ gamepad_1.input[GAMEPAD_TH0] &= ~BUTTON_A;
+ //printf("BUTTON_A Up | GAMEPAD_TH0: %X\n", gamepad_1.input[GAMEPAD_TH0]);
+ break;
+ case SDLK_s:
+ gamepad_1.input[GAMEPAD_TH1] &= ~BUTTON_B;
+ gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_B;
+ break;
+ case SDLK_d:
+ gamepad_1.input[GAMEPAD_TH1] &= ~BUTTON_C;
+ gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_C;
+ break;
+ case SDLK_q:
+ gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_X;
+ break;
+ case SDLK_w:
+ gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_Y;
+ break;
+ case SDLK_e:
+ gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_Z;
+ break;
+ case SDLK_f:
+ gamepad_1.input[GAMEPAD_EXTRA] &= ~BUTTON_MODE;
+ break;
}
+ break;
+ case SDL_QUIT:
+ puts("");
+ exit(0);
+ }
+ return 0;
+}
+
+uint32_t frame_counter = 0;
+uint32_t start = 0;
+int wait_render_frame(vdp_context * context, int frame_limit)
+{
+ SDL_Event event;
+ int ret = 0;
+ while(SDL_PollEvent(&event)) {
+ ret = handle_event(&event);
}
if (frame_limit) {
+ puts("evil frame limit");
//TODO: Adjust frame delay so we actually get 60 FPS rather than 62.5 FPS
uint32_t current = SDL_GetTicks();
uint32_t desired = last_frame + frame_delay;
@@ -387,9 +448,34 @@ int wait_render_frame(vdp_context * context, int frame_limit)
return ret;
}
+void render_wait_audio(psg_context * context)
+{
+ SDL_LockMutex(audio_mutex);
+ while (current_audio != NULL) {
+ SDL_CondWait(audio_cond, audio_mutex);
+ }
+ current_audio = context->audio_buffer;
+ SDL_CondSignal(audio_ready);
+
+ context->audio_buffer = context->back_buffer;
+ context->back_buffer = current_audio;
+ SDL_UnlockMutex(audio_mutex);
+ context->buffer_pos = 0;
+}
+
void render_fps(uint32_t fps)
{
frame_delay = 1000/fps;
}
+uint32_t render_audio_buffer()
+{
+ return buffer_samples;
+}
+
+uint32_t render_sample_rate()
+{
+ return sample_rate;
+}
+