Broken WIP

This commit is contained in:
Maximilian Mader 2019-10-06 01:13:45 +02:00
parent 5d68673843
commit 3b4f81ca78
Signed by: Max
GPG Key ID: F71D56A3151C4FB3
3 changed files with 162 additions and 4 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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);