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
|
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
|
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_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`
|
GTK3_LDFLAGS := `pkg-config --libs gio-2.0 gtk+-3.0 epoxy openal`
|
||||||
|
|
||||||
# TODO: REMOVE DISABLE UNUSED WARNINGS
|
# TODO: REMOVE DISABLE UNUSED WARNINGS
|
||||||
GTK3_CFLAGS += -Wno-unused
|
GTK3_CFLAGS += -Wno-unused
|
||||||
|
117
gtk3/main.c
117
gtk3/main.c
@ -1,5 +1,11 @@
|
|||||||
#include "main.h"
|
#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 GtkApplication *main_application;
|
||||||
static GtkBuilder *builder;
|
static GtkBuilder *builder;
|
||||||
static GtkGLArea *gl_area;
|
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
|
// Returns a `GApplication`s `GMenuModel` by ID
|
||||||
// GApplication menus are loaded from `gtk/menus.ui`, `gtk/menus-traditional.ui` and `gtk/menus-common.ui`.
|
// 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) {
|
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_application_add_window(GTK_APPLICATION(app), GTK_WINDOW(main_window));
|
||||||
gtk_widget_show_all(GTK_WIDGET(main_window));
|
gtk_widget_show_all(GTK_WIDGET(main_window));
|
||||||
|
|
||||||
|
setup_audio();
|
||||||
|
|
||||||
g_thread_new("CoreLoop", run, user_data);
|
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();
|
save_settings();
|
||||||
free_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.
|
// 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);
|
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) {
|
static gpointer run(gpointer user_data_gptr) {
|
||||||
UserData *user_data = 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_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||||
GB_set_pixels_output(&gb, get_current_buffer());
|
GB_set_pixels_output(&gb, get_current_buffer());
|
||||||
GB_set_rgb_encode_callback(&gb, rgb_encode);
|
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_color_correction_mode(&gb, get_color_correction_mode());
|
||||||
GB_set_highpass_filter_mode(&gb, get_highpass_mode());
|
GB_set_highpass_filter_mode(&gb, get_highpass_mode());
|
||||||
GB_set_rewind_length(&gb, config.rewind_duration);
|
GB_set_rewind_length(&gb, config.rewind_duration);
|
||||||
GB_set_update_input_hint_callback(&gb, handle_events);
|
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;
|
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) {
|
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 */
|
/* Run emulation */
|
||||||
while (running) {
|
while (running) {
|
||||||
if (paused || rewind_paused) {
|
if (paused || rewind_paused) {
|
||||||
|
45
gtk3/main.h
45
gtk3/main.h
@ -1,6 +1,8 @@
|
|||||||
#ifndef main_h
|
#ifndef main_h
|
||||||
#define main_h
|
#define main_h
|
||||||
|
|
||||||
|
#include <AL/al.h>
|
||||||
|
#include <AL/alc.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <epoxy/gl.h>
|
#include <epoxy/gl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@ -13,6 +15,47 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "shader.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 {
|
typedef struct UserData {
|
||||||
bool fullscreen;
|
bool fullscreen;
|
||||||
GFile *file;
|
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);
|
void gl_check_realize(GtkWidget *w, gpointer user_data_gptr);
|
||||||
gboolean test_gl_support(void);
|
gboolean test_gl_support(void);
|
||||||
|
|
||||||
|
static void setup_audio();
|
||||||
|
|
||||||
static GMenuModel *get_menu_model(GApplication *app, const char *id);
|
static GMenuModel *get_menu_model(GApplication *app, const char *id);
|
||||||
static void create_fallback_canvas(void);
|
static void create_fallback_canvas(void);
|
||||||
static void setup_menu(GApplication *app);
|
static void setup_menu(GApplication *app);
|
||||||
|
Loading…
Reference in New Issue
Block a user