mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-04-22 07:30:50 +00:00
Added libsndfile support to fluid_filerenderer.c with file type, audio format and endian byte order options.
Added 3 additional parameters to new_fluid_file_renderer() for specifying audio format options. Added public functions fluid_file_renderer_get_(type/format/endian)_names. Added new settings options "audio.file.(type/format/endian)". fluid_aufile.c updated to use new file renderer. fluid_settings_add_option and fluid_settings_remove_option now use const char *. Added FLUID_N_ELEMENTS and FLUID_MUTEX_INIT to fluid_sys.h. Added -E, -O and -T command line options and help for file rendering options. Re-organized --help output to be lower case letter before upper case. Added FLUID_STRRCHR to fluidsynth_priv.h.
This commit is contained in:
parent
43a9923dff
commit
e0a18f7c2a
11 changed files with 577 additions and 87 deletions
|
@ -157,6 +157,25 @@ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.10 gthread-2.0 >= 2.10)
|
|||
AC_SUBST(GLIB_CFLAGS)
|
||||
AC_SUBST(GLIB_LIBS)
|
||||
|
||||
dnl Check for libsndfile support
|
||||
|
||||
AC_ARG_ENABLE(libsndfile-support, AS_HELP_STRING([--disable-libsndfile-support],
|
||||
[Do not compile libsndfile support (default=auto)]),
|
||||
enable_libsndfile_support=$enableval, enable_libsndfile_support="yes")
|
||||
|
||||
if test "x$enable_libsndfile_support" != "xno"; then
|
||||
PKG_CHECK_MODULES(LIBSNDFILE, sndfile >= 1.0.0, LIBSNDFILE_SUPPORT=1, LIBSNDFILE_SUPPORT=0)
|
||||
else
|
||||
LIBSNDFILE_SUPPORT=0
|
||||
fi
|
||||
|
||||
if test "$LIBSNDFILE_SUPPORT" = "1"; then
|
||||
AC_DEFINE(LIBSNDFILE_SUPPORT, 1, [Define to enable libsndfile support])
|
||||
fi
|
||||
AM_CONDITIONAL(LIBSNDFILE_SUPPORT, test "$LIBSNDFILE_SUPPORT" = "1")
|
||||
AC_SUBST(LIBSNDFILE_CFLAGS)
|
||||
AC_SUBST(LIBSNDFILE_LIBS)
|
||||
|
||||
|
||||
dnl
|
||||
dnl Check support for all the drivers
|
||||
|
@ -423,6 +442,12 @@ echo
|
|||
echo "**************************************************************"
|
||||
echo "Summary:"
|
||||
|
||||
if test "${LIBSNDFILE_SUPPORT}" = "1"; then
|
||||
echo "libsndfile: yes"
|
||||
else
|
||||
echo "libsndfile: no (raw audio file rendering only)"
|
||||
fi
|
||||
|
||||
if test "${PULSE_SUPPORT}" = "1"; then
|
||||
echo "PulseAudio: yes"
|
||||
else
|
||||
|
|
|
@ -67,11 +67,15 @@ FLUIDSYNTH_API void delete_fluid_audio_driver(fluid_audio_driver_t* driver);
|
|||
|
||||
FLUIDSYNTH_API void fluid_audio_driver_get_names(char* buf, size_t buflen, const char* separator);
|
||||
|
||||
|
||||
FLUIDSYNTH_API fluid_file_renderer_t* new_fluid_file_renderer(fluid_synth_t* synth,
|
||||
char* filename, int period_size);
|
||||
FLUIDSYNTH_API fluid_file_renderer_t *new_fluid_file_renderer(fluid_synth_t* synth,
|
||||
char* filename, char* type,
|
||||
char* format, char* endian,
|
||||
int period_size);
|
||||
FLUIDSYNTH_API int fluid_file_renderer_process_block(fluid_file_renderer_t* dev);
|
||||
FLUIDSYNTH_API void delete_fluid_file_renderer(fluid_file_renderer_t* dev);
|
||||
FLUIDSYNTH_API const char **fluid_file_renderer_get_type_names (void);
|
||||
FLUIDSYNTH_API const char **fluid_file_renderer_get_format_names (void);
|
||||
FLUIDSYNTH_API const char **fluid_file_renderer_get_endian_names (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -126,12 +126,12 @@ libfluidsynth_la_SOURCES = \
|
|||
|
||||
INCLUDES = -I$(top_srcdir)/include $(LASH_CFLAGS) $(LADCCA_CFLAGS) \
|
||||
$(READLINE_CFLAGS) $(JACK_CFLAGS) $(ALSA_CFLAGS) $(PULSE_CFLAGS) \
|
||||
$(PORTAUDIO_CFLAGS) $(DART_CFLAGS) $(GLIB_CFLAGS)
|
||||
$(PORTAUDIO_CFLAGS) $(DART_CFLAGS) $(GLIB_CFLAGS) $(LIBSNDFILE_CFLAGS)
|
||||
|
||||
libfluidsynth_la_LIBADD = $(LIBFLUID_LIBS) $(LASH_LIBS) $(LADCCA_LIBS) \
|
||||
$(READLINE_LIBS) $(COREAUDIO_LIBS) $(COREMIDI_LIBS) $(JACK_LIBS) \
|
||||
$(ALSA_LIBS) $(PULSE_LIBS) $(PORTAUDIO_LIBS) $(DART_LIBS) \
|
||||
$(GLIB_LIBS)
|
||||
$(GLIB_LIBS) $(LIBSNDFILE_LIBS)
|
||||
|
||||
libfluidsynth_la_LDFLAGS = \
|
||||
-version-info @LT_VERSION_INFO@ \
|
||||
|
|
|
@ -132,6 +132,9 @@
|
|||
/* Include the LADSPA Fx unit */
|
||||
#undef LADSPA
|
||||
|
||||
/* Define to enable libsndfile support */
|
||||
#undef LIBSNDFILE_SUPPORT
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#undef LT_OBJDIR
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "fluid_adriver.h"
|
||||
#include "fluid_settings.h"
|
||||
#include "fluid_sys.h"
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
@ -62,7 +63,36 @@ static int fluid_file_audio_run_s16(void* d, unsigned int msec);
|
|||
|
||||
void fluid_file_audio_driver_settings(fluid_settings_t* settings)
|
||||
{
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
const char **names, **np;
|
||||
int i;
|
||||
#endif
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
fluid_settings_register_str(settings, "audio.file.name", "fluidsynth.wav", 0, NULL, NULL);
|
||||
fluid_settings_register_str(settings, "audio.file.type", "auto", 0, NULL, NULL);
|
||||
fluid_settings_register_str(settings, "audio.file.format", "s16", 0, NULL, NULL);
|
||||
fluid_settings_register_str(settings, "audio.file.endian", "auto", 0, NULL, NULL);
|
||||
|
||||
fluid_settings_add_option (settings, "audio.file.type", "auto");
|
||||
|
||||
names = fluid_file_renderer_get_type_names ();
|
||||
for (np = names; *np; np++)
|
||||
fluid_settings_add_option(settings, "audio.file.type", *np);
|
||||
|
||||
names = fluid_file_renderer_get_format_names ();
|
||||
for (np = names; *np; np++)
|
||||
fluid_settings_add_option(settings, "audio.file.format", *np);
|
||||
|
||||
names = fluid_file_renderer_get_endian_names ();
|
||||
for (np = names; *np; np++)
|
||||
fluid_settings_add_option(settings, "audio.file.endian", *np);
|
||||
#else
|
||||
fluid_settings_register_str(settings, "audio.file.name", "fluidsynth.raw", 0, NULL, NULL);
|
||||
fluid_settings_register_str(settings, "audio.file.type", "raw", 0, NULL, NULL);
|
||||
fluid_settings_register_str(settings, "audio.file.format", "s16", 0, NULL, NULL);
|
||||
fluid_settings_register_str(settings, "audio.file.endian", "cpu", 0, NULL, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -72,7 +102,7 @@ new_fluid_file_audio_driver(fluid_settings_t* settings,
|
|||
{
|
||||
fluid_file_audio_driver_t* dev;
|
||||
int err;
|
||||
char* filename = NULL;
|
||||
char* filename = NULL, *type = NULL, *format = NULL, *endian = NULL;
|
||||
int msec;
|
||||
|
||||
dev = FLUID_NEW(fluid_file_audio_driver_t);
|
||||
|
@ -94,14 +124,21 @@ new_fluid_file_audio_driver(fluid_settings_t* settings,
|
|||
goto error_recovery;
|
||||
}
|
||||
|
||||
dev->renderer = new_fluid_file_renderer(synth, filename, dev->period_size);
|
||||
fluid_settings_dupstr (settings, "audio.file.type", &type); /* ++ alloc file type */
|
||||
fluid_settings_dupstr (settings, "audio.file.format", &format); /* ++ alloc file format */
|
||||
fluid_settings_dupstr (settings, "audio.file.endian", &endian); /* ++ alloc file endian */
|
||||
|
||||
dev->renderer = new_fluid_file_renderer(synth, filename, type, format, endian,
|
||||
dev->period_size);
|
||||
if (filename) FLUID_FREE (filename); /* -- free filename */
|
||||
if (type) FLUID_FREE (type); /* -- free type */
|
||||
if (format) FLUID_FREE (format); /* -- free format */
|
||||
if (endian) FLUID_FREE (endian); /* -- free endian */
|
||||
|
||||
if (dev->renderer == NULL) {
|
||||
if (filename) FLUID_FREE (filename); /* -- free filename */
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
if (filename) FLUID_FREE (filename); /* -- free filename */
|
||||
|
||||
msec = (int) (0.5 + dev->period_size / dev->sample_rate * 1000.0);
|
||||
dev->timer = new_fluid_timer(msec, fluid_file_audio_run_s16, (void*) dev, TRUE, FALSE, TRUE);
|
||||
if (dev->timer == NULL) {
|
||||
|
|
|
@ -24,15 +24,203 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_synth.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
#include <sndfile.h>
|
||||
#endif
|
||||
|
||||
struct _fluid_file_renderer_t {
|
||||
FILE* file;
|
||||
fluid_synth_t* synth;
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
SNDFILE* sndfile;
|
||||
float* buf;
|
||||
#else
|
||||
FILE* file;
|
||||
short* buf;
|
||||
#endif
|
||||
|
||||
int period_size;
|
||||
int buf_size;
|
||||
};
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
|
||||
/* Default file type used, if none specified and auto extension search fails */
|
||||
#define FLUID_FILE_RENDERER_DEFAULT_FILE_TYPE SF_FORMAT_WAV
|
||||
|
||||
/* File audio format names.
|
||||
* !! Keep in sync with format_ids[] */
|
||||
const char *format_names[] = {
|
||||
"s8",
|
||||
"s16",
|
||||
"s24",
|
||||
"s32",
|
||||
"u8",
|
||||
"float",
|
||||
"double",
|
||||
NULL /* Terminator */
|
||||
};
|
||||
|
||||
|
||||
/* File audio format IDs.
|
||||
* !! Keep in sync with format_names[] */
|
||||
const int format_ids[] = {
|
||||
SF_FORMAT_PCM_S8,
|
||||
SF_FORMAT_PCM_16,
|
||||
SF_FORMAT_PCM_24,
|
||||
SF_FORMAT_PCM_32,
|
||||
SF_FORMAT_PCM_U8,
|
||||
SF_FORMAT_FLOAT,
|
||||
SF_FORMAT_DOUBLE
|
||||
};
|
||||
|
||||
/* File endian byte order names.
|
||||
* !! Keep in sync with endian_ids[] */
|
||||
const char *endian_names[] = {
|
||||
"auto",
|
||||
"little",
|
||||
"big",
|
||||
"cpu",
|
||||
NULL
|
||||
};
|
||||
|
||||
/* File endian byte order ids.
|
||||
* !! Keep in sync with endian_names[] */
|
||||
const int endian_ids[] = {
|
||||
SF_ENDIAN_FILE,
|
||||
SF_ENDIAN_LITTLE,
|
||||
SF_ENDIAN_BIG,
|
||||
SF_ENDIAN_CPU
|
||||
};
|
||||
|
||||
static int fluid_file_renderer_parse_options (char *filetype, char *format,
|
||||
char *endian, char *filename, SF_INFO *info);
|
||||
static int fluid_file_renderer_find_file_type (char *extension, int *type);
|
||||
|
||||
|
||||
#else /* No libsndfile support */
|
||||
|
||||
|
||||
/* File type names. */
|
||||
char *type_names[] = {
|
||||
"raw",
|
||||
NULL /* Terminator */
|
||||
};
|
||||
|
||||
/* File audio format names. */
|
||||
char *format_names[] = {
|
||||
"s16",
|
||||
NULL /* Terminator */
|
||||
};
|
||||
|
||||
/* File endian byte order names. */
|
||||
char *endian_names[] = {
|
||||
"cpu",
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Create a new file renderer and open the file.
|
||||
* @param synth The synth that creates audio data.
|
||||
* @param filename Output filename
|
||||
* @param type File type string or NULL for default "auto", which tries to
|
||||
* determine format from filename extension or uses "wav".
|
||||
* @param format Audio format string (can be empty or NULL for default format "s16")
|
||||
* @param endian Endian specification or NULL for default "auto", which uses
|
||||
* the file type's usual byte order.
|
||||
* @param period_size Sample count, amount of samples to write to the file at
|
||||
* every call to fluid_file_renderer_process_block().
|
||||
* @return the new object, or NULL on failure
|
||||
* @since: 1.1.0
|
||||
*/
|
||||
fluid_file_renderer_t *
|
||||
new_fluid_file_renderer(fluid_synth_t* synth, char* filename, char* type,
|
||||
char* format, char* endian, int period_size)
|
||||
{
|
||||
fluid_file_renderer_t* dev;
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
SF_INFO info;
|
||||
double samplerate;
|
||||
#endif
|
||||
|
||||
dev = FLUID_NEW(fluid_file_renderer_t);
|
||||
if (dev == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
FLUID_MEMSET(dev, 0, sizeof(fluid_file_renderer_t));
|
||||
|
||||
dev->synth = synth;
|
||||
dev->period_size = period_size;
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
dev->buf_size = 2 * dev->period_size * sizeof (float);
|
||||
dev->buf = FLUID_ARRAY(float, 2 * dev->period_size);
|
||||
#else
|
||||
dev->buf_size = 2 * dev->period_size * sizeof (short);
|
||||
dev->buf = FLUID_ARRAY(short, 2 * dev->period_size);
|
||||
#endif
|
||||
|
||||
if (dev->buf == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
if (filename == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "No file name specified");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
memset (&info, 0, sizeof (info));
|
||||
|
||||
info.format = FLUID_FILE_RENDERER_DEFAULT_FILE_TYPE | SF_FORMAT_PCM_16;
|
||||
|
||||
if (!fluid_file_renderer_parse_options (type, format, endian, filename, &info))
|
||||
goto error_recovery;
|
||||
|
||||
fluid_settings_getnum (synth->settings, "synth.sample-rate", &samplerate);
|
||||
info.samplerate = samplerate + 0.5;
|
||||
info.channels = 2;
|
||||
|
||||
if (!sf_format_check (&info))
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Invalid or unsupported audio file format settings");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
dev->sndfile = sf_open (filename, SFM_WRITE, &info);
|
||||
|
||||
if (!dev->sndfile)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Failed to open audio file '%s' for writing", filename);
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
/* Turn on clipping and normalization of floats (-1.0 - 1.0) */
|
||||
sf_command (dev->sndfile, SFC_SET_CLIPPING, NULL, SF_TRUE);
|
||||
sf_command (dev->sndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE);
|
||||
#else
|
||||
dev->file = fopen(filename, "wb");
|
||||
if (dev->file == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Failed to open the file '%s'", filename);
|
||||
goto error_recovery;
|
||||
}
|
||||
#endif
|
||||
|
||||
return dev;
|
||||
|
||||
error_recovery:
|
||||
delete_fluid_file_renderer(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close file and destroy a file renderer object.
|
||||
* @param dev File renderer object.
|
||||
|
@ -44,9 +232,17 @@ void delete_fluid_file_renderer(fluid_file_renderer_t* dev)
|
|||
return;
|
||||
}
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
if (dev->sndfile != NULL) {
|
||||
int retval = sf_close (dev->sndfile);
|
||||
if (retval != 0) FLUID_LOG (FLUID_WARN, "Error closing audio file: %s",
|
||||
sf_error_number (retval));
|
||||
}
|
||||
#else
|
||||
if (dev->file != NULL) {
|
||||
fclose(dev->file);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dev->buf != NULL) {
|
||||
FLUID_FREE(dev->buf);
|
||||
|
@ -56,62 +252,32 @@ void delete_fluid_file_renderer(fluid_file_renderer_t* dev)
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new file renderer and open the file.
|
||||
* @param synth The synth that creates audio data.
|
||||
* @param filename Output filename
|
||||
* @param period_size Sample count, amount of samples to write to the file at
|
||||
* every call to fluid_file_renderer_process_block().
|
||||
* @return the new object, or NULL on failure
|
||||
* @since: 1.1.0
|
||||
*/
|
||||
fluid_file_renderer_t* new_fluid_file_renderer(fluid_synth_t* synth, char* filename, int period_size)
|
||||
{
|
||||
fluid_file_renderer_t* dev;
|
||||
|
||||
dev = FLUID_NEW(fluid_file_renderer_t);
|
||||
if (dev == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
FLUID_MEMSET(dev, 0, sizeof(fluid_file_renderer_t));
|
||||
|
||||
dev->synth = synth;
|
||||
dev->period_size = period_size;
|
||||
dev->buf_size = 2 * dev->period_size * sizeof(short);
|
||||
|
||||
dev->buf = FLUID_ARRAY(short, 2 * dev->period_size);
|
||||
if (dev->buf == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
if (filename == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "No file name specified");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
dev->file = fopen(filename, "wb");
|
||||
if (dev->file == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Failed to open the file '%s'", filename);
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
return dev;
|
||||
|
||||
error_recovery:
|
||||
delete_fluid_file_renderer(dev);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
/**
|
||||
* Write period_size samples to file.
|
||||
* @param dev File renderer instance
|
||||
* @return FLUID_OK or FLUID_FAILED if an error occurred
|
||||
* @since: 1.1.0
|
||||
*/
|
||||
int fluid_file_renderer_process_block(fluid_file_renderer_t* dev)
|
||||
int
|
||||
fluid_file_renderer_process_block(fluid_file_renderer_t* dev)
|
||||
{
|
||||
int n;
|
||||
|
||||
fluid_synth_write_float(dev->synth, dev->period_size, dev->buf, 0, 2, dev->buf, 1, 2);
|
||||
|
||||
n = sf_writef_float (dev->sndfile, dev->buf, dev->period_size);
|
||||
|
||||
if (n != dev->period_size) {
|
||||
FLUID_LOG (FLUID_ERR, "Audio file write error: %s",
|
||||
sf_strerror (dev->sndfile));
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
return FLUID_OK;
|
||||
}
|
||||
#else /* No libsndfile support */
|
||||
int
|
||||
fluid_file_renderer_process_block(fluid_file_renderer_t* dev)
|
||||
{
|
||||
int n, offset;
|
||||
|
||||
|
@ -129,3 +295,188 @@ int fluid_file_renderer_process_block(fluid_file_renderer_t* dev)
|
|||
return FLUID_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
/**
|
||||
* Get NULL terminated list of supported audio file type names.
|
||||
* @return NULL terminated list of strings which is internal and should not be
|
||||
* modified or freed. NOTE: May return NULL if memory allocation fails.
|
||||
*/
|
||||
const char **
|
||||
fluid_file_renderer_get_type_names (void)
|
||||
{
|
||||
static fluid_mutex_t mutex = FLUID_MUTEX_INIT;
|
||||
static const char **type_names = NULL;
|
||||
SF_FORMAT_INFO finfo;
|
||||
int major_count;
|
||||
int i, i2, index;
|
||||
|
||||
fluid_mutex_lock (mutex);
|
||||
|
||||
if (!type_names)
|
||||
{
|
||||
sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof (int));
|
||||
|
||||
type_names = FLUID_ARRAY (const char *, major_count + 1);
|
||||
|
||||
if (type_names)
|
||||
{
|
||||
for (i = 0, index = 0; i < major_count; i++)
|
||||
{
|
||||
finfo.format = i;
|
||||
sf_command (NULL, SFC_GET_FORMAT_MAJOR, &finfo, sizeof (finfo));
|
||||
|
||||
/* Check for duplicates */
|
||||
for (i2 = 0; i2 < index; i2++)
|
||||
if (strcmp (type_names[i2], finfo.extension) == 0)
|
||||
break;
|
||||
|
||||
if (i2 < index) continue;
|
||||
|
||||
type_names[index++] = finfo.extension; /* Add name to array */
|
||||
}
|
||||
|
||||
type_names[index] = NULL;
|
||||
}
|
||||
else FLUID_LOG (FLUID_ERR, "Out of memory");
|
||||
}
|
||||
|
||||
fluid_mutex_unlock (mutex);
|
||||
|
||||
return (const char **)type_names;
|
||||
}
|
||||
#else
|
||||
const char **
|
||||
fluid_file_renderer_get_type_names (void)
|
||||
{
|
||||
return type_names;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
const char **
|
||||
fluid_file_renderer_get_format_names (void)
|
||||
{
|
||||
return format_names;
|
||||
}
|
||||
|
||||
const char **
|
||||
fluid_file_renderer_get_endian_names (void)
|
||||
{
|
||||
return endian_names;
|
||||
}
|
||||
|
||||
|
||||
#if LIBSNDFILE_SUPPORT
|
||||
|
||||
/**
|
||||
* Parse a colon separated format string and configure an SF_INFO structure accordingly.
|
||||
* @param filetype File type string (NULL or "auto" to attempt to identify format
|
||||
* by filename extension, with fallback to "wav")
|
||||
* @param format File audio format string or NULL to use "s16"
|
||||
* @param endian File endian string or NULL to use "auto" which uses the file type's
|
||||
* default endian byte order.
|
||||
* @param filename File name (used by "auto" type to determine type, based on extension)
|
||||
* @param info Audio file info structure to configure
|
||||
* @return TRUE on success, FALSE otherwise
|
||||
*/
|
||||
static int
|
||||
fluid_file_renderer_parse_options (char *filetype, char *format, char *endian,
|
||||
char *filename, SF_INFO *info)
|
||||
{
|
||||
int type = -1; /* -1 indicates "auto" type */
|
||||
char *s;
|
||||
int i;
|
||||
|
||||
/* If "auto" type, then use extension to search for a match */
|
||||
if (!filetype || FLUID_STRCMP (filetype, "auto") == 0)
|
||||
{
|
||||
type = FLUID_FILE_RENDERER_DEFAULT_FILE_TYPE;
|
||||
s = FLUID_STRRCHR (filename, '.');
|
||||
|
||||
if (s && s[1] != '\0')
|
||||
{
|
||||
if (!fluid_file_renderer_find_file_type (s + 1, &type))
|
||||
FLUID_LOG (FLUID_WARN, "Failed to determine audio file type from filename, defaulting to WAV");
|
||||
}
|
||||
}
|
||||
else if (!fluid_file_renderer_find_file_type (filetype, &type))
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Invalid or unsupported audio file type '%s'", filetype);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
info->format = (info->format & ~SF_FORMAT_TYPEMASK) | type;
|
||||
|
||||
/* Look for subtype */
|
||||
if (format)
|
||||
{
|
||||
for (i = 0; format_names[i]; i++)
|
||||
if (FLUID_STRCMP (format, format_names[i]) == 0)
|
||||
break;
|
||||
|
||||
if (!format_names[i])
|
||||
{
|
||||
FLUID_LOG (FLUID_ERR, "Invalid or unsupported file audio format '%s'", format);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
info->format = (info->format & ~SF_FORMAT_SUBMASK) | format_ids[i];
|
||||
}
|
||||
|
||||
/* Look for endian */
|
||||
if (endian)
|
||||
{
|
||||
for (i = 0; endian_names[i]; i++)
|
||||
if (FLUID_STRCMP (endian, endian_names[i]) == 0)
|
||||
break;
|
||||
|
||||
if (!endian_names[i])
|
||||
{
|
||||
FLUID_LOG (FLUID_ERR, "Invalid or unsupported endian byte order '%s'", endian);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
info->format = (info->format & ~SF_FORMAT_ENDMASK) | endian_ids[i];
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a supported libsndfile file type by extension.
|
||||
* @param extension The extension string
|
||||
* @param ext_len Length of the extension string
|
||||
* @param type Location to store the type (unmodified if not found)
|
||||
* @return TRUE if found, FALSE otherwise
|
||||
*/
|
||||
static int
|
||||
fluid_file_renderer_find_file_type (char *extension, int *type)
|
||||
{
|
||||
SF_FORMAT_INFO finfo;
|
||||
int major_count;
|
||||
int i;
|
||||
|
||||
sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof (int));
|
||||
|
||||
for (i = 0; i < major_count; i++)
|
||||
{
|
||||
finfo.format = i;
|
||||
sf_command (NULL, SFC_GET_FORMAT_MAJOR, &finfo, sizeof (finfo));
|
||||
|
||||
if (FLUID_STRCMP (extension, finfo.extension) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < major_count)
|
||||
{
|
||||
*type = finfo.format;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -944,7 +944,7 @@ fluid_settings_getstr_default(fluid_settings_t* settings, char* name)
|
|||
* @return 1 if the setting exists and option was added, 0 otherwise
|
||||
*/
|
||||
int
|
||||
fluid_settings_add_option(fluid_settings_t* settings, char* name, char* s)
|
||||
fluid_settings_add_option(fluid_settings_t* settings, char* name, const char* s)
|
||||
{
|
||||
fluid_setting_node_t *node;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
|
@ -981,7 +981,7 @@ fluid_settings_add_option(fluid_settings_t* settings, char* name, char* s)
|
|||
* @return 1 if the setting exists and option was removed, 0 otherwise
|
||||
*/
|
||||
int
|
||||
fluid_settings_remove_option(fluid_settings_t* settings, char* name, char* s)
|
||||
fluid_settings_remove_option(fluid_settings_t* settings, char* name, const char* s)
|
||||
{
|
||||
fluid_setting_node_t *node;
|
||||
char* tokens[MAX_SETTINGS_TOKENS];
|
||||
|
|
|
@ -25,10 +25,10 @@
|
|||
|
||||
|
||||
/** returns 1 if the option was added, 0 otherwise */
|
||||
int fluid_settings_add_option(fluid_settings_t* settings, char* name, char* s);
|
||||
int fluid_settings_add_option(fluid_settings_t* settings, char* name, const char* s);
|
||||
|
||||
/** returns 1 if the option was added, 0 otherwise */
|
||||
int fluid_settings_remove_option(fluid_settings_t* settings, char* name, char* s);
|
||||
int fluid_settings_remove_option(fluid_settings_t* settings, char* name, const char* s);
|
||||
|
||||
|
||||
typedef int (*fluid_num_update_t)(void* data, char* name, double value);
|
||||
|
|
|
@ -63,6 +63,7 @@ void fluid_time_config(void);
|
|||
#define FLUID_UINT_TO_POINTER GUINT_TO_POINTER
|
||||
#define FLUID_POINTER_TO_INT GPOINTER_TO_INT
|
||||
#define FLUID_INT_TO_POINTER GINT_TO_POINTER
|
||||
#define FLUID_N_ELEMENTS(struct) (sizeof (struct) / sizeof (struct[0]))
|
||||
|
||||
|
||||
/*
|
||||
|
@ -126,6 +127,7 @@ int fluid_timer_stop(fluid_timer_t* timer);
|
|||
|
||||
/* Regular mutex */
|
||||
typedef GStaticMutex fluid_mutex_t;
|
||||
#define FLUID_MUTEX_INIT G_STATIC_MUTEX_INIT
|
||||
#define fluid_mutex_init(_m) g_static_mutex_init(&(_m))
|
||||
#define fluid_mutex_destroy(_m) g_static_mutex_free(&(_m))
|
||||
#define fluid_mutex_lock(_m) g_static_mutex_lock(&(_m))
|
||||
|
|
|
@ -176,24 +176,31 @@ settings_foreach_func (void *data, char *name, int type)
|
|||
}
|
||||
}
|
||||
|
||||
void fast_render_loop(fluid_settings_t* settings, fluid_synth_t* synth, fluid_player_t* player)
|
||||
static void
|
||||
fast_render_loop(fluid_settings_t* settings, fluid_synth_t* synth, fluid_player_t* player)
|
||||
{
|
||||
fluid_file_renderer_t* renderer;
|
||||
char* filename = NULL;
|
||||
char* filename = NULL, *type = NULL, *format = NULL, *endian = NULL;
|
||||
int period_size = 0;
|
||||
|
||||
fluid_settings_getint(settings, "audio.period-size", &period_size);
|
||||
fluid_settings_dupstr(settings, "audio.file.name", &filename); /* ++ alloc file name */
|
||||
fluid_settings_dupstr (settings, "audio.file.type", &type); /* ++ alloc file type */
|
||||
fluid_settings_dupstr (settings, "audio.file.format", &format); /* ++ alloc file format */
|
||||
fluid_settings_dupstr (settings, "audio.file.endian", &endian); /* ++ alloc file endian */
|
||||
|
||||
if (filename == NULL || period_size <= 0) {
|
||||
if (filename == NULL || type == NULL || format == NULL || endian == NULL || period_size <= 0) {
|
||||
fprintf(stderr, "Failed to fetch parameters for file renderer\n");
|
||||
if (filename) FLUID_FREE (filename); /* -- free file name */
|
||||
return;
|
||||
}
|
||||
|
||||
renderer = new_fluid_file_renderer(synth, filename, period_size);
|
||||
renderer = new_fluid_file_renderer (synth, filename, type, format, endian, period_size);
|
||||
|
||||
FLUID_FREE (filename); /* -- free file name */
|
||||
FLUID_FREE (type); /* -- free file type */
|
||||
FLUID_FREE (format); /* -- free format */
|
||||
FLUID_FREE (endian); /* -- free endian */
|
||||
|
||||
if (!renderer) {
|
||||
return;
|
||||
|
@ -235,9 +242,6 @@ int main(int argc, char** argv)
|
|||
fluid_audio_driver_t* adriver = NULL;
|
||||
fluid_synth_t* synth = NULL;
|
||||
fluid_server_t* server = NULL;
|
||||
char* midi_id = NULL;
|
||||
char* midi_driver = NULL;
|
||||
char* midi_device = NULL;
|
||||
char* config_file = NULL;
|
||||
int audio_groups = 0;
|
||||
int audio_channels = 0;
|
||||
|
@ -245,7 +249,7 @@ int main(int argc, char** argv)
|
|||
int dump = 0;
|
||||
int fast_render = 0;
|
||||
int connect_lash = 1;
|
||||
char *optchars = "a:C:c:df:F:G:g:hijK:L:lm:no:p:R:r:sVvz:";
|
||||
char *optchars = "a:C:c:dE:f:F:G:g:hijK:L:lm:nO:o:p:R:r:sT:Vvz:";
|
||||
#ifdef LASH_ENABLED
|
||||
int enabled_lash = 0; /* set to TRUE if lash gets enabled */
|
||||
fluid_lash_args_t *lash_args;
|
||||
|
@ -266,6 +270,9 @@ int main(int argc, char** argv)
|
|||
{"audio-bufsize", 1, 0, 'z'},
|
||||
{"audio-channels", 1, 0, 'L'},
|
||||
{"audio-driver", 1, 0, 'a'},
|
||||
{"audio-file-endian", 1, 0, 'E'},
|
||||
{"audio-file-format", 1, 0, 'O'},
|
||||
{"audio-file-type", 1, 0, 'T'},
|
||||
{"audio-groups", 1, 0, 'G'},
|
||||
{"chorus", 1, 0, 'C'},
|
||||
{"connect-jack-outputs", 0, 0, 'j'},
|
||||
|
@ -352,6 +359,24 @@ int main(int argc, char** argv)
|
|||
fluid_settings_setstr(settings, "synth.dump", "yes");
|
||||
dump = 1;
|
||||
break;
|
||||
case 'E':
|
||||
if (FLUID_STRCMP (optarg, "help") == 0)
|
||||
{
|
||||
const char **names = fluid_file_renderer_get_endian_names ();
|
||||
const char **sp;
|
||||
|
||||
print_welcome ();
|
||||
printf ("-E options (audio file byte order):\n ");
|
||||
|
||||
for (sp = names; *sp; sp++)
|
||||
printf (" %s", *sp);
|
||||
|
||||
printf ("\n\nauto: Use audio file format's default endian byte order\n"
|
||||
"cpu: Use CPU native byte order\n");
|
||||
exit (0);
|
||||
}
|
||||
else fluid_settings_setstr(settings, "audio.file.endian", optarg);
|
||||
break;
|
||||
case 'f':
|
||||
config_file = optarg;
|
||||
break;
|
||||
|
@ -390,6 +415,23 @@ int main(int argc, char** argv)
|
|||
case 'n':
|
||||
midi_in = 0;
|
||||
break;
|
||||
case 'O':
|
||||
if (FLUID_STRCMP (optarg, "help") == 0)
|
||||
{
|
||||
const char **names = fluid_file_renderer_get_format_names ();
|
||||
const char **sp;
|
||||
|
||||
print_welcome ();
|
||||
printf ("-O options (file audio format):\n ");
|
||||
|
||||
for (sp = names; *sp; sp++)
|
||||
printf (" %s", *sp);
|
||||
|
||||
printf ("\n");
|
||||
exit (0);
|
||||
}
|
||||
else fluid_settings_setstr(settings, "audio.file.format", optarg);
|
||||
break;
|
||||
case 'o':
|
||||
process_o_cmd_line_option(settings, optarg);
|
||||
break;
|
||||
|
@ -409,6 +451,25 @@ int main(int argc, char** argv)
|
|||
case 's':
|
||||
with_server = 1;
|
||||
break;
|
||||
case 'T':
|
||||
if (FLUID_STRCMP (optarg, "help") == 0)
|
||||
{
|
||||
const char **names = fluid_file_renderer_get_type_names ();
|
||||
const char **sp;
|
||||
|
||||
if (!names) exit (1); /* Can happen if out of memory */
|
||||
|
||||
print_welcome ();
|
||||
printf ("-T options (audio file type):\n ");
|
||||
|
||||
for (sp = names; *sp; sp++)
|
||||
printf (" %s", *sp);
|
||||
|
||||
printf ("\n\nauto: Determine type from file name extension, defaults to \"wav\"\n");
|
||||
exit (0);
|
||||
}
|
||||
else fluid_settings_setstr(settings, "audio.file.type", optarg);
|
||||
break;
|
||||
case 'V':
|
||||
printf("FluidSynth %s\n", VERSION);
|
||||
exit (0);
|
||||
|
@ -725,20 +786,22 @@ print_help()
|
|||
printf(" -a, --audio-driver=[label]\n"
|
||||
" The name of the audio driver to use.\n"
|
||||
" Valid values: %s\n", allnames);
|
||||
printf(" -C, --chorus\n"
|
||||
" Turn the chorus on or off [0|1|yes|no, default = on]\n");
|
||||
printf(" -c, --audio-bufcount=[count]\n"
|
||||
" Number of audio buffers\n");
|
||||
printf(" -C, --chorus\n"
|
||||
" Turn the chorus on or off [0|1|yes|no, default = on]\n");
|
||||
printf(" -d, --dump\n"
|
||||
" Dump incoming and outgoing MIDI events to stdout\n");
|
||||
printf(" -F, --fast-render=[file]\n"
|
||||
" Render MIDI file to raw audio data and store in [file]\n");
|
||||
printf(" -E, --audio-file-endian\n"
|
||||
" Audio file endian for fast rendering or aufile driver (\"help\" for list)\n");
|
||||
printf(" -f, --load-config\n"
|
||||
" Load command configuration file (shell commands)\n");
|
||||
printf(" -G, --audio-groups\n"
|
||||
" Defines the number of LADSPA audio nodes\n");
|
||||
printf(" -F, --fast-render=[file]\n"
|
||||
" Render MIDI file to raw audio data and store in [file]\n");
|
||||
printf(" -g, --gain\n"
|
||||
" Set the master gain [0 < gain < 10, default = 0.2]\n");
|
||||
printf(" -G, --audio-groups\n"
|
||||
" Defines the number of LADSPA audio nodes\n");
|
||||
printf(" -h, --help\n"
|
||||
" Print out this help summary\n");
|
||||
printf(" -i, --no-shell\n"
|
||||
|
@ -747,32 +810,36 @@ print_help()
|
|||
" Attempt to connect the jack outputs to the physical ports\n");
|
||||
printf(" -K, --midi-channels=[num]\n"
|
||||
" The number of midi channels [default = 16]\n");
|
||||
printf(" -L, --audio-channels=[num]\n"
|
||||
" The number of stereo audio channels [default = 1]\n");
|
||||
#ifdef LASH_ENABLED
|
||||
printf(" -l, --disable-lash\n"
|
||||
" Don't connect to LASH server\n");
|
||||
#endif
|
||||
printf(" -L, --audio-channels=[num]\n"
|
||||
" The number of stereo audio channels [default = 1]\n");
|
||||
fluid_midi_driver_get_names(allnames, sizeof(allnames), ", ");
|
||||
printf(" -m, --midi-driver=[label]\n"
|
||||
" The name of the midi driver to use.\n"
|
||||
" Valid values: %s\n", allnames);
|
||||
printf(" -n, --no-midi-in\n"
|
||||
" Don't create a midi driver to read MIDI input events [default = yes]\n");
|
||||
printf(" -p, --portname=[label]\n"
|
||||
" Set MIDI port name (alsa_seq, coremidi drivers)\n");
|
||||
printf(" -o\n"
|
||||
" Define a setting, -o name=value (\"-o help\" to dump current values)\n");
|
||||
printf(" -R, --reverb\n"
|
||||
" Turn the reverb on or off [0|1|yes|no, default = on]\n");
|
||||
printf(" -O, --audio-file-format\n"
|
||||
" Audio file format for fast rendering or aufile driver (\"help\" for list)\n");
|
||||
printf(" -p, --portname=[label]\n"
|
||||
" Set MIDI port name (alsa_seq, coremidi drivers)\n");
|
||||
printf(" -r, --sample-rate\n"
|
||||
" Set the sample rate\n");
|
||||
printf(" -R, --reverb\n"
|
||||
" Turn the reverb on or off [0|1|yes|no, default = on]\n");
|
||||
printf(" -s, --server\n"
|
||||
" Start FluidSynth as a server process\n");
|
||||
printf(" -V, --version\n"
|
||||
" Show version of program\n");
|
||||
printf(" -T, --audio-file-type\n"
|
||||
" Audio file type for fast rendering or aufile driver (\"help\" for list)\n");
|
||||
printf(" -v, --verbose\n"
|
||||
" Print out verbose messages about midi events\n");
|
||||
printf(" -V, --version\n"
|
||||
" Show version of program\n");
|
||||
printf(" -z, --audio-bufsize=[size]\n"
|
||||
" Size of each audio buffer\n");
|
||||
exit(0);
|
||||
|
|
|
@ -232,6 +232,7 @@ typedef FILE* fluid_file;
|
|||
#define FLUID_STRCPY(_dst,_src) strcpy(_dst,_src)
|
||||
#define FLUID_STRNCPY(_dst,_src,_n) strncpy(_dst,_src,_n)
|
||||
#define FLUID_STRCHR(_s,_c) strchr(_s,_c)
|
||||
#define FLUID_STRRCHR(_s,_c) strrchr(_s,_c)
|
||||
#ifdef strdup
|
||||
#define FLUID_STRDUP(s) strdup(s)
|
||||
#else
|
||||
|
|
Loading…
Reference in a new issue