Skip to content

Commit

Permalink
wip: xpinmame on linux using sdl2 for video and audio
Browse files Browse the repository at this point in the history
  • Loading branch information
francisdb committed Jan 25, 2024
1 parent 9405e06 commit c4599cb
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 218 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/xpinmame.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
- if: matrix.os == 'ubuntu-latest'
run: |
sudo apt install libx11-dev libxv-dev libasound2-dev
sudo apt install libx11-dev libxv-dev libasound2-dev sdl2-dev
- name: Build xpinmame-${{ matrix.platform }}
run: |
cp cmake/xpinmame/CMakeLists_${{ matrix.platform }}.txt CMakeLists.txt
Expand Down
22 changes: 15 additions & 7 deletions cmake/xpinmame/CMakeLists_linux-x64.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,10 @@ add_compile_definitions(
XMAMEROOT="/usr/local/share/xpinmame"
HAVE_SNPRINTF
HAVE_GETTIMEOFDAY
#SYSDEP_DSP_ALSA
#SYSDEP_MIXER_ALSA
SYSDEP_DSP_OSS
# SYSDEP_DSP_ALSA
# SYSDEP_MIXER_ALSA
SYSDEP_DSP_SDL
SDL_DEBUG
)

add_executable(xpinmame
Expand Down Expand Up @@ -615,10 +616,11 @@ add_executable(xpinmame
src/unix/sysdep/sysdep_mixer.c
# src/unix/sysdep/dsp-drivers/alsa.c
# src/unix/sysdep/mixer-drivers/alsa.c
src/unix/sysdep/dsp-drivers/oss.c
src/unix/video-drivers/x11.c
src/unix/video-drivers/xinput.c
src/unix/video-drivers/x11_window.c
src/unix/sysdep/dsp-drivers/sdl.c
# src/unix/video-drivers/x11.c
# src/unix/video-drivers/xinput.c
# src/unix/video-drivers/x11_window.c
src/unix/video-drivers/sdl.c
src/unix/joystick-drivers/joy_i386.c
src/unix/joystick-drivers/joy_pad.c
src/unix/joystick-drivers/joy_x11.c
Expand All @@ -639,6 +641,10 @@ find_package(
ALSA
)

find_package(
SDL2
)

target_include_directories(xpinmame PUBLIC
src
src/wpc
Expand All @@ -649,6 +655,7 @@ target_include_directories(xpinmame PUBLIC
${X11_X11_INCLUDE_PATH}
${X11_Xv_INCLUDE_PATH}
${ALSA_INCLUDE_DIRS}
${SDL2_INCLUDE_DIRS}
)

target_link_libraries(xpinmame PUBLIC
Expand All @@ -657,6 +664,7 @@ target_link_libraries(xpinmame PUBLIC
${X11_Xv_LIB}
${X11_Xext_LIB}
${ALSA_LIBRARIES}
${SDL2_LIBRARIES}
)

set_target_properties(xpinmame PROPERTIES
Expand Down
183 changes: 66 additions & 117 deletions src/unix/sysdep/dsp-drivers/sdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,34 +30,23 @@ Version 0.1, January 2002
*/

// SDL defines this to __inline__ which no longer works with gcc 5+ ?
// TODO find the correct way to handle this, similar issue with ALSA
#ifndef SDL_FORCE_INLINE
#if ( (defined(__GNUC__) && (__GNUC__ >= 5)))
#define SDL_FORCE_INLINE __attribute__((always_inline)) static inline
#endif
#endif /* take the definition from SDL */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "SDL.h"
#include "SDL2/SDL.h"
#include "sysdep/sysdep_dsp.h"
#include "sysdep/sysdep_dsp_priv.h"
#include "sysdep/plugin_manager.h"

#ifdef __BEOS__
#define BUFFERSIZE 1470 * 4 /* in my experience, BeOS likes buffers to be 4x */
#else
#define BUFFERSIZE 1024
#endif

/* private variables */
static struct {
Uint8 *data;
int amountRemain;
int amountWrite;
int amountRead;
int tmp;
Uint32 soundlen;
int sound_n_pos;
int sound_w_pos;
int sound_r_pos;
} sample;

/* callback function prototype */
static void sdl_fill_sound(void *unused, Uint8 *stream, int len);

Expand All @@ -80,6 +69,10 @@ const struct plugin_struct sysdep_dsp_sdl = {
3 /* high priority */
};

struct sdl_info {
SDL_AudioDeviceID id;
};

/* public methods (static but exported through the sysdep_dsp or plugin
struct) */
static void *sdl_dsp_create(const void *flags)
Expand All @@ -105,54 +98,65 @@ static void *sdl_dsp_create(const void *flags)
sdl_dsp_destroy(dsp);
return NULL;
}


if (!(sample.data = calloc(BUFFERSIZE, sizeof(Uint8))))
{
fprintf(stderr, "error malloc failed for data\n");
sdl_dsp_destroy(dsp);
return NULL;
}

/* fill in the functions and some data */
dsp->_priv = priv;
dsp->write = sdl_dsp_write;
dsp->destroy = sdl_dsp_destroy;
dsp->hw_info.type = params->type;
dsp->hw_info.samplerate = params->samplerate;


/* set the number of bits */

audiospec->format = (dsp->hw_info.type & SYSDEP_DSP_16BIT)?
AUDIO_S16SYS : AUDIO_S8;

/* set the number of channels */
audiospec->channels = (dsp->hw_info.type & SYSDEP_DSP_STEREO)? 2:1;

/* set the samplerate */
audiospec->freq = dsp->hw_info.samplerate;

/* set samples size */
audiospec->samples = BUFFERSIZE;

/* set callback funcion */
audiospec->callback = sdl_fill_sound;

audiospec->userdata = NULL;


/* Open audio device */
if(SDL_WasInit(SDL_INIT_VIDEO)!=0) /* If sdl video system is already */
SDL_InitSubSystem(SDL_INIT_AUDIO);/* initialized, we just initialize */
else /* the audio subsystem */
SDL_Init(SDL_INIT_AUDIO); /* else we MUST use "SDL_Init" */
/* (untested) */
if (SDL_OpenAudio(audiospec, NULL) != 0) {
fprintf(stderr, "failed opening audio device\n");
return NULL;
}
SDL_PauseAudio(0);

fprintf(stderr, "sdl info: driver = %s\n", SDL_GetCurrentAudioDriver());

// get audio subsystem and open a queue with above spec
SDL_AudioSpec *obtained;
if (!(obtained = calloc(1, sizeof(SDL_AudioSpec))))
{
fprintf(stderr, "sdl error: malloc failed for SDL_AudioSpec\n");
sdl_dsp_destroy(dsp);
return NULL;
}

const SDL_AudioDeviceID id = SDL_OpenAudioDevice(NULL, 0, audiospec, obtained, 0);
if (id == 0) {
fprintf(stderr, "sdl error: SDL_OpenAudioDevice() failed: %s\n", SDL_GetError());
return NULL;
}

// free the spec
free(audiospec);

// print the id
fprintf(stderr, "sdl info: device id = %d\n", id);
// print the obtained contents
fprintf(stderr, "sdl info: obtained->format = %d\n", obtained->format);
fprintf(stderr, "sdl info: obtained->channels = %d\n", obtained->channels);
fprintf(stderr, "sdl info: obtained->freq = %d\n", obtained->freq);
fprintf(stderr, "sdl info: obtained->samples = %d\n", obtained->samples);
fprintf(stderr, "sdl info: obtained->callback = %p\n", obtained->callback);
fprintf(stderr, "sdl info: obtained->userdata = %p\n", obtained->userdata);

// resume playing on device
SDL_PauseAudioDevice(id, 0);

struct sdl_info *info = (struct sdl_info *)calloc(1, sizeof(struct sdl_info));
info->id = id;

dsp->_priv = info;

fprintf(stderr, "info: audiodevice %s set to %dbit linear %s %dHz\n",
fprintf(stderr, "sdl info: audiodevice %s set to %dbit linear %s %dHz\n",
device, (dsp->hw_info.type & SYSDEP_DSP_16BIT)? 16:8,
(dsp->hw_info.type & SYSDEP_DSP_STEREO)? "stereo":"mono",
dsp->hw_info.samplerate);
Expand All @@ -171,74 +175,19 @@ static void sdl_dsp_destroy(struct sysdep_dsp_struct *dsp)
static int sdl_dsp_write(struct sysdep_dsp_struct *dsp, unsigned char *data,
int count)
{
/* sound_n_pos = normal position
sound_r_pos = read position
and so on. */
int result = 0;
Uint8 *src;
SDL_LockAudio();

sample.amountRemain = BUFFERSIZE - sample.sound_n_pos;
sample.amountWrite = (dsp->hw_info.type & SYSDEP_DSP_STEREO)? count * 4 : count * 2;

if(sample.amountRemain <= 0) {
SDL_UnlockAudio();
return(result);
}

if(sample.amountRemain < sample.amountWrite) sample.amountWrite = sample.amountRemain;
result = (int)sample.amountWrite;
sample.sound_n_pos += sample.amountWrite;

src = (Uint8 *)data;
sample.tmp = BUFFERSIZE - sample.sound_w_pos;

if(sample.tmp < sample.amountWrite){
memcpy(sample.data + sample.sound_w_pos, src, sample.tmp);
sample.amountWrite -= sample.tmp;
src += sample.tmp;
memcpy(sample.data, src, sample.amountWrite);
sample.sound_w_pos = sample.amountWrite;
}
else{
memcpy( sample.data + sample.sound_w_pos, src, sample.amountWrite);
sample.sound_w_pos += sample.amountWrite;
}
SDL_UnlockAudio();

return count;
}
// count is the number of samples to write
const int len = (dsp->hw_info.type & SYSDEP_DSP_STEREO)? count * 4 : count * 2;

/* Private method */
static void sdl_fill_sound(void *unused, Uint8 *stream, int len)
{
int result;
Uint8 *dst;
SDL_LockAudio();
sample.amountRead = len;
if(sample.sound_n_pos <= 0)
SDL_UnlockAudio();

if(sample.sound_n_pos<sample.amountRead) sample.amountRead = sample.sound_n_pos;
result = (int)sample.amountRead;
sample.sound_n_pos -= sample.amountRead;

dst = (Uint8*)stream;

sample.tmp = BUFFERSIZE - sample.sound_r_pos;
if(sample.tmp<sample.amountRead){
memcpy( dst, sample.data + sample.sound_r_pos, sample.tmp);
sample.amountRead -= sample.tmp;
dst += sample.tmp;
memcpy( dst, sample.data, sample.amountRead);
sample.sound_r_pos = sample.amountRead;
}
else{
memcpy( dst, sample.data + sample.sound_r_pos, sample.amountRead);
sample.sound_r_pos += sample.amountRead;
}
SDL_UnlockAudio();
// get device id from dsp
const struct sdl_info *info = (struct sdl_info *)dsp->_priv;
const SDL_AudioDeviceID dev = info->id;

const int result = SDL_QueueAudio(dev, data, len);
if (result != 0) {
fprintf(stderr, "error: SDL_QueueAudio() failed: %s\n", SDL_GetError());
return 0;
}
return count;
}

#endif /* ifdef SYSDEP_DSP_SDL */
Loading

0 comments on commit c4599cb

Please sign in to comment.