Broken WIP
This commit is contained in:
parent
5d68673843
commit
3b4f81ca78
4
Makefile
4
Makefile
@ -83,8 +83,8 @@ endif
|
||||
|
||||
CFLAGS += -Werror -Wall -Wno-unused-result -Wno-strict-aliasing -Wno-unknown-warning -Wno-unknown-warning-option -Wno-multichar -Wno-int-in-bool-context -std=gnu11 -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES
|
||||
SDL_LDFLAGS := -lSDL2 -lGL
|
||||
GTK3_CFLAGS := `pkg-config --cflags gio-2.0 gtk+-3.0 epoxy` -DGTK_DISABLE_DEPRECATED=1 -DG_DISABLE_DEPRECATED=1 -DRESOURCE_PREFIX=\"/io/github/sameboy/\" -DAPP_ID=\"io.github.sameboy\"
|
||||
GTK3_LDFLAGS := `pkg-config --libs gio-2.0 gtk+-3.0 epoxy`
|
||||
GTK3_CFLAGS := `pkg-config --cflags gio-2.0 gtk+-3.0 epoxy openal` -DGTK_DISABLE_DEPRECATED=1 -DG_DISABLE_DEPRECATED=1 -DRESOURCE_PREFIX=\"/io/github/sameboy/\" -DAPP_ID=\"io.github.sameboy\"
|
||||
GTK3_LDFLAGS := `pkg-config --libs gio-2.0 gtk+-3.0 epoxy openal`
|
||||
|
||||
# TODO: REMOVE DISABLE UNUSED WARNINGS
|
||||
GTK3_CFLAGS += -Wno-unused
|
||||
|
117
gtk3/main.c
117
gtk3/main.c
@ -1,5 +1,11 @@
|
||||
#include "main.h"
|
||||
|
||||
static ALCdevice *al_device;
|
||||
static ALCcontext *al_context;
|
||||
static ALuint al_source;
|
||||
static ALuint al_buffer[96000*2];
|
||||
static ALuint next_buffer = 0;
|
||||
|
||||
static GtkApplication *main_application;
|
||||
static GtkBuilder *builder;
|
||||
static GtkGLArea *gl_area;
|
||||
@ -199,6 +205,69 @@ void gl_check_realize(GtkWidget *w, gpointer user_data_gptr) {
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_audio() {
|
||||
#define RETURN_IF_AL_ERROR(msg) { \
|
||||
GError *error = openal_error(msg); \
|
||||
if (error) { \
|
||||
g_printerr("OpenAL: (%d) %s\n", error->code, error->message); \
|
||||
g_clear_error(&error); \
|
||||
return; \
|
||||
} \
|
||||
}
|
||||
|
||||
al_device = alcOpenDevice(NULL);
|
||||
|
||||
if (!al_device) RETURN_IF_AL_ERROR("Failed to open device")
|
||||
|
||||
al_context = alcCreateContext(al_device, NULL);
|
||||
|
||||
if (!alcMakeContextCurrent(al_context)) RETURN_IF_AL_ERROR("Failed to create context")
|
||||
|
||||
alGenSources((ALuint)1, &al_source);
|
||||
RETURN_IF_AL_ERROR(NULL)
|
||||
|
||||
alSourcef(al_source, AL_PITCH, 1);
|
||||
RETURN_IF_AL_ERROR(NULL)
|
||||
|
||||
alSourcef(al_source, AL_GAIN, 1);
|
||||
RETURN_IF_AL_ERROR(NULL)
|
||||
|
||||
alSource3f(al_source, AL_POSITION, 0, 0, 0);
|
||||
RETURN_IF_AL_ERROR(NULL)
|
||||
|
||||
alSource3f(al_source, AL_VELOCITY, 0, 0, 0);
|
||||
RETURN_IF_AL_ERROR(NULL)
|
||||
|
||||
alSourcei(al_source, AL_LOOPING, AL_FALSE);
|
||||
RETURN_IF_AL_ERROR(NULL)
|
||||
|
||||
alSourcei(al_source, AL_SOURCE_TYPE, AL_STREAMING);
|
||||
RETURN_IF_AL_ERROR(NULL)
|
||||
|
||||
alGenBuffers((ALuint)96000*2, al_buffer);
|
||||
RETURN_IF_AL_ERROR("Failed to create audio buffer")
|
||||
}
|
||||
|
||||
static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample) {
|
||||
alBufferData(al_buffer[next_buffer], AL_FORMAT_STEREO16, sample, 4, 96000);
|
||||
|
||||
GError *error = openal_error("alBufferData");
|
||||
if (error) {
|
||||
g_printerr("OpenAL: (%d) %s\n", error->code, error->message);
|
||||
g_clear_error(&error);
|
||||
}
|
||||
|
||||
alSourceQueueBuffers(al_source, 1, &al_buffer[next_buffer]);
|
||||
|
||||
error = openal_error("alSourceQueueBuffers");
|
||||
if (error) {
|
||||
g_printerr("OpenAL: (%d) %s\n", error->code, error->message);
|
||||
g_clear_error(&error);
|
||||
}
|
||||
|
||||
next_buffer = (next_buffer + 1) % (96000*2);
|
||||
}
|
||||
|
||||
// Returns a `GApplication`s `GMenuModel` by ID
|
||||
// GApplication menus are loaded from `gtk/menus.ui`, `gtk/menus-traditional.ui` and `gtk/menus-common.ui`.
|
||||
static GMenuModel *get_menu_model(GApplication *app, const char *id) {
|
||||
@ -499,6 +568,8 @@ static void activate(GApplication *app, gpointer user_data_gptr) {
|
||||
gtk_application_add_window(GTK_APPLICATION(app), GTK_WINDOW(main_window));
|
||||
gtk_widget_show_all(GTK_WIDGET(main_window));
|
||||
|
||||
setup_audio();
|
||||
|
||||
g_thread_new("CoreLoop", run, user_data);
|
||||
}
|
||||
|
||||
@ -508,6 +579,13 @@ static void shutdown(GApplication *app, GFile **files, gint n_files, const gchar
|
||||
|
||||
save_settings();
|
||||
free_settings();
|
||||
|
||||
alDeleteSources(1, &al_source);
|
||||
alDeleteBuffers(96000*2, al_buffer);
|
||||
al_device = alcGetContextsDevice(al_context);
|
||||
alcMakeContextCurrent(NULL);
|
||||
alcDestroyContext(al_context);
|
||||
alcCloseDevice(al_device);
|
||||
}
|
||||
|
||||
// This function gets called when there are files to open.
|
||||
@ -1347,6 +1425,37 @@ static void vblank(GB_gameboy_t *gb) {
|
||||
g_idle_add((GSourceFunc) on_vblank, NULL);
|
||||
}
|
||||
|
||||
static gpointer openal_run(gpointer user_data_gptr) {
|
||||
GMutex audio_mutex;
|
||||
GCond audio_cond;
|
||||
g_cond_init(&audio_cond);
|
||||
g_mutex_init(&audio_mutex);
|
||||
g_mutex_lock(&audio_mutex);
|
||||
|
||||
gboolean play_audio = true;
|
||||
|
||||
while (play_audio) {
|
||||
ALint processed;
|
||||
alGetSourcei(al_source, AL_BUFFERS_PROCESSED, &processed);
|
||||
|
||||
ALint state;
|
||||
alGetSourcei(al_source, AL_SOURCE_STATE, &state);
|
||||
if (state != AL_PLAYING) {
|
||||
alSourcePlay(al_source);
|
||||
}
|
||||
|
||||
ALuint x = 0;
|
||||
while (processed--) {
|
||||
alSourceUnqueueBuffers(al_source, 1, &x);
|
||||
}
|
||||
|
||||
gint64 end_time = g_get_monotonic_time() + 1 * G_TIME_SPAN_MILLISECOND;
|
||||
g_cond_wait_until(&audio_cond, &audio_mutex, end_time);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gpointer run(gpointer user_data_gptr) {
|
||||
UserData *user_data = user_data_gptr;
|
||||
|
||||
@ -1372,12 +1481,12 @@ static gpointer run(gpointer user_data_gptr) {
|
||||
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||
GB_set_pixels_output(&gb, get_current_buffer());
|
||||
GB_set_rgb_encode_callback(&gb, rgb_encode);
|
||||
// GB_set_sample_rate(&gb, have_aspec.freq);
|
||||
GB_set_sample_rate(&gb, 96000);
|
||||
GB_set_color_correction_mode(&gb, get_color_correction_mode());
|
||||
GB_set_highpass_filter_mode(&gb, get_highpass_mode());
|
||||
GB_set_rewind_length(&gb, config.rewind_duration);
|
||||
GB_set_update_input_hint_callback(&gb, handle_events);
|
||||
// GB_apu_set_sample_callback(&gb, gb_audio_callback);
|
||||
GB_apu_set_sample_callback(&gb, gb_audio_callback);
|
||||
}
|
||||
|
||||
GError *error;
|
||||
@ -1446,6 +1555,10 @@ static gpointer run(gpointer user_data_gptr) {
|
||||
}
|
||||
|
||||
if (user_data->file != NULL && GB_load_rom(&gb, g_file_get_path(user_data->file)) == 0) {
|
||||
alSourcePlay(al_source);
|
||||
|
||||
g_thread_new("OpenAL", openal_run, NULL);
|
||||
|
||||
/* Run emulation */
|
||||
while (running) {
|
||||
if (paused || rewind_paused) {
|
||||
|
45
gtk3/main.h
45
gtk3/main.h
@ -1,6 +1,8 @@
|
||||
#ifndef main_h
|
||||
#define main_h
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <epoxy/gl.h>
|
||||
#include <signal.h>
|
||||
@ -13,6 +15,47 @@
|
||||
#include "settings.h"
|
||||
#include "shader.h"
|
||||
|
||||
#define OPENAL_ERROR openal_error_quark()
|
||||
|
||||
GQuark openal_error_quark (void) {
|
||||
return g_quark_from_static_string("openal-error-quark");
|
||||
}
|
||||
|
||||
GError *openal_error(const gchar *user_msg) {
|
||||
ALCenum error = alGetError();
|
||||
gchar *description;
|
||||
gchar *msg;
|
||||
|
||||
switch (error) {
|
||||
case AL_NO_ERROR:
|
||||
return NULL;
|
||||
case AL_INVALID_NAME:
|
||||
description = "A bad name (ID) was passed to an OpenAL function";
|
||||
break;
|
||||
case AL_INVALID_ENUM:
|
||||
description = "An invalid enum value was passed to an OpenAL function";
|
||||
break;
|
||||
case AL_INVALID_VALUE:
|
||||
description = "An invalid value was passed to an OpenAL function";
|
||||
break;
|
||||
case AL_INVALID_OPERATION:
|
||||
description = "The requested operation is not valid";
|
||||
break;
|
||||
case AL_OUT_OF_MEMORY:
|
||||
description = "The requested operation resulted in OpenAL running out of memory";
|
||||
break;
|
||||
}
|
||||
|
||||
if (user_msg != NULL) {
|
||||
msg = g_strdup_printf("%s: %s", user_msg, description);
|
||||
}
|
||||
else {
|
||||
msg = description;
|
||||
}
|
||||
|
||||
return g_error_new_literal(OPENAL_ERROR, error, msg);
|
||||
}
|
||||
|
||||
typedef struct UserData {
|
||||
bool fullscreen;
|
||||
GFile *file;
|
||||
@ -43,6 +86,8 @@ static gint handle_local_options(GApplication *app, GVariantDict *options, gpoin
|
||||
void gl_check_realize(GtkWidget *w, gpointer user_data_gptr);
|
||||
gboolean test_gl_support(void);
|
||||
|
||||
static void setup_audio();
|
||||
|
||||
static GMenuModel *get_menu_model(GApplication *app, const char *id);
|
||||
static void create_fallback_canvas(void);
|
||||
static void setup_menu(GApplication *app);
|
||||
|
Loading…
Reference in New Issue
Block a user