[gimp-gap] added portable audioplayback support.
- From: Wolfgang Hofer <wolfgangh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp-gap] added portable audioplayback support.
- Date: Sat, 9 Feb 2013 19:03:42 +0000 (UTC)
commit 393caed73fb930b347625fe379cc8cd92322fde2
Author: Wolfgang Hofer <wolfgangh svn gnome org>
Date: Sat Feb 9 19:55:54 2013 +0100
added portable audioplayback support.
ChangeLog | 33 ++
Makefile.am | 2 +-
configure.in | 82 ++++-
gap/Makefile.am | 20 +-
gap/gap_apcl_lib.h | 129 +++++++
gap/gap_player_dialog.c | 69 ++--
gap/gap_sdl_audioplayer.c | 933 +++++++++++++++++++++++++++++++++++++++++++++
gap/gap_sdl_audioplayer.h | 129 +++++++
8 files changed, 1348 insertions(+), 49 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 36ac2a0..abd20d7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2013-02-10 Wolfgang Hofer <hof gimp org>
+
+- added audio support for other Operating Systems than Linux.
+ Audio playback now can be configured to use an SDL media library based
+ audio playback module (as alternative to the already existing
+ wavplay client/server based audio playback).
+
+ The configure option --disable-audio-support was removed and
+ replaced by the new options:
+
+ --disable-audio-support-sdl
+ --disable-audio-support-wavplay
+
+ on Linux
+ enable-audio-support-sdl is default
+ enable-audio-support-wavplay is fallback (when SDL library is not installed)
+
+ on Windows
+ enable-audio-support-sdl is default,
+
+ NO audio playback possible when SDL library library is not installed)
+
+
+ The SDL library is available for Linux, Windows and MacOS
+
+
+ * configure.in
+ * Makefile.am
+ * gap/Makefile.am
+ * gap/gap_apcl_lib.h #new file
+ * gap/gap_sdl_audioplayer.c [.h] #new files
+ * gap/gap_player_dialog.c
+
2013-01-16 Wolfgang Hofer <hof gimp org>
- fixed bug in the storybard master properties that truncated framerate to integer values.
diff --git a/Makefile.am b/Makefile.am
index 561ac5b..42d1dac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
-if GAP_AUDIO_SUPPORT
+if GAP_AUDIO_SUPPORT_WAVPLAY
LIBWAVCLIENT=libwavplayclient
endif
diff --git a/configure.in b/configure.in
index be9211e..b977c35 100644
--- a/configure.in
+++ b/configure.in
@@ -1085,30 +1085,88 @@ AC_SUBST(GAPVIDEOAPI_EXTINCS)
dnl Test for audiosupport
-dnl audiosupport currently is based on wavplay that is available on UNIX systems
-dnl (the wavplay client does not compile on Windows)
+dnl First check for the SDL media library and configure to compile and link
+dnl with the SDL based audioplayer when present.
+dnl (the check for libsdl uses the SDL specific sdl-config when available
+dnl and uses pkg-config as alternative check when sdl-config was not found.)
dnl ------------------------
-AC_ARG_ENABLE(audio_support,
- [ --disable-audio-support don't build with audio support])
+sdl_audio_err=""
+SDL_CONFIG="sdl-config"
+GAP_AUDIO_SDL_LIBS=""
+GAP_AUDIO_SDL_CFLAGS=""
+AC_ARG_ENABLE(audio_support_sdl,
+ [ --disable-audio-support-sdl don't build with SDL based audio support])
+ if test "x$enable_audio_support_sdl" != "xno"; then
+
+dnl -- TODO the AC_CHECK_HEADER for SDL_audio.h seems not to work
+dnl (e.g failed in my development environment even when SDL_audio.h is present
+dnl at the rellevant directory (that both pkg-config --cflags sdl AND sdl-config --cflags
+dnl gives as result)
+dnl -- therefore skip the check for SDL_audio.h
+dnl
+dnl
+dnl AC_CHECK_LIB(SDL, SDL_OpenAudio,
+dnl [AC_CHECK_HEADER(SDL_audio.h,
+dnl sdl_audio_err="",
+dnl sdl_audio_err="$NEW_LINE SDL audio header file (SDL_audio.h) not found (audio playback will be disabled)")],
+dnl sdl_audio_err="SDL library (libsdl) not found (audio playback will be disabled)")
+
+ AC_CHECK_LIB(SDL, SDL_OpenAudio,
+ sdl_audio_err="",
+ sdl_audio_err="SDL library (libsdl) not found (audio playback will be disabled)")
+
+ if test "x$sdl_audio_err" != "x"; then
+ enable_audio_support_sdl="no"
+ else
+ enable_audio_support_sdl="yes"
+ AC_CHECK_PROG(SDL_CONFIG, "$SDL_CONFIG", yes, no)
+ if test $SDL_CONFIG = no; then
+ GAP_AUDIO_SDL_CFLAGS=`$PKG_CONFIG --cflags sdl`
+ GAP_AUDIO_SDL_LIBS=`$PKG_CONFIG --libs sdl`
+ else
+ GAP_AUDIO_SDL_CFLAGS=`$SDL_CONFIG --cflags`
+ GAP_AUDIO_SDL_LIBS=`$SDL_CONFIG --libs`
+ fi
+
+ AC_DEFINE(GAP_ENABLE_AUDIO_SUPPORT_SDL, 1,
+ [Define to 1 to enable audio support via SDL media library])
+ fi
+ fi
+
+AM_CONDITIONAL(GAP_AUDIO_SUPPORT_SDL, test "x$enable_audio_support_sdl" != "xno")
+AC_SUBST(GAP_AUDIO_SDL_CFLAGS)
+AC_SUBST(GAP_AUDIO_SDL_LIBS)
+
+
+dnl further checks for alternative audiosupport, based on wavplay client-server that is available on UNIX systems
+dnl (note that the wavplay client does not compile on Windows)
+dnl ------------------------
+AC_ARG_ENABLE(audio_support_wavplay,
+ [ --disable-audio-support-wavplay don't build with wavplay based audio support])
if test "x$os_win32" = "xyes"; then
- enable_audio_support=no
+ enable_audio_support_wavplay=no
+ fi
+ if test "x$enable_audio_support_sdl" != "xno"; then
+ if test "x$enable_audio_support_sdl" != "x"; then
+ enable_audio_support_wavplay=no
+ fi;
fi
- if test "x$enable_audio_support" != "xno"; then
+ if test "x$enable_audio_support_wavplay" != "xno"; then
AC_CHECK_PROG(WAVPLAY_SERVER, wavplay, yes, no)
if test $WAVPLAY_SERVER = no; then
audio_warning="
-Audio support will be compiled in but will not work because the wavplay
-executable was not found. For audio support the wavplay audioserver must
+Audio support based on wavplay client-server implementation will be compiled but will not work because the wavplay
+executable was not found. For this kind of audio support the wavplay audioserver must
be installed at runtime.
"
fi
- AC_DEFINE(GAP_ENABLE_AUDIO_SUPPORT, 1,
- [Define to 1 to enable audio support])
+ AC_DEFINE(GAP_ENABLE_AUDIO_SUPPORT_WAVPLAY, 1,
+ [Define to 1 to enable audio support via wavplay client])
fi
-AM_CONDITIONAL(GAP_AUDIO_SUPPORT, test "x$enable_audio_support" != "xno")
+AM_CONDITIONAL(GAP_AUDIO_SUPPORT_WAVPLAY, test "x$enable_audio_support_wavplay" != "xno")
dnl optional compile preview widget with GDK-pixbuf support
dnl
@@ -1221,4 +1279,4 @@ docs/reference/Makefile
docs/reference/txt/Makefile
])
-AC_MSG_RESULT($frontends_warning $audio_warning $videoapi_warning $moved_old_ffmpeg_warn $moved_old_libmpeg3_warn $vid_ffmpeg_warning $yasm_warn $vid_mpeg3_warning $vid_quicktime_warning $vid_xvidcore_warning $pkg_cfg_warning)
+AC_MSG_RESULT($frontends_warning $sdl_audio_err $audio_warning $videoapi_warning $moved_old_ffmpeg_warn $moved_old_libmpeg3_warn $vid_ffmpeg_warning $yasm_warn $vid_mpeg3_warning $vid_quicktime_warning $vid_xvidcore_warning $pkg_cfg_warning)
diff --git a/gap/Makefile.am b/gap/Makefile.am
index 1173ccc..058948b 100644
--- a/gap/Makefile.am
+++ b/gap/Makefile.am
@@ -12,10 +12,16 @@ endif
GAP_DECODE_MPLAYER_FRONTEND = gap_decode_mplayer
-if GAP_AUDIO_SUPPORT
-WAVPLAYCLIENT = $(top_builddir)/libwavplayclient/libwavplayclient.a
+if GAP_AUDIO_SUPPORT_WAVPLAY
+GAP_AUDIO_LIBS = $(top_builddir)/libwavplayclient/libwavplayclient.a
endif
+if GAP_AUDIO_SUPPORT_SDL
+GAP_SDL_AUDIO_EXTRASRC = gap_sdl_audioplayer.h gap_sdl_audioplayer.c
+GAP_AUDIO_LIBS = $(GAP_AUDIO_SDL_LIBS)
+endif
+
+
if GAP_VIDEOAPI_SUPPORT
GAPVIDEOAPI = $(top_builddir)/libgapvidapi/libgapvidapi.a $(GAPVIDEOAPI_EXTLIBS)
INC_GAPVIDEOAPI = -I$(top_srcdir)/libgapvidapi $(GAPVIDEOAPI_EXTINCS)
@@ -339,6 +345,7 @@ gap_player_SOURCES = \
gap_player_dialog.h \
gap_player_cache.c \
gap_player_cache.h \
+ $(GAP_SDL_AUDIO_EXTRASRC) \
gap_audio_extract.c \
gap_audio_extract.h \
gap_drawable_vref_parasite.c \
@@ -379,6 +386,7 @@ gap_storyboard_SOURCES = \
gap_player_dialog.h \
gap_player_cache.c \
gap_player_cache.h \
+ $(GAP_SDL_AUDIO_EXTRASRC) \
gap_drawable_vref_parasite.c \
gap_drawable_vref_parasite.h \
gap_libgapstory.h \
@@ -400,6 +408,7 @@ gap_video_extract_SOURCES = \
gap_player_dialog.h \
gap_player_cache.c \
gap_player_cache.h \
+ $(GAP_SDL_AUDIO_EXTRASRC) \
gap_drawable_vref_parasite.c \
gap_drawable_vref_parasite.h \
gap_libgapstory.h \
@@ -488,6 +497,7 @@ INCLUDES = \
-I$(top_srcdir)/libwavplayclient \
$(INC_LIBGAPBASE) \
$(INC_GAPVIDEOAPI) \
+ $(GAP_AUDIO_SDL_CFLAGS) \
$(GIMP_CFLAGS) \
-I$(includedir)
@@ -511,10 +521,10 @@ gap_decode_mplayer_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
gap_morph_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) -lm
gap_name2layer_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
gap_navigator_dialog_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
-gap_player_LDADD = $(GAPVIDEOAPI) $(WAVPLAYCLIENT) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS)
+gap_player_LDADD = $(GAPVIDEOAPI) $(GAP_AUDIO_LIBS) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS)
gap_onion_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
-gap_storyboard_LDADD = $(GAPVIDEOAPI) $(WAVPLAYCLIENT) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS)
-gap_video_extract_LDADD = $(GAPVIDEOAPI) $(WAVPLAYCLIENT) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS)
+gap_storyboard_LDADD = $(GAPVIDEOAPI) $(GAP_AUDIO_LIBS) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS)
+gap_video_extract_LDADD = $(GAPVIDEOAPI) $(GAP_AUDIO_LIBS) ${LIBGAPSTORY} $(LIBGAPBASE) $(GIMP_LIBS)
gap_video_index_LDADD = $(GAPVIDEOAPI) $(LIBGAPSTORY) $(LIBGAPBASE) $(GIMP_LIBS)
gap_fg_matting_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS) -lm
gap_fire_pattern_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
diff --git a/gap/gap_apcl_lib.h b/gap/gap_apcl_lib.h
new file mode 100644
index 0000000..3b5d2af
--- /dev/null
+++ b/gap/gap_apcl_lib.h
@@ -0,0 +1,129 @@
+/* gap_apcl_lib.h
+ * Provides the GAP Audio Player Client support API functions.
+ *
+ * This module includes the relevant audio playback
+ * implementation which is configured at compiletime.
+ *
+ * following implementations are available:
+ * - SDL media library based audioplayback GAP_ENABLE_AUDIO_SUPPORT_SDL
+ * - wavplay client/server based audioplayback GAP_ENABLE_AUDIO_SUPPORT_WAVPLAY
+ */
+
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program 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 Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _GAP_APCL_LIB_H
+#define _GAP_APCL_LIB_H
+
+#define WPC_FLAGS_BITS_SIGNED_LITTLE_ENDIAN_SAMPLE 0
+#define WPC_FLAGS_BITS_UNSIGNED_LITTLE_ENDIAN_SAMPLE 1
+#define WPC_FLAGS_BITS_SIGNED_BIG_ENDIAN_SAMPLES 2
+#define WPC_FLAGS_BITS_UNSIGNED_BIG_ENDIAN_SAMPLE 3
+
+
+#ifdef GAP_ENABLE_AUDIO_SUPPORT_SDL
+#define GAP_ENABLE_AUDIO_SUPPORT 1
+/* ------- START SDL based stuff ----------------------------------------------------------- */
+
+/* use audio playback based on the SDL media library
+ * (SDL works on multiple Operating systems including Linux and Windows and McOS)
+ *
+ * AudioPlayerCLient Wrapper Procedures
+ * Implementation for SDL based audio player
+ * can use MACRO definitions for most Procedures
+ */
+
+#include <gap_sdl_audioplayer.h>
+
+#define APCL_ErrFunc GapSdlErrFunc
+
+static int apcl_have_memory_playback(void) { return (1); }
+
+/* Define MACROs to map the API functions ( apcl_* ) to SDL based player functions (gap_sdl_*) */
+#define apcl_memory_buffer(buffer,len,erf) gap_sdl_memory_buffer(buffer,len,erf) /* Tell audio_player a buffer with PCM audiodata */
+#define apcl_channels(flags,erf,channels) gap_sdl_channels(flags,erf,channels) /* Tell audio_player the number of channels */
+#define apcl_bits(flags,erf,bits) gap_sdl_bits(flags,erf,bits) /* Tell audio_player the number of bits per sample */
+#define apcl_volume(volume,flags,erf) gap_sdl_volume(volume,flags,erf) /* Tell audio_player the mixvolume 0.0 to 1.0 */
+
+#define apcl_bye(flags,erf) gap_sdl_cmd(GAP_SDL_CMD_Bye,flags,erf) /* Tell audio_player to exit */
+#define apcl_play(flags,erf) gap_sdl_cmd(GAP_SDL_CMD_Play,flags,erf) /* Tell audio_player to play */
+#define apcl_pause(flags,erf) gap_sdl_cmd(GAP_SDL_CMD_Pause,flags,erf) /* Tell audio_player to pause */
+#define apcl_stop(flags,erf) gap_sdl_cmd(GAP_SDL_CMD_Stop,flags,erf) /* Tell audio_player to stop */
+#define apcl_restore(flags,erf) gap_sdl_cmd(GAP_SDL_CMD_Restore,flags,erf) /* Tell audio_player to restore settings */
+#define apcl_semreset(flags,erf) gap_sdl_cmd(GAP_SDL_CMD_SemReset,flags,erf) /* No operation (audio_player has no semaphores) */
+
+#define apcl_start(erf) gap_sdl_start(erf) /* Tell audio_player to init a playback thread */
+#define apcl_path(path,flags,erf) gap_sdl_path(path,flags,erf) /* Tell audio_player a pathname */
+#define apcl_sampling_rate(rate,flags,erf) gap_sdl_sampling_rate(flags,erf,rate) /* Tell audio_player the samplingrate */
+#define apcl_start_sample(offs,flags,erf) gap_sdl_start_sample(flags,erf,offs) /* Tell audio_player where to start playback */
+
+
+
+/* ------- END SDL based stuff ----------------------------------------------------------- */
+
+#else
+#ifdef GAP_ENABLE_AUDIO_SUPPORT_WAVPLAY
+#define GAP_ENABLE_AUDIO_SUPPORT 1
+
+/* ------- START waveplay client/server based stuff ----------------------------------------------------------- */
+/* use wavplay as external audio server (available for Linux) */
+
+#include <wavplay.h>
+#include <wavfile.h>
+#include <client.h>
+
+
+/* AudioPlayerCLient Wrapper Procedures
+ * Implementation for wavplay client
+ * can use MACRO definitions for most Procedures
+ * -- Note that this requires the wavplay server (available on Linux) installed
+ * -- for working audio support at run time.
+ */
+
+
+#define APCL_ErrFunc ErrFunc
+
+/* static dummy implementations for (newer) features that are NOT supported by wavplay */
+static int apcl_have_memory_playback(void) { return (0); }
+static int apcl_bits(int flags, PCL_ErrFunc erf,int bits) { return (1); }
+static int apcl_memory_buffer(char *buffer, long buffer_len, PCL_ErrFunc erf) { return (1); }
+static int apcl_channels(int flags, PCL_ErrFunc erf, int channels) { return (1); }
+
+/* apcl_volume: volume must be a value between 0.0 and 1.0 */
+extern int apcl_volume(double volume, int flags,APCL_ErrFunc erf);
+
+/* Define MACROs to map the API functions ( apcl_* ) to wavplay client library functions (tosvr_*) */
+#define apcl_bye(flags,erf) tosvr_cmd(ToSvr_Bye,flags,erf) /* Tell server to exit */
+#define apcl_play(flags,erf) tosvr_cmd(ToSvr_Play,flags,erf) /* Tell server to play */
+#define apcl_pause(flags,erf) tosvr_cmd(ToSvr_Pause,flags,erf) /* Tell server to pause */
+#define apcl_stop(flags,erf) tosvr_cmd(ToSvr_Stop,flags,erf) /* Tell server to stop */
+#define apcl_restore(flags,erf) tosvr_cmd(ToSvr_Restore,flags,erf) /* Tell server to restore settings */
+#define apcl_semreset(flags,erf) tosvr_cmd(ToSvr_SemReset,flags,erf) /* Tell server to reset semaphores */
+
+#define apcl_start(erf) tosvr_start(erf)
+#define apcl_path(path,flags,erf) tosvr_path(path,flags,erf) /* Tell server a pathname */
+#define apcl_sampling_rate(rate,flags,erf) tosvr_sampling_rate(flags,erf,rate) /* Tell server a pathname */
+#define apcl_start_sample(offs,flags,erf) tosvr_start_sample(flags,erf,offs) /* Tell server a pathname */
+
+
+
+
+/* ------- END waveplay client/server based stuff ----------------------------------------------------------- */
+
+#endif /* GAP_ENABLE_AUDIO_SUPPORT_WAVPLAY */
+#endif /* GAP_ENABLE_AUDIO_SUPPORT_SDL */
+#endif /* _GAP_APCL_LIB_H */
diff --git a/gap/gap_player_dialog.c b/gap/gap_player_dialog.c
index 25bc2ce..319d3d9 100644
--- a/gap/gap_player_dialog.c
+++ b/gap/gap_player_dialog.c
@@ -113,15 +113,17 @@
#include "gap_audio_extract.h"
#include "gap_drawable_vref_parasite.h"
#include "gap_detail_tracking_exec.h"
+#include "gap_audio_wav.h"
#include "gap-intl.h"
extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */
int cmdopt_x = 0; /* Debug option flag for wavplay */
-#ifdef GAP_ENABLE_AUDIO_SUPPORT
+#include "gap_apcl_lib.h" /* headerfile for libwavplayclient (preferred) */
+
+#ifdef GAP_ENABLE_AUDIO_SUPPORT_WAVPLAY
-#include "wpc_lib.h" /* headerfile for libwavplayclient (preferred) */
char *env_WAVPLAYPATH = WAVPLAYPATH; /* Default pathname of executable /usr/local/bin/wavplay */
char *env_AUDIODEV = AUDIODEV; /* Default compiled in audio device */
@@ -726,13 +728,12 @@ static void
p_audio_filename_changed(GapPlayerMainGlobalParams *gpp)
{
#ifdef GAP_ENABLE_AUDIO_SUPPORT
- int fd;
int rc;
- int channels; /* Channels recorded in this wav file */
- u_long samplerate; /* Sampling rate */
- int sample_bits; /* data bit size (8/12/16) */
- u_long samples; /* The number of samples in this file */
- u_long datastart; /* The offset to the wav data */
+ long samplerate; /* Sampling rate in Hz */
+ long channels; /* Channels recorded in this wav file */
+ long bytes_per_sample; /* data bit size (8/12/16) */
+ long sample_bits; /* data bit size of one sample value (8/12/16) */
+ long samples; /* The number of samples in this file */
if (gap_debug)
{
@@ -741,21 +742,8 @@ p_audio_filename_changed(GapPlayerMainGlobalParams *gpp)
p_audio_stop(gpp);
gpp->audio_status = MIN(gpp->audio_status, GAP_PLAYER_MAIN_AUSTAT_SERVER_STARTED);
- /* Open the file for reading: */
- if ( (fd = g_open(gpp->audio_filename,O_RDONLY)) < 0 )
- {
- p_print_and_clear_audiolabels(gpp);
- return;
- }
-
- rc = WaveReadHeader(fd
- ,&channels
- ,&samplerate
- ,&sample_bits
- ,&samples
- ,&datastart
- ,p_audio_errfunc);
- close(fd);
+ rc = gap_audio_wav_file_check(gpp->audio_filename, &samplerate, &channels
+ , &bytes_per_sample, &sample_bits, &samples);
if(rc != 0)
{
@@ -1051,23 +1039,23 @@ p_audio_start_play(GapPlayerMainGlobalParams *gpp)
&& (flt_samplerate >= GAP_PLAYER_MAIN_MIN_SAMPLERATE)
)
{
- UInt32 lu_samplerate;
+ guint32 lu_samplerate;
p_audio_init(gpp); /* tell ausioserver to go standby for this audiofile */
gpp->audio_required_samplerate = (guint32)flt_samplerate;
if(flt_samplerate > GAP_PLAYER_MAIN_MAX_SAMPLERATE)
{
- lu_samplerate = (UInt32)GAP_PLAYER_MAIN_MAX_SAMPLERATE;
+ lu_samplerate = (guint32)GAP_PLAYER_MAIN_MAX_SAMPLERATE;
/* required samplerate is faster than highest possible audioplayback speed
* (the audioplayback will be played but runs out of sync and cant follow)
*/
}
else
{
- lu_samplerate = (UInt32)flt_samplerate;
+ lu_samplerate = (guint32)flt_samplerate;
}
apcl_sampling_rate(lu_samplerate,0,p_audio_errfunc);
- apcl_start_sample((UInt32)offset_start_samples,0,p_audio_errfunc);
+ apcl_start_sample((guint32)offset_start_samples,0,p_audio_errfunc);
apcl_play(0,p_audio_errfunc); /* Tell server to play */
apcl_volume(gpp->audio_volume, 0, p_audio_errfunc);
@@ -1082,11 +1070,22 @@ p_audio_start_play(GapPlayerMainGlobalParams *gpp)
/* -----------------------------
* p_audio_startup_server
* -----------------------------
+ * In case compiled with (older) wavplay client/server
+ * implementation, this method checks if the wavplay server
+ * is available.
+ *
+ * In case newer audiosupport is availabel just enable the relevant GUI widgets
+ *
+ * In case audiosupport is NOT available
+ *
*/
static void
p_audio_startup_server(GapPlayerMainGlobalParams *gpp)
{
-#ifdef GAP_ENABLE_AUDIO_SUPPORT
+ gboolean l_audio_enable = FALSE;
+
+
+#ifdef GAP_ENABLE_AUDIO_SUPPORT_WAVPLAY
const char *cp;
gboolean wavplay_server_found;
@@ -1163,11 +1162,11 @@ p_audio_startup_server(GapPlayerMainGlobalParams *gpp)
if(wavplay_server_found)
{
p_audio_filename_changed(gpp);
- gpp->audio_enable = TRUE;
+ l_audio_enable = TRUE;
}
else
{
- gpp->audio_enable = FALSE;
+ l_audio_enable = FALSE;
g_message(_("No audiosupport available\n"
"the audioserver executable file '%s' was not found.\n"
"If you have installed '%s'\n"
@@ -1179,7 +1178,15 @@ p_audio_startup_server(GapPlayerMainGlobalParams *gpp)
, "WAVPLAYPATH"
);
}
+#else
+#ifdef GAP_ENABLE_AUDIO_SUPPORT
+ p_audio_filename_changed(gpp);
+ l_audio_enable = TRUE;
+#endif
+
#endif
+
+ gpp->audio_enable = l_audio_enable;
return;
} /* end p_audio_startup_server */
@@ -7202,7 +7209,7 @@ on_prefs_save_gimprc_button_clicked (GtkButton *button,
p_gimprc_save_boolean_option("video_player_enable_detail_tracking"
,gpp->enableDetailTracking);
- valueAsString = g_strdup_printf("%d", gpp->cache_ntiles);
+ valueAsString = g_strdup_printf("%ld", (long)gpp->cache_ntiles);
gimp_gimprc_set("video_player_cache_ntiles", valueAsString);
g_free(valueAsString);
diff --git a/gap/gap_sdl_audioplayer.c b/gap/gap_sdl_audioplayer.c
new file mode 100644
index 0000000..2b55004
--- /dev/null
+++ b/gap/gap_sdl_audioplayer.c
@@ -0,0 +1,933 @@
+/* gap_sdl_audioplayer.c
+ * implements audio wavefile playback via SDL medialibrary.
+ * (SDL is available for Linux, Windows and MacOS)
+ *
+ * This player uses an interface that is compatible with
+ * the wavplay client wrapper, but adds support for playback of
+ * audio pcm data from a preloaded memory buffer.
+ *
+ * Note that the (older) wavplay server/client based audioplayback
+ * may be configured at compiletime as alternative on Linux only.
+ */
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program 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 Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <SDL.h>
+#include <SDL_audio.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <gap_sdl_audioplayer.h>
+
+#include <gap_audio_wav.h>
+
+
+#define NUM_SOUNDSLOTS 1 /* number of sounds that can be played (mixed) at same time */
+ /* Note that the current implementation is partly prepared for more than one sound at a time
+ * but limited to 1 Sound (due to wavplay compatible API that does not require this feature)
+ * Note that Playing from multiple slots also requires same audio parameters (channels, samplerate, format)
+ * for audio data in all slots.
+ */
+
+#define AUDIO_BUFFER_SIZE_IN_SAMPLES 4096
+
+/* The AUDIO_FILE_PACKET_SIZE shall be large enough to provide all requested samples (len)
+ * in the mixaudio_callback with only one file read (fread) operation for optimal performance.
+ * in tests on Linux systems a size of AUDIO_BUFFER_SIZE_IN_SAMPLES * 4 was sufficient
+ * but tests on Windows7 showed that the mixaudio_callback requested a len value of 44112 bytes.
+ * therfore the AUDIO_FILE_PACKET_SIZE was increased to AUDIO_BUFFER_SIZE_IN_SAMPLES * 32
+ * that should work on most systems.
+ * (smaller AUDIO_BUFFER_SIZE_IN_SAMPLES was also successfully tested on Windows7)
+ *
+ */
+#define AUDIO_FILE_PACKET_SIZE (AUDIO_BUFFER_SIZE_IN_SAMPLES * 32)
+
+
+#define MAX_WAV_FILENAME_LENGTH 2048
+
+typedef struct {
+ Uint32 start_at_sample; /* offset (where to start play) in number of audio frames */
+ int mix_volume; /* 0 upto SDL_MIX_MAXVOLUME (Note this does not change hardware volume.) */
+
+ /* preloaded memory slot (relevant in case data != NULL) */
+ Uint8 *data; /* the audio sample data */
+ Uint32 dpos; /* the current data position in bytes (points to rest of data that has not yet been played) */
+ Uint32 dlen; /* the length of audio sample data in bytes */
+
+ /* file based audio slot */
+ FILE *fpWav; /* filehandle to read from audio wavefile */
+ long offset_to_first_sample; /* fseek offset to the 1st sample data byte in the audio wavefile */
+ Uint8 audio_buf[AUDIO_FILE_PACKET_SIZE]; /* buffer for fetching audio sample data from file */
+ char wav_filename[MAX_WAV_FILENAME_LENGTH]; /* the name of the audio file to be played */
+} AudioSlot;
+
+
+typedef struct
+{
+ /* audio params */
+ unsigned int samplerate;
+ unsigned int channels;
+ unsigned int bits_per_sample;
+ unsigned int frame_size; /* frame_size = (bits_per_sample / 8) * channels */
+ unsigned int format; /* AUDIO_S16, AUDIO_U8, ... */
+
+ /* private attribuites (managed by the playback_callback thread only) */
+ SDL_AudioSpec sdlAudioSpec;
+ AudioSlot sounds[NUM_SOUNDSLOTS];
+
+} AudioPlaybackThreadUserData;
+
+
+static AudioPlaybackThreadUserData *audioPlaybackThreadUserDataPtr = NULL;
+
+extern int gap_debug;
+
+/* ------------------------------------------------
+ * call_errfunc
+ * ------------------------------------------------
+ * Error reporting function for this source module:
+ */
+static void
+call_errfunc(GapSdlErrFunc v_erf, const char *format,...) {
+ va_list ap;
+
+ if ( v_erf == NULL )
+ {
+ return; /* Only report error if we have function */
+ }
+ va_start(ap,format);
+ v_erf(format,ap); /* Use caller's supplied function */
+ va_end(ap);
+}
+
+/* -------------------------------------
+ * mixaudio_callback
+ * -------------------------------------
+ * this callback function will be called when the audio device is ready for more data.
+ * It is passed a pointer to user specific data, the audio buffer, and the length in bytes of the audio buffer.
+ * This function usually runs in a separate thread, and so access to data structures
+ * must be protected by calling SDL_LockAudio and SDL_UnlockAudio.
+ *
+ * This callback fetches audio data from preloaded memory (at address usrPtr->sounds[i].data)
+ * or tries to fetch from file
+ * in case address usrPtr->sounds[i].data is NULL and
+ * usrPtr->sounds[i].fpWav refers to an audiofile opened for read access.
+ *
+ * it is assumed that the audiofile contains uncopressed PCM data
+ * matching the current audio playback settings (channels, samplerate, bits_per_sample,...)
+ * .. e.g no converting of different channels, samplerates is done in this function.
+ */
+void mixaudio_callback(void *userData, Uint8 *stream, int len)
+{
+ int ii;
+ Uint32 amount;
+ AudioPlaybackThreadUserData *usrPtr;
+
+
+ usrPtr = (AudioPlaybackThreadUserData *) userData;
+ if (usrPtr == NULL)
+ {
+ return;
+ }
+
+ SDL_LockAudio();
+
+ for (ii=0; ii < NUM_SOUNDSLOTS; ii++)
+ {
+ if (usrPtr->sounds[ii].data == NULL)
+ {
+ int lenRest;
+ int lenToDeliver;
+ Uint8 *streamPos;
+
+ lenToDeliver = len;
+ streamPos = stream;
+
+ while(lenToDeliver > 0)
+ {
+ lenRest = MIN(lenToDeliver, AUDIO_FILE_PACKET_SIZE);
+ amount = AUDIO_FILE_PACKET_SIZE;
+ if ( amount > lenRest )
+ {
+ amount = lenRest;
+ }
+ /* try fetch data packet direct from file */
+ if ((usrPtr->sounds[ii].fpWav == NULL) || (amount <= 0))
+ {
+ /* file not available (already closed when plyaed until end */
+ amount = 0;
+ }
+ else
+ {
+ int datasize;
+ datasize = fread(&usrPtr->sounds[ii].audio_buf[0]
+ , 1
+ , amount
+ , usrPtr->sounds[ii].fpWav
+ );
+ if(gap_debug)
+ {
+ printf("mixaudio_callback fread amount:%d datasize:%d len:%d lenToDeliver:%d lenRest:%d mix_volume:%d\n"
+ , amount
+ , datasize
+ , len
+ , lenToDeliver
+ , lenRest
+ , (int)usrPtr->sounds[ii].mix_volume
+ );
+ }
+ if (datasize != amount)
+ {
+ if (datasize > 0)
+ {
+ amount = datasize;
+ }
+ else
+ {
+ amount = 0;
+ }
+ }
+
+ }
+ SDL_MixAudio(streamPos
+ , &usrPtr->sounds[ii].audio_buf[0]
+ , amount
+ , usrPtr->sounds[ii].mix_volume
+ );
+ if(amount < lenRest)
+ {
+ break;
+ }
+ lenToDeliver -= amount;
+ streamPos += amount;
+
+ }
+
+
+ }
+ else
+ {
+ /* fetch data from preloaded memory data buffer */
+ amount = (usrPtr->sounds[ii].dlen - usrPtr->sounds[ii].dpos);
+ if ( amount > len )
+ {
+ amount = len;
+ }
+ if(gap_debug)
+ {
+ printf("mixaudio_callback mix amount:%d len:%d mix_volume:%d\n"
+ , amount
+ , len
+ , (int)usrPtr->sounds[ii].mix_volume
+ );
+ }
+ SDL_MixAudio(stream
+ , &usrPtr->sounds[ii].data[usrPtr->sounds[ii].dpos]
+ , amount
+ , usrPtr->sounds[ii].mix_volume
+ );
+ usrPtr->sounds[ii].dpos += amount;
+ }
+ }
+
+ SDL_UnlockAudio();
+
+} /* end mixaudio_callback */
+
+
+
+/* ------------------------------------------------
+ * newAudioPlaybackThreadUserData
+ * ------------------------------------------------
+ * allocate a new AudioPlaybackThreadUserData structure
+ * and initialize with default values.
+ */
+static AudioPlaybackThreadUserData *
+newAudioPlaybackThreadUserData()
+{
+ int ii;
+ AudioPlaybackThreadUserData *usrPtr;
+
+ /* init user data for the audio_playback_thread */
+ usrPtr = g_new0 (AudioPlaybackThreadUserData, 1);
+
+ /* prepared parameters (relevant for next playback start) */
+ usrPtr->samplerate = 44100;
+ usrPtr->channels = 2;
+ usrPtr->bits_per_sample = 16;
+ usrPtr->frame_size = (usrPtr->bits_per_sample / 8) * usrPtr->channels;
+ usrPtr->format = AUDIO_S16;
+
+ /* actual parameters (relevant for playback) */
+ usrPtr->sdlAudioSpec.freq = 44100;
+ usrPtr->sdlAudioSpec.format = AUDIO_S16;
+ usrPtr->sdlAudioSpec.channels = 2;
+ usrPtr->sdlAudioSpec.samples = AUDIO_BUFFER_SIZE_IN_SAMPLES; /* 512 upto 8192 are recommanded values */
+ usrPtr->sdlAudioSpec.callback = mixaudio_callback;
+ usrPtr->sdlAudioSpec.userdata = usrPtr;
+
+
+ /* init sound slots (relevant for filling audio buffer
+ * at playback int mixaudio_callback thread)
+ */
+ for (ii=0; ii < NUM_SOUNDSLOTS; ii++)
+ {
+ usrPtr->sounds[ii].start_at_sample = 0;
+ usrPtr->sounds[ii].mix_volume = SDL_MIX_MAXVOLUME;
+ usrPtr->sounds[ii].data = NULL;
+ usrPtr->sounds[ii].dpos = 0;
+ usrPtr->sounds[ii].dlen = 0;
+
+ usrPtr->sounds[ii].fpWav = NULL;
+ usrPtr->sounds[ii].offset_to_first_sample = 0;
+ usrPtr->sounds[ii].wav_filename[0] = '\0';
+ }
+
+ return (usrPtr);
+
+} /* end newAudioPlaybackThreadUserData */
+
+
+/* ------------------------------------------------
+ * getUsrPtr
+ * ------------------------------------------------
+ */
+static AudioPlaybackThreadUserData *
+getUsrPtr()
+{
+ AudioPlaybackThreadUserData *usrPtr;
+ if (audioPlaybackThreadUserDataPtr == NULL)
+ {
+ audioPlaybackThreadUserDataPtr = newAudioPlaybackThreadUserData();
+ }
+
+ usrPtr = audioPlaybackThreadUserDataPtr;
+ return (usrPtr);
+
+} /* end getUsrPtr */
+
+/* ------------------------------------------------
+ * close_files
+ * ------------------------------------------------
+ */
+static void
+close_files()
+{
+ AudioPlaybackThreadUserData *usrPtr;
+
+ usrPtr = getUsrPtr();
+ if (usrPtr != NULL)
+ {
+ int ii;
+
+ SDL_LockAudio();
+ for (ii=0; ii < NUM_SOUNDSLOTS; ii++)
+ {
+ if (usrPtr->sounds[ii].fpWav != NULL)
+ {
+ fclose(usrPtr->sounds[ii].fpWav);
+ usrPtr->sounds[ii].fpWav = NULL;
+ }
+ }
+ SDL_UnlockAudio();
+ }
+
+} /* end close_files */
+
+
+/* ------------------------------------------------
+ * stop_audio
+ * ------------------------------------------------
+ */
+static void
+stop_audio()
+{
+ AudioPlaybackThreadUserData *usrPtr;
+
+ usrPtr = getUsrPtr();
+ if (usrPtr != NULL)
+ {
+ SDL_LockAudio();
+
+ if(SDL_GetAudioStatus() != SDL_AUDIO_STOPPED)
+ {
+ SDL_CloseAudio();
+ }
+ SDL_UnlockAudio();
+ }
+
+} /* end stop_audio */
+
+
+/* ------------------------------------------------
+ * start_audio
+ * ------------------------------------------------
+ * init SDL audio with new (pending) setings and (re)start audio playback
+ * from prepared position "start_at_sample"
+ * (e.g. from begin in case gap_sdl_start_sample was not called before)
+ *
+ * in case audio is already playing stop it, and restart with the new settings.
+ */
+static int
+start_audio()
+{
+ AudioPlaybackThreadUserData *usrPtr;
+ int ii;
+
+ usrPtr = getUsrPtr();
+ if (usrPtr == NULL)
+ {
+ return (1);
+ }
+
+ SDL_LockAudio();
+ if(SDL_GetAudioStatus() != SDL_AUDIO_STOPPED)
+ {
+ SDL_CloseAudio();
+ }
+
+ for (ii=0; ii < NUM_SOUNDSLOTS; ii++)
+ {
+ if (usrPtr->sounds[ii].data == NULL)
+ {
+ if (usrPtr->sounds[ii].fpWav == NULL)
+ {
+ usrPtr->sounds[ii].fpWav = gap_audio_wav_open_seek_data(usrPtr->sounds[ii].wav_filename);
+ }
+
+ if (usrPtr->sounds[ii].fpWav != NULL)
+ {
+ long seekPosition;
+
+ seekPosition = usrPtr->sounds[ii].offset_to_first_sample
+ + (usrPtr->sounds[ii].start_at_sample * usrPtr->frame_size);
+
+ fseek(usrPtr->sounds[ii].fpWav, seekPosition, SEEK_SET);
+ }
+ }
+ else
+ {
+ usrPtr->sounds[ii].dpos = usrPtr->sounds[ii].start_at_sample * usrPtr->frame_size;
+ if (usrPtr->sounds[ii].dpos >= usrPtr->sounds[ii].dlen)
+ {
+ /* reset to begin on illegal start position */
+ usrPtr->sounds[ii].dpos = 0;
+ }
+ }
+ }
+
+
+ /* load sdlAudioSpec (relevant for playback) from prepared values */
+ usrPtr->sdlAudioSpec.freq = usrPtr->samplerate;
+ usrPtr->sdlAudioSpec.format = usrPtr->format;
+ usrPtr->sdlAudioSpec.channels = usrPtr->channels;
+ usrPtr->sdlAudioSpec.samples = AUDIO_BUFFER_SIZE_IN_SAMPLES; /* audio buffer size (512 upto 8192 recommanded) */
+
+
+ SDL_UnlockAudio();
+ if ( SDL_OpenAudio(&usrPtr->sdlAudioSpec, NULL) < 0 )
+ {
+ /* Unable to open audio use SDL_GetError() to query reason */
+ return(2);
+ }
+
+ SDL_PauseAudio(0); /* pause value 0 triggers playback start */
+
+ return (0); /* OK */
+
+} /* end start_audio */
+
+
+
+/* -------------------------------------
+ * gap_sdl_start
+ * -------------------------------------
+ * prepare the audio_playback.
+ * (not mandatory in this SDL based implementation)
+ */
+int
+gap_sdl_start(GapSdlErrFunc erf)
+{
+ AudioPlaybackThreadUserData *usrPtr;
+
+ usrPtr = getUsrPtr();
+ if (usrPtr != NULL)
+ {
+ return (0); /* OK */
+ }
+
+ call_errfunc(erf, "failed to prepare audio_playback.");
+ return (1);
+
+} /* end gap_sdl_start */
+
+
+/* -------------------------------------
+ * gap_sdl_memory_buffer
+ * -------------------------------------
+ */
+int
+gap_sdl_memory_buffer(char *buffer, long buffer_len, GapSdlErrFunc erf)
+{
+ int rc = 1;
+ int ii = 0;
+ AudioPlaybackThreadUserData *usrPtr;
+
+ usrPtr = getUsrPtr();
+ if (usrPtr != NULL)
+ {
+ stop_audio();
+ usrPtr->sounds[ii].data = buffer; /* point to memory provided by the caller */
+ usrPtr->sounds[ii].dpos = 0;
+ usrPtr->sounds[ii].dlen = buffer_len;
+
+ if (usrPtr->sounds[ii].fpWav != NULL)
+ {
+ fclose(usrPtr->sounds[ii].fpWav);
+ usrPtr->sounds[ii].fpWav = NULL;
+ }
+ rc = 0; /* OK */
+ }
+
+ if ( (rc != 0) && (erf != NULL) )
+ {
+ call_errfunc(erf, "memory_buffer: %ld len: %ld not accepted", (long)&buffer, buffer_len);
+ }
+
+ return (rc);
+
+} /* end gap_sdl_memory_buffer */
+
+
+
+/* -------------------------------------
+ * gap_sdl_path
+ * -------------------------------------
+ *
+ * Send a pathname to the audio_player.
+ * (use flags =1 to keep current playback parameters)
+ * typical call with flags == 0 does init the audio playback parameters
+ * from the header information of the specified RIFF WAVE file (rfered by pathname)
+ */
+int
+gap_sdl_path(const char *pathname,int flags,GapSdlErrFunc erf)
+{
+ int rc = 1;
+ AudioPlaybackThreadUserData *usrPtr;
+
+ usrPtr = getUsrPtr();
+ if (usrPtr != NULL)
+ {
+ int rcCheck;
+ long sample_rate;
+ long channels;
+ long bytes_per_sample;
+ long bits;
+ long samples;
+
+ rcCheck = gap_audio_wav_file_check(pathname, &sample_rate, &channels
+ , &bytes_per_sample, &bits, &samples);
+ if (rcCheck == 0)
+ {
+ int ii;
+
+ rc = 0; /* OK */
+ ii = 0;
+ stop_audio();
+ usrPtr->sounds[ii].data = NULL; /* no preloded memory available */
+ usrPtr->sounds[ii].dpos = 0;
+ usrPtr->sounds[ii].dlen = 0;
+
+
+ if (flags != 1)
+ {
+ /* set audio params from wavefile header */
+ usrPtr->format = AUDIO_S16;
+
+ usrPtr->samplerate = sample_rate;
+ usrPtr->channels = channels;
+ usrPtr->bits_per_sample = bits;
+ usrPtr->frame_size = (usrPtr->bits_per_sample / 8) * usrPtr->channels;
+ switch (bits)
+ {
+ case 8:
+ usrPtr->format = AUDIO_U8;
+ break;
+ case 16:
+ usrPtr->format = AUDIO_S16; /* same as AUDIO_S16LSB */
+ break;
+ default:
+ rc = 2; /* unsupported bits_per_channel value */
+ break;
+ }
+ }
+ if (rc == 0)
+ {
+ if (usrPtr->sounds[ii].fpWav != NULL)
+ {
+ if (strcmp(usrPtr->sounds[ii].wav_filename, pathname) != 0)
+ {
+ /* file differs from currently opened wavfile, force close/reopen */
+ fclose(usrPtr->sounds[ii].fpWav);
+ usrPtr->sounds[ii].fpWav = NULL;
+ }
+ else
+ {
+ long seekPosition;
+
+ /* current wavfile was specified again, just rewind existing filehandle */
+ seekPosition = usrPtr->sounds[ii].offset_to_first_sample;
+ fseek(usrPtr->sounds[ii].fpWav, seekPosition, SEEK_SET);
+ }
+ }
+
+ if (usrPtr->sounds[ii].fpWav == NULL)
+ {
+ g_snprintf(usrPtr->sounds[ii].wav_filename, MAX_WAV_FILENAME_LENGTH -1, pathname);
+ usrPtr->sounds[ii].wav_filename[MAX_WAV_FILENAME_LENGTH -1] = '\0';
+ usrPtr->sounds[ii].offset_to_first_sample = 0;
+ usrPtr->sounds[ii].fpWav = gap_audio_wav_open_seek_data(usrPtr->sounds[ii].wav_filename);
+ }
+
+ if(usrPtr->sounds[ii].fpWav == NULL)
+ {
+ rc = 3; /* failed to open audio data file */
+ }
+ else
+ {
+ /* store current file offset (position of the 1st audio sample data byte) */
+ usrPtr->sounds[ii].offset_to_first_sample = ftell(usrPtr->sounds[ii].fpWav);
+ }
+ }
+
+ }
+ }
+
+ if ( (rc != 0) && (erf != NULL) )
+ {
+ if (pathname != NULL)
+ {
+ // TODO provide to_string for errorcodes rc
+ call_errfunc(erf, "path: Not a valid RIFF WAVE file %s rc:%d (%s)", pathname, rc, " ");
+ }
+ else
+ {
+ call_errfunc(erf, "path: is NULL (name of RIFF WAVE file was expected).");
+ }
+ }
+
+ return (rc);
+
+} /* end gap_sdl_path */
+
+
+/* -------------------------------------
+ * gap_sdl_volume
+ * -------------------------------------
+ * Tell audio_player to use mix volume (0.0 upto 1.0)
+ * (Note: this does not set the hardware audio volume,
+ * values smaller than 1 may reduce the sound quality due to data loss while mix down)
+ */
+int
+gap_sdl_volume(double volume, int flags, GapSdlErrFunc erf)
+{
+ int rc = 1;
+ AudioPlaybackThreadUserData *usrPtr;
+
+ usrPtr = getUsrPtr();
+ if (usrPtr != NULL)
+ {
+ if ((volume >= 0.0) && (volume <= 1.0))
+ {
+ int ii = 0;
+ gdouble mixVolumeDouble;
+
+ SDL_LockAudio();
+ mixVolumeDouble = SDL_MIX_MAXVOLUME;
+ mixVolumeDouble = mixVolumeDouble * volume;
+ usrPtr->sounds[ii].mix_volume = (int)mixVolumeDouble;
+ SDL_UnlockAudio();
+
+ rc = 0; /* OK */
+ }
+ }
+
+ if ( (rc != 0) && (erf != NULL) )
+ {
+ call_errfunc(erf, "volume: value %f not accepted (valid range is 0.0 to 1.0)", (float)volume);
+ }
+
+ return (rc);
+
+} /* end gap_sdl_volume */
+
+
+/* -------------------------------------
+ * gap_sdl_channels
+ * -------------------------------------
+ * Tell audio_player the number of channels
+ */
+int
+gap_sdl_channels(int flags,GapSdlErrFunc erf, int channels)
+{
+ int rc = 1;
+ AudioPlaybackThreadUserData *usrPtr;
+
+ usrPtr = getUsrPtr();
+ if (usrPtr != NULL)
+ {
+ usrPtr->channels = channels;
+ usrPtr->frame_size = (usrPtr->bits_per_sample / 8) * usrPtr->channels;
+ rc = 0; /* OK */
+ }
+
+ if ( (rc != 0) && (erf != NULL) )
+ {
+ call_errfunc(erf, "channels: %d not accepted", channels);
+ }
+
+ return (rc);
+
+} /* end gap_sdl_channels */
+
+
+/* -------------------------------------
+ * gap_sdl_bits
+ * -------------------------------------
+ * Tell audio_player about new data bits per sample and sample format setting:
+ * flags: 0 signed sample little endian (AUDIO_S8, AUDIO_S16LSB)
+ * flags: 1 unsigned sample little endian (AUDIO_U8, AUDIO_U16LSB)
+ * flags: 2 signed sample big endian (AUDIO_S16MSB)
+ * flags: 3 unsigned sample big endian (AUDIO_U16MSB)
+ */
+int
+gap_sdl_bits(int flags,GapSdlErrFunc erf,int bits)
+{
+ int rc = 1;
+ AudioPlaybackThreadUserData *usrPtr;
+
+ usrPtr = getUsrPtr();
+ if (usrPtr != NULL)
+ {
+ rc = 0; /* OK */
+ switch (bits)
+ {
+ case 8:
+ usrPtr->bits_per_sample = bits;
+ if ((flags & 1) != 0) { usrPtr->format = AUDIO_U8; }
+ else { usrPtr->format = AUDIO_S8; }
+ break;
+ case 16:
+ usrPtr->bits_per_sample = bits;
+ if ((flags & 3) == 1) { usrPtr->format = AUDIO_U16LSB; }
+ else if ((flags & 3) == 2) { usrPtr->format = AUDIO_S16MSB; }
+ else if ((flags & 3) == 3) { usrPtr->format = AUDIO_U16MSB; }
+ else { usrPtr->format = AUDIO_S16; } /* same as AUDIO_S16LSB */
+ break;
+ default:
+ rc = 2; /* unsupported bits_per_channel value */
+ break;
+ }
+ usrPtr->frame_size = (usrPtr->bits_per_sample / 8) * usrPtr->channels;
+ }
+
+ if ( (rc != 0) && (erf != NULL) )
+ {
+ call_errfunc(erf, "bits: %d not accepted", bits);
+ }
+
+ return (rc);
+
+} /* end gap_sdl_bits */
+
+
+
+
+/* -------------------------------------
+ * gap_sdl_sampling_rate
+ * -------------------------------------
+ * Tell audio_player to use new sampling rate:
+ */
+int
+gap_sdl_sampling_rate(int flags,GapSdlErrFunc erf,Uint32 sampling_rate)
+{
+ int rc = 1;
+ AudioPlaybackThreadUserData *usrPtr;
+
+ usrPtr = getUsrPtr();
+ if (usrPtr != NULL)
+ {
+ usrPtr->samplerate = sampling_rate;
+ rc = 0; /* OK */
+ }
+
+ if ( (rc != 0) && (erf != NULL) )
+ {
+ call_errfunc(erf, "sampling_rate: %d not accepted", sampling_rate);
+ }
+
+ return (rc);
+
+} /* end gap_sdl_sampling_rate */
+
+
+
+
+/* -------------------------------------
+ * gap_sdl_start_sample
+ * -------------------------------------
+ * Tell audio_player to start at a new sample number:
+ */
+int
+gap_sdl_start_sample(int flags, GapSdlErrFunc erf, Uint32 sample)
+{
+ int rc = 1;
+ int ii = 0;
+ AudioPlaybackThreadUserData *usrPtr;
+
+ usrPtr = getUsrPtr();
+ if (usrPtr != NULL)
+ {
+ usrPtr->sounds[ii].start_at_sample = sample;
+ rc = 0; /* OK */
+ }
+
+ if ( (rc != 0) && (erf != NULL) )
+ {
+ call_errfunc(erf, "start_sample: %d not accepted", (int)sample);
+ }
+
+ return rc;
+
+} /* end gap_sdl_start_sample */
+
+
+
+/* -------------------------------------
+ * msg_name
+ * -------------------------------------
+ * convert int cmd to readable string representation.
+ */
+static const char *
+msg_name(int cmd)
+{
+ switch(cmd)
+ {
+ case GAP_SDL_CMD_Bye:
+ return ("GAP_SDL_CMD_Bye");
+ break;
+ case GAP_SDL_CMD_Play:
+ return ("GAP_SDL_CMD_Play");
+ break;
+ case GAP_SDL_CMD_Pause:
+ return ("GAP_SDL_CMD_Pause");
+ break;
+ case GAP_SDL_CMD_Stop:
+ return ("GAP_SDL_CMD_Stop");
+ break;
+ case GAP_SDL_CMD_Restore:
+ return ("GAP_SDL_CMD_Restore");
+ break;
+ case GAP_SDL_CMD_SemReset:
+ return ("GAP_SDL_CMD_SemReset");
+ break;
+ }
+ return ("unknown");
+
+} /* end msg_name */
+
+
+/* -------------------------------------
+ * gap_sdl_cmd
+ * -------------------------------------
+ * perform simple audio_player command .
+ * Note: some of the commands do not make sense
+ * in this SDL based implementation
+ * and are just dummies for compatibility with the
+ * API (that was designed base on the older wavplay client functions)
+ */
+int
+gap_sdl_cmd(int cmd,int flags,GapSdlErrFunc erf) {
+ static char *sdl_no_error_available = "";
+ char *sdl_error;
+ int rc = 1;
+ AudioPlaybackThreadUserData *usrPtr;
+
+
+ sdl_error = sdl_no_error_available;
+ usrPtr = getUsrPtr();
+ if (usrPtr != NULL)
+ {
+ if(gap_debug)
+ {
+ printf("gap_sdl_cmd cmd:%d (%s) flags:%d SdlAudioStatus:%d\n"
+ , cmd
+ , msg_name(cmd)
+ , flags
+ , (int)SDL_GetAudioStatus()
+ );
+ }
+ switch(cmd)
+ {
+ case GAP_SDL_CMD_Bye:
+ stop_audio();
+ close_files();
+ rc = 0; /* OK */
+ break;
+ case GAP_SDL_CMD_Play:
+ rc = start_audio();
+ sdl_error = SDL_GetError(); /* SDL_GetError uses sttically allocated message that must NOT be freed */
+ break;
+ case GAP_SDL_CMD_Pause:
+ stop_audio();
+ rc = 0; /* OK */
+ break;
+ case GAP_SDL_CMD_Stop:
+ stop_audio();
+ close_files();
+ rc = 0; /* OK */
+ break;
+ case GAP_SDL_CMD_Restore:
+ stop_audio();
+ rc = 0; /* OK */
+ break;
+ case GAP_SDL_CMD_SemReset:
+ rc = 0; /* OK */
+ break;
+ }
+
+ }
+
+
+ if ((rc != 0) && (erf != NULL ))
+ {
+ call_errfunc(erf, "%s: Sending cmd%d to audio_player failed (rc:%d) err:%s",
+ msg_name(cmd),
+ cmd,
+ sdl_error,
+ rc);
+ }
+ if(gap_debug)
+ {
+ printf("gap_sdl_cmd cmd:%d (%s) flags:%d retcode:%d\n", cmd, msg_name(cmd), flags, rc);
+ }
+ return rc; /* Zero indicates success */
+
+} /* end gap_sdl_cmd */
diff --git a/gap/gap_sdl_audioplayer.h b/gap/gap_sdl_audioplayer.h
new file mode 100644
index 0000000..f3044e7
--- /dev/null
+++ b/gap/gap_sdl_audioplayer.h
@@ -0,0 +1,129 @@
+/* gap_sdl_audioplayer.h
+ * provides audio wavefile playback via SDL medialibrary.
+ * (SDL is available for Linux, Windows and MacOS)
+ *
+ * This player uses an interface that is compatible with
+ * the wavplay client wrapper, but adds support for playback of
+ * audio pcm data from a preloaded memory buffer.
+ *
+ * Note that the (older) wavplay server/client based audioplayback
+ * may be configured at compiletime as alternative on Linux only.
+ *
+ */
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program 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 Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _GAP_SDL_AUDIOPLAYER_H
+#define _GAP_SDL_AUDIOPLAYER_H
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <SDL.h>
+#include <SDL_audio.h>
+
+
+
+
+typedef void (*GapSdlErrFunc)(const char *format,va_list ap);
+
+#define GAP_SDL_CMD_Bye 0
+#define GAP_SDL_CMD_Play 1
+#define GAP_SDL_CMD_Pause 2
+#define GAP_SDL_CMD_Stop 3
+#define GAP_SDL_CMD_Restore 4
+#define GAP_SDL_CMD_SemReset 5
+
+
+/*
+ * start the audio_playback thread.
+ */
+int gap_sdl_start(GapSdlErrFunc erf);
+
+/*
+ * Tell audio_player a buffer with PCM audiodata
+ * Fetch of audio data switches to the specified memory buffer
+ * where following default playback settings are automatically established:
+ * samplerate: 44100 Hz.
+ * bits: 16 (SND_PCM_FORMAT_S16_LE)
+ * channels: 2
+ *
+ * IMPORTANT: the buffer MUST be aligned at short boundaries
+ * (e.g do not allocate the memory as char that would lead to a crash)
+ */
+int apcl_memory_buffer(char *buffer, long buffer_len, GapSdlErrFunc erf);
+
+/*
+ * Send simple command to audio_player:
+ */
+int gap_sdl_cmd(int cmd, int flags, GapSdlErrFunc erf);
+
+/*
+ * Send a pathname to the audio_player:
+ * The patrhname must refere to a RIFF WAVE fmt file.
+ *
+ * Note: to trigger audio playback the
+ * audio_playback thread must be started { call gap_sdl_start(NULL) }
+ * and playback must be turned on (call gap_sdl_cmd(GAP_SDL_CMD_Play,0,NULL)
+ *
+ * flags: 0 set audio hardware parameters (samplerate, channels,...) from the wavefile specified by path.
+ * flags: 1 keep current audio hardware parameters.
+ * (you may use this in case your program has already explicite set
+ * the wanted samplerate, channels, ... )
+ *
+ * returns 0 OK, 1 if pathname is not readable as valid RIFF WAVE file.
+ */
+int gap_sdl_path(const char *pathname, int flags, GapSdlErrFunc erf);
+
+/*
+ * Tell audio_player about new data bits per sample and sample format setting:
+ * flags: 0 signed sample little endian (AUDIO_S8, AUDIO_S16LSB)
+ * flags: 1 unsigned sample little endian (AUDIO_U8, AUDIO_U16LSB)
+ * flags: 2 signed sample big endian (AUDIO_S16MSB)
+ * flags: 3 unsigned sample big endian (AUDIO_U16MSB)
+ */
+int gap_sdl_bits(int flags,GapSdlErrFunc erf,int bits);
+
+/*
+ * Tell audio_player to start at a new sample number:
+ */
+int gap_sdl_start_sample(int flags, GapSdlErrFunc erf, Uint32 sample);
+
+/*
+ * Tell audio_player to use new sampling rate:
+ */
+int gap_sdl_sampling_rate(int flags, GapSdlErrFunc erf, Uint32 sampling_rate);
+
+/*
+ * Tell audio_player to use new number of channels (1 for Mono, 2 for Stereo)
+ */
+int gap_sdl_channels(int flags,GapSdlErrFunc erf, int channels);
+
+/*
+ * Tell audio_player to use mix volume (0.0 upto 1.0)
+ *
+ * flags: 0 use mix volume. Note that this does not set the hardware audio volume,
+ * but downscales all processed samples.
+ * (Where values smaller than 1 may reduce the sound quality
+ * due to data loss while mix down)
+ * flags: 1 use master volume of the audio device (TODO: NOT YET supported)
+ */
+int gap_sdl_volume(double volume, int flags, GapSdlErrFunc erf);
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]