mirror of
https://github.com/libretro/RetroArch
synced 2025-02-22 12:40:09 +00:00
Merge branch 'master' into ownconf
Conflicts: config.mk
This commit is contained in:
commit
26654f7645
6
Makefile
6
Makefile
@ -16,6 +16,10 @@ ifeq ($(BUILD_ALSA), 1)
|
||||
OBJ += alsa.o
|
||||
LIBS += -lasound
|
||||
endif
|
||||
ifeq ($(BUILD_ROAR), 1)
|
||||
OBJ += roar.o
|
||||
LIBS += -lroar
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_OPENGL), 1)
|
||||
OBJ += gl.o
|
||||
@ -25,7 +29,7 @@ ifeq ($(BUILD_FILTER), 1)
|
||||
OBJ += hqflt/hq.o
|
||||
endif
|
||||
|
||||
CFLAGS = -Wall -O3 -march=native -std=c99
|
||||
CFLAGS = -Wall -O3 -march=native -std=gnu99
|
||||
|
||||
|
||||
|
||||
|
16
alsa.c
16
alsa.c
@ -27,6 +27,7 @@
|
||||
typedef struct alsa
|
||||
{
|
||||
snd_pcm_t *pcm;
|
||||
bool nonblock;
|
||||
} alsa_t;
|
||||
|
||||
static void* __alsa_init(const char* device, int rate, int latency)
|
||||
@ -125,7 +126,8 @@ static ssize_t __alsa_write(void* data, const void* buf, size_t size)
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
else if ( alsa->nonblock && frames == -EAGAIN )
|
||||
return 0;
|
||||
else if ( frames < 0 )
|
||||
return -1;
|
||||
|
||||
@ -134,11 +136,18 @@ static ssize_t __alsa_write(void* data, const void* buf, size_t size)
|
||||
|
||||
static bool __alsa_stop(void *data)
|
||||
{
|
||||
/* int *fd = data;
|
||||
ioctl(*fd, SNDCTL_DSP_RESET, 0);*/
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __alsa_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
alsa_t *alsa = data;
|
||||
if (snd_pcm_nonblock(alsa->pcm, state) < 0)
|
||||
fprintf(stderr, "SSNES [ERROR]: Could not set PCM to non-blocking. Will not be able to fast-forward.\n");
|
||||
else
|
||||
alsa->nonblock = state;
|
||||
}
|
||||
|
||||
static bool __alsa_start(void *data)
|
||||
{
|
||||
return true;
|
||||
@ -163,6 +172,7 @@ const audio_driver_t audio_alsa = {
|
||||
.write = __alsa_write,
|
||||
.stop = __alsa_stop,
|
||||
.start = __alsa_start,
|
||||
.set_nonblock_state = __alsa_set_nonblock_state,
|
||||
.free = __alsa_free
|
||||
};
|
||||
|
||||
|
4
config.h
4
config.h
@ -35,6 +35,7 @@
|
||||
#define AUDIO_RSOUND 1
|
||||
#define AUDIO_OSS 2
|
||||
#define AUDIO_ALSA 3
|
||||
#define AUDIO_ROAR 4
|
||||
////////////////////////
|
||||
|
||||
// Chooses which video and audio subsystem to use. Remember to update config.mk if you change these.
|
||||
@ -92,7 +93,7 @@ static const char* audio_device = NULL;
|
||||
static const int out_latency = 64;
|
||||
|
||||
// Defines the quality (and cpu reqirements) of samplerate conversion.
|
||||
#define SAMPLERATE_QUALITY SRC_SINC_FASTEST
|
||||
#define SAMPLERATE_QUALITY SRC_LINEAR
|
||||
|
||||
|
||||
|
||||
@ -117,6 +118,7 @@ static const struct snes_keybind snes_keybinds[] = {
|
||||
{ SNES_DEVICE_ID_JOYPAD_DOWN, GLFW_KEY_DOWN, 11 },
|
||||
{ SNES_DEVICE_ID_JOYPAD_START, GLFW_KEY_ENTER, 6 },
|
||||
{ SNES_DEVICE_ID_JOYPAD_SELECT, GLFW_KEY_RSHIFT, 14 },
|
||||
{ SNES_FAST_FORWARD_KEY, GLFW_KEY_SPACE, 9 },
|
||||
{ -1 }
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@ BUILD_FILTER = 0
|
||||
BUILD_RSOUND = 1
|
||||
BUILD_OSS = 0
|
||||
BUILD_ALSA = 0
|
||||
BUILD_ROAR = 0
|
||||
|
||||
|
||||
PREFIX = /usr
|
||||
|
5
driver.h
5
driver.h
@ -24,6 +24,9 @@
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define SNES_FAST_FORWARD_KEY 0x666 // Hurr, durr
|
||||
void set_fast_forward_button(bool state);
|
||||
|
||||
struct snes_keybind
|
||||
{
|
||||
int id;
|
||||
@ -48,6 +51,7 @@ typedef struct audio_driver
|
||||
ssize_t (*write)(void* data, const void* buf, size_t size);
|
||||
bool (*stop)(void* data);
|
||||
bool (*start)(void* data);
|
||||
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about blocking in audio thread? Fast forwarding.
|
||||
void (*free)(void* data);
|
||||
} audio_driver_t;
|
||||
|
||||
@ -64,6 +68,7 @@ typedef struct video_driver
|
||||
void* (*init)(video_info_t *video, const input_driver_t **input);
|
||||
// Should the video driver act as an input driver as well? :)
|
||||
bool (*frame)(void* data, const uint16_t* frame, int width, int height);
|
||||
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about syncing to vblank? Fast forwarding.
|
||||
void (*free)(void* data);
|
||||
} video_driver_t;
|
||||
|
||||
|
71
gl.c
71
gl.c
@ -21,6 +21,7 @@
|
||||
#include <stdint.h>
|
||||
#include "libsnes.hpp"
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static GLuint texture;
|
||||
static uint8_t *gl_buffer;
|
||||
@ -29,7 +30,7 @@ static GLuint tex_filter;
|
||||
|
||||
typedef struct gl
|
||||
{
|
||||
int foo;
|
||||
bool vsync;
|
||||
} gl_t;
|
||||
|
||||
|
||||
@ -68,11 +69,26 @@ static int16_t glfw_input_state(void *data, const struct snes_keybind *snes_keyb
|
||||
glfwGetJoystickButtons(joypad_id, buttons, joypad_buttons);
|
||||
}
|
||||
|
||||
// Finds fast forwarding state.
|
||||
for ( i = 0; snes_keybinds[i].id != -1; i++ )
|
||||
{
|
||||
if ( snes_keybinds[i].id == SNES_FAST_FORWARD_KEY )
|
||||
{
|
||||
bool pressed = false;
|
||||
if ( glfwGetKey(snes_keybinds[i].key) )
|
||||
pressed = true;
|
||||
else if ( snes_keybinds[i].joykey < joypad_buttons && buttons[snes_keybinds[i].joykey] == GLFW_PRESS )
|
||||
pressed = true;
|
||||
set_fast_forward_button(pressed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 0; snes_keybinds[i].id != -1; i++ )
|
||||
{
|
||||
if ( snes_keybinds[i].id == (int)id )
|
||||
{
|
||||
if ( glfwGetKey(snes_keybinds[i].key ))
|
||||
if ( glfwGetKey(snes_keybinds[i].key) )
|
||||
return 1;
|
||||
|
||||
if ( snes_keybinds[i].joykey < joypad_buttons && buttons[snes_keybinds[i].joykey] == GLFW_PRESS )
|
||||
@ -128,6 +144,12 @@ static void GLFWCALL resize(int width, int height)
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
static float tv_to_fps(const struct timeval *tv, const struct timeval *new_tv, int frames)
|
||||
{
|
||||
float time = new_tv->tv_sec - tv->tv_sec + (new_tv->tv_usec - tv->tv_usec)/1000000.0;
|
||||
return frames/time;
|
||||
}
|
||||
|
||||
static bool gl_frame(void *data, const uint16_t* frame, int width, int height)
|
||||
{
|
||||
(void)data;
|
||||
@ -160,6 +182,31 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height)
|
||||
|
||||
glEnd();
|
||||
|
||||
// Shows FPS in taskbar.
|
||||
static int frames = 0;
|
||||
static struct timeval tv;
|
||||
struct timeval new_tv;
|
||||
|
||||
if (frames == 0)
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
if ((frames % 60) == 0 && frames > 0)
|
||||
{
|
||||
gettimeofday(&new_tv, NULL);
|
||||
struct timeval tmp_tv = {
|
||||
.tv_sec = tv.tv_sec,
|
||||
.tv_usec = tv.tv_usec
|
||||
};
|
||||
gettimeofday(&tv, NULL);
|
||||
char tmpstr[256] = {0};
|
||||
|
||||
float fps = tv_to_fps(&tmp_tv, &new_tv, 60);
|
||||
|
||||
snprintf(tmpstr, sizeof(tmpstr) - 1, "SSNES || FPS: %6.1f || Frames: %d", fps, frames);
|
||||
glfwSetWindowTitle(tmpstr);
|
||||
}
|
||||
frames++;
|
||||
|
||||
glfwSwapBuffers();
|
||||
|
||||
return true;
|
||||
@ -171,10 +218,22 @@ static void gl_free(void *data)
|
||||
free(gl_buffer);
|
||||
}
|
||||
|
||||
static void gl_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
gl_t *gl = data;
|
||||
if (gl->vsync)
|
||||
{
|
||||
if (state)
|
||||
glfwSwapInterval(0);
|
||||
else
|
||||
glfwSwapInterval(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void* gl_init(video_info_t *video, const input_driver_t **input)
|
||||
{
|
||||
gl_t *foo = malloc(sizeof(gl_t));
|
||||
if ( foo == NULL )
|
||||
gl_t *gl = malloc(sizeof(gl_t));
|
||||
if ( gl == NULL )
|
||||
return NULL;
|
||||
|
||||
keep_aspect = video->force_aspect;
|
||||
@ -200,6 +259,7 @@ static void* gl_init(video_info_t *video, const input_driver_t **input)
|
||||
glfwSwapInterval(1); // Force vsync
|
||||
else
|
||||
glfwSwapInterval(0);
|
||||
gl->vsync = video->vsync;
|
||||
|
||||
gl_buffer = malloc(256 * 256 * 2 * video->input_scale * video->input_scale);
|
||||
if ( !gl_buffer )
|
||||
@ -225,12 +285,13 @@ static void* gl_init(video_info_t *video, const input_driver_t **input)
|
||||
GL_UNSIGNED_SHORT_1_5_5_5_REV, gl_buffer);
|
||||
|
||||
*input = &input_glfw;
|
||||
return foo;
|
||||
return gl;
|
||||
}
|
||||
|
||||
const video_driver_t video_gl = {
|
||||
.init = gl_init,
|
||||
.frame = gl_frame,
|
||||
.set_nonblock_state = gl_set_nonblock_state,
|
||||
.free = gl_free
|
||||
};
|
||||
|
||||
|
19
oss.c
19
oss.c
@ -22,6 +22,8 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void* __oss_init(const char* device, int rate, int latency)
|
||||
{
|
||||
@ -86,7 +88,11 @@ static ssize_t __oss_write(void* data, const void* buf, size_t size)
|
||||
|
||||
ssize_t ret;
|
||||
if ( (ret = write(*fd, buf, size)) <= 0 )
|
||||
{
|
||||
if ( (fcntl(*fd, F_GETFL) & O_NONBLOCK) && errno == EAGAIN )
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -103,6 +109,18 @@ static bool __oss_start(void *data)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __oss_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
int *fd = data;
|
||||
int rc;
|
||||
if (state)
|
||||
rc = fcntl(*fd, F_SETFL, fcntl(*fd, F_GETFL) | O_NONBLOCK);
|
||||
else
|
||||
rc = fcntl(*fd, F_SETFL, fcntl(*fd, F_GETFL) & (~O_NONBLOCK));
|
||||
if (rc != 0)
|
||||
fprintf(stderr, "SSNES [ERROR]: Could not set nonblocking on OSS file descriptor. Will not be able to fast-forward.\n");
|
||||
}
|
||||
|
||||
static void __oss_free(void *data)
|
||||
{
|
||||
int *fd = data;
|
||||
@ -117,6 +135,7 @@ const audio_driver_t audio_oss = {
|
||||
.write = __oss_write,
|
||||
.stop = __oss_stop,
|
||||
.start = __oss_start,
|
||||
.set_nonblock_state = __oss_set_nonblock_state,
|
||||
.free = __oss_free
|
||||
};
|
||||
|
||||
|
92
roar.c
Normal file
92
roar.c
Normal file
@ -0,0 +1,92 @@
|
||||
/* SSNES - A Super Ninteno Entertainment System (SNES) Emulator frontend for libsnes.
|
||||
* Copyright (C) 2010 - Hans-Kristian Arntzen
|
||||
*
|
||||
* Some code herein may be based on code found in BSNES.
|
||||
*
|
||||
* SSNES is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with SSNES.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "driver.h"
|
||||
#include <stdlib.h>
|
||||
#include <roaraudio.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void* __roar_init(const char* device, int rate, int latency)
|
||||
{
|
||||
int err;
|
||||
roar_vs_t *vss;
|
||||
if ( (vss = roar_vs_new_simple(NULL, NULL, rate, 2, ROAR_CODEC_PCM_S_LE, 16, ROAR_DIR_PLAY, &err)) == NULL )
|
||||
{
|
||||
fprintf(stderr, "roar_vs: \"%s\"\n", roar_vs_strerr(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vss;
|
||||
}
|
||||
|
||||
static ssize_t __roar_write(void* data, const void* buf, size_t size)
|
||||
{
|
||||
roar_vs_t *vss = data;
|
||||
|
||||
if ( size == 0 )
|
||||
return 0;
|
||||
|
||||
int err;
|
||||
if (roar_vs_write(vss, buf, size, &err) < 0)
|
||||
{
|
||||
if (err == ROAR_ERROR_NONE)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static bool __roar_stop(void *data)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __roar_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
roar_vs_t *vss = data;
|
||||
if (roar_vs_blocking(vss, (state) ? ROAR_VS_FALSE : ROAR_VS_TRUE, NULL) < 0)
|
||||
fprintf(stderr, "SSNES [ERROR]: Can't set nonblocking. Will not be able to fast-forward.\n");
|
||||
}
|
||||
|
||||
static bool __roar_start(void *data)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __roar_free(void *data)
|
||||
{
|
||||
roar_vs_t *vss = data;
|
||||
roar_vs_close(vss, ROAR_VS_TRUE, NULL);
|
||||
}
|
||||
|
||||
const audio_driver_t audio_roar = {
|
||||
.init = __roar_init,
|
||||
.write = __roar_write,
|
||||
.stop = __roar_stop,
|
||||
.start = __roar_start,
|
||||
.set_nonblock_state = __roar_set_nonblock_state,
|
||||
.free = __roar_free
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
11
rsound.c
11
rsound.c
@ -25,6 +25,7 @@ typedef struct rsd
|
||||
rsound_t *rd;
|
||||
int latency;
|
||||
int rate;
|
||||
int nonblock;
|
||||
} rsd_t;
|
||||
|
||||
static void* __rsd_init(const char* device, int rate, int latency)
|
||||
@ -74,6 +75,9 @@ static ssize_t __rsd_write(void* data, const void* buf, size_t size)
|
||||
{
|
||||
rsd_t *rsd = data;
|
||||
|
||||
if ( rsd_delay_ms(rsd->rd) > rsd->latency && rsd->nonblock )
|
||||
return 0;
|
||||
|
||||
if ( size == 0 )
|
||||
return 0;
|
||||
|
||||
@ -101,6 +105,12 @@ static bool __rsd_stop(void *data)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __rsd_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
rsd_t *rsd = data;
|
||||
rsd->nonblock = state;
|
||||
}
|
||||
|
||||
static bool __rsd_start(void *data)
|
||||
{
|
||||
rsd_t *rsd = data;
|
||||
@ -124,6 +134,7 @@ const audio_driver_t audio_rsound = {
|
||||
.write = __rsd_write,
|
||||
.stop = __rsd_stop,
|
||||
.start = __rsd_start,
|
||||
.set_nonblock_state = __rsd_set_nonblock_state,
|
||||
.free = __rsd_free
|
||||
};
|
||||
|
||||
|
43
ssnes.c
43
ssnes.c
@ -36,6 +36,7 @@ static SRC_STATE* source = NULL;
|
||||
extern const audio_driver_t audio_rsound;
|
||||
extern const audio_driver_t audio_oss;
|
||||
extern const audio_driver_t audio_alsa;
|
||||
extern const audio_driver_t audio_roar;
|
||||
extern const video_driver_t video_gl;
|
||||
////////////////////////////////////////////////
|
||||
|
||||
@ -52,6 +53,8 @@ static driver_t driver = {
|
||||
.audio = &audio_oss,
|
||||
#elif AUDIO_DRIVER == AUDIO_ALSA
|
||||
.audio = &audio_alsa,
|
||||
#elif AUDIO_DRIVER == AUDIO_ROAR
|
||||
.audio = &audio_roar,
|
||||
#else
|
||||
#error "Define a valid audio driver in config.h"
|
||||
#endif
|
||||
@ -70,6 +73,29 @@ static void write_file(const char* path, uint8_t* data, size_t size);
|
||||
static void load_save_file(const char* path, int type);
|
||||
static void save_file(const char* path, int type);
|
||||
|
||||
|
||||
// To avoid continous switching if we hold the button down, we require that the button must go from pressed, unpressed back to pressed to be able to toggle between then.
|
||||
|
||||
#define AUDIO_CHUNK_SIZE_BLOCKING 64
|
||||
#define AUDIO_CHUNK_SIZE_NONBLOCKING 1024 // So we don't get complete line-noise when fast-forwarding audio.
|
||||
static size_t audio_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING;
|
||||
void set_fast_forward_button(bool new_button_state)
|
||||
{
|
||||
static bool old_button_state = false;
|
||||
static bool syncing_state = false;
|
||||
if (new_button_state && !old_button_state)
|
||||
{
|
||||
syncing_state = !syncing_state;
|
||||
driver.video->set_nonblock_state(driver.video_data, syncing_state);
|
||||
driver.audio->set_nonblock_state(driver.audio_data, syncing_state);
|
||||
if (syncing_state)
|
||||
audio_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING;
|
||||
else
|
||||
audio_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING;
|
||||
}
|
||||
old_button_state = new_button_state;
|
||||
}
|
||||
|
||||
static void init_drivers(void)
|
||||
{
|
||||
init_video_input();
|
||||
@ -197,30 +223,28 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
|
||||
|
||||
}
|
||||
|
||||
#define SRC_SAMPLES 64
|
||||
|
||||
static void audio_sample(uint16_t left, uint16_t right)
|
||||
{
|
||||
if ( !audio_active )
|
||||
return;
|
||||
|
||||
static float data[SRC_SAMPLES];
|
||||
static float data[AUDIO_CHUNK_SIZE_NONBLOCKING];
|
||||
static int data_ptr = 0;
|
||||
|
||||
data[data_ptr++] = (float)(*(int16_t*)&left)/0x7FFF;
|
||||
data[data_ptr++] = (float)(*(int16_t*)&right)/0x7FFF;
|
||||
|
||||
if ( data_ptr == SRC_SAMPLES )
|
||||
if ( data_ptr >= audio_chunk_size )
|
||||
{
|
||||
float outsamples[SRC_SAMPLES * 16];
|
||||
int16_t temp_outsamples[SRC_SAMPLES * 16];
|
||||
float outsamples[audio_chunk_size * 16];
|
||||
int16_t temp_outsamples[audio_chunk_size * 16];
|
||||
|
||||
SRC_DATA src_data;
|
||||
|
||||
src_data.data_in = data;
|
||||
src_data.data_out = outsamples;
|
||||
src_data.input_frames = SRC_SAMPLES / 2;
|
||||
src_data.output_frames = SRC_SAMPLES * 8;
|
||||
src_data.input_frames = audio_chunk_size / 2;
|
||||
src_data.output_frames = audio_chunk_size * 8;
|
||||
src_data.end_of_input = 0;
|
||||
src_data.src_ratio = (double)out_rate / (double)in_rate;
|
||||
|
||||
@ -229,7 +253,10 @@ static void audio_sample(uint16_t left, uint16_t right)
|
||||
src_float_to_short_array(outsamples, temp_outsamples, src_data.output_frames_gen * 2);
|
||||
|
||||
if ( driver.audio->write(driver.audio_data, temp_outsamples, src_data.output_frames_gen * 4) < 0 )
|
||||
{
|
||||
fprintf(stderr, "SSNES [ERROR]: Audio backend failed to write. Will continue without sound.\n");
|
||||
audio_active = false;
|
||||
}
|
||||
|
||||
data_ptr = 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user