Merge branch 'master' into cmake-modernization

This commit is contained in:
derselbst 2021-12-20 15:56:02 +01:00
commit d47f53518e
13 changed files with 417 additions and 26 deletions

View file

@ -184,19 +184,19 @@ jobs:
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main' sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main'
displayName: 'Use recent CMake Version' displayName: 'Use recent CMake Version'
condition: ne(variables.CACHE_RESTORED, 'true') condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
enabled: 'false' enabled: 'false'
- script: | - script: |
sudo apt-get update -y sudo apt-get update -y
displayName: 'Update apt' displayName: 'Update apt'
condition: ne(variables.CACHE_RESTORED, 'true') condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- script: | - script: |
set -ex set -ex
sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gettext cmake zlib1g-dev autogen automake autoconf libtool pkg-config autotools-dev build-essential meson ninja-build sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gettext cmake zlib1g-dev autogen automake autoconf libtool pkg-config autotools-dev build-essential meson ninja-build
displayName: 'apt-get install' displayName: 'apt-get install'
condition: ne(variables.CACHE_RESTORED, 'true') condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- script: | - script: |
set -e set -e
@ -260,7 +260,7 @@ jobs:
displayName: 'Compile libiconv' displayName: 'Compile libiconv'
workingDirectory: $(DEV) workingDirectory: $(DEV)
condition: ne(variables.CACHE_RESTORED, 'true') condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- script: | - script: |
set -ex set -ex
@ -276,7 +276,7 @@ jobs:
popd popd
displayName: 'Compile libffi' displayName: 'Compile libffi'
workingDirectory: $(DEV) workingDirectory: $(DEV)
condition: ne(variables.CACHE_RESTORED, 'true') condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- script: | - script: |
set -ex set -ex
@ -400,7 +400,7 @@ jobs:
popd popd
displayName: 'Compile gettext' displayName: 'Compile gettext'
workingDirectory: $(DEV) workingDirectory: $(DEV)
condition: ne(variables.CACHE_RESTORED, 'true') condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- script: | - script: |
set -ex set -ex
@ -463,7 +463,7 @@ jobs:
popd popd
displayName: 'Compile glib' displayName: 'Compile glib'
workingDirectory: $(DEV) workingDirectory: $(DEV)
condition: ne(variables.CACHE_RESTORED, 'true') condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- template: cmake-android.yml - template: cmake-android.yml
parameters: parameters:
@ -559,7 +559,7 @@ jobs:
displayName: 'Create fake oboe.pc' displayName: 'Create fake oboe.pc'
workingDirectory: $(DEV) workingDirectory: $(DEV)
condition: ne(variables.CACHE_RESTORED, 'true') condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- template: cmake-android.yml - template: cmake-android.yml
parameters: parameters:

View file

@ -20,9 +20,6 @@ jobs:
UnixLibs: UnixLibs:
imageName: 'macos-11' imageName: 'macos-11'
CMakeFlags: '-Denable-framework=0' CMakeFlags: '-Denable-framework=0'
10_14:
imageName: 'macOS-10.14'
CMakeFlags: ''
10_15: 10_15:
imageName: 'macOS-10.15' imageName: 'macOS-10.15'
CMakeFlags: '' CMakeFlags: ''

View file

@ -69,17 +69,17 @@ jobs:
# ninja --version # ninja --version
cmake --version cmake --version
rm -rf C:/Strawberry/perl/bin/pkg-config* rm -rf C:/Strawberry/perl/bin/pkg-config*
choco install --svc --sdc -i pkgconfiglite & choco install --svc --sdc -i pkgconfiglite
chocoTask=$! # chocoTask=$!
# manually update vcpkg # manually update vcpkg
cd $VCPKG_INSTALLATION_ROOT cd $VCPKG_INSTALLATION_ROOT
# git checkout master # git checkout master
git remote -v git remote -v
git fetch --unshallow --tags --prune --progress origin git fetch --tags --prune --progress origin
git checkout --force $(VCPKG_REVISION) git checkout --force $(VCPKG_REVISION)
sed -i 's/arm64/arm/g' ports/glib/portfile.cmake sed -i 's/arm64/arm/g' ports/glib/portfile.cmake
./bootstrap-vcpkg.sh ./bootstrap-vcpkg.sh
wait $chocoTask # wait $chocoTask
which pkg-config which pkg-config
displayName: 'Update vcpkg' displayName: 'Update vcpkg'
- task: DownloadBuildArtifacts@0 - task: DownloadBuildArtifacts@0

View file

@ -41,7 +41,7 @@ set ( PACKAGE "fluidsynth" )
# FluidSynth package version # FluidSynth package version
set ( FLUIDSYNTH_VERSION_MAJOR 2 ) set ( FLUIDSYNTH_VERSION_MAJOR 2 )
set ( FLUIDSYNTH_VERSION_MINOR 2 ) set ( FLUIDSYNTH_VERSION_MINOR 2 )
set ( FLUIDSYNTH_VERSION_MICRO 3 ) set ( FLUIDSYNTH_VERSION_MICRO 4 )
set ( VERSION "${FLUIDSYNTH_VERSION_MAJOR}.${FLUIDSYNTH_VERSION_MINOR}.${FLUIDSYNTH_VERSION_MICRO}" ) set ( VERSION "${FLUIDSYNTH_VERSION_MAJOR}.${FLUIDSYNTH_VERSION_MINOR}.${FLUIDSYNTH_VERSION_MICRO}" )
set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" ) set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" )
@ -56,7 +56,7 @@ set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" )
# This is not exactly the same algorithm as the libtool one, but the results are the same. # This is not exactly the same algorithm as the libtool one, but the results are the same.
set ( LIB_VERSION_CURRENT 3 ) set ( LIB_VERSION_CURRENT 3 )
set ( LIB_VERSION_AGE 0 ) set ( LIB_VERSION_AGE 0 )
set ( LIB_VERSION_REVISION 3 ) set ( LIB_VERSION_REVISION 4 )
set ( LIB_VERSION_INFO set ( LIB_VERSION_INFO
"${LIB_VERSION_CURRENT}.${LIB_VERSION_AGE}.${LIB_VERSION_REVISION}" ) "${LIB_VERSION_CURRENT}.${LIB_VERSION_AGE}.${LIB_VERSION_REVISION}" )
@ -89,6 +89,7 @@ option ( enable-waveout "compile Windows WaveOut support (if it is available)" o
option ( enable-winmidi "compile Windows MIDI support (if it is available)" on ) option ( enable-winmidi "compile Windows MIDI support (if it is available)" on )
option ( enable-sdl2 "compile SDL2 audio support (if it is available)" on ) option ( enable-sdl2 "compile SDL2 audio support (if it is available)" on )
option ( enable-pulseaudio "compile PulseAudio support (if it is available)" on ) option ( enable-pulseaudio "compile PulseAudio support (if it is available)" on )
option ( enable-pipewire "compile PipeWire support (if it is available)" on )
option ( enable-readline "compile readline lib line editing (if it is available)" on ) option ( enable-readline "compile readline lib line editing (if it is available)" on )
option ( enable-threads "enable multi-threading support (such as parallel voice synthesis)" on ) option ( enable-threads "enable multi-threading support (such as parallel voice synthesis)" on )
option ( enable-openmp "enable OpenMP support (parallelization of soundfont decoding, vectorization of voice mixing, etc.)" on ) option ( enable-openmp "enable OpenMP support (parallelization of soundfont decoding, vectorization of voice mixing, etc.)" on )
@ -563,6 +564,14 @@ else ( enable-jack )
unset_pkg_config ( JACK ) unset_pkg_config ( JACK )
endif ( enable-jack ) endif ( enable-jack )
unset ( PIPEWIRE_SUPPORT CACHE )
if ( enable-pipewire )
pkg_check_modules ( PIPEWIRE libpipewire-0.3 )
set ( PIPEWIRE_SUPPORT ${PIPEWIRE_FOUND} )
else ( enable-pipewire )
unset_pkg_config ( PIPEWIRE )
endif ( enable-pipewire )
unset ( LASH_SUPPORT CACHE ) unset ( LASH_SUPPORT CACHE )
if ( enable-lash ) if ( enable-lash )
pkg_check_modules ( LASH lash-1.0>=0.3 IMPORTED_TARGET ) pkg_check_modules ( LASH lash-1.0>=0.3 IMPORTED_TARGET )
@ -824,8 +833,6 @@ endif ()
generate_pkgconfig_spec(fluidsynth.pc.in ${CMAKE_BINARY_DIR}/fluidsynth.pc libfluidsynth-OBJ) generate_pkgconfig_spec(fluidsynth.pc.in ${CMAKE_BINARY_DIR}/fluidsynth.pc libfluidsynth-OBJ)
list ( JOIN PC_REQUIRES_PRIV " " PC_REQUIRES_PRIV_JOINED )
configure_file ( fluidsynth.pc.in configure_file ( fluidsynth.pc.in
${CMAKE_BINARY_DIR}/fluidsynth.pc IMMEDIATE @ONLY ) ${CMAKE_BINARY_DIR}/fluidsynth.pc IMMEDIATE @ONLY )
install ( FILES ${CMAKE_BINARY_DIR}/fluidsynth.pc install ( FILES ${CMAKE_BINARY_DIR}/fluidsynth.pc

View file

@ -31,6 +31,12 @@ else ( JACK_SUPPORT )
set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} JACK: no\n" ) set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} JACK: no\n" )
endif ( JACK_SUPPORT ) endif ( JACK_SUPPORT )
if ( PIPEWIRE_SUPPORT )
set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} PipeWire: yes\n" )
else ( PIPEWIRE_SUPPORT )
set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} PipeWire: no\n" )
endif ( PIPEWIRE_SUPPORT )
if ( MIDISHARE_SUPPORT ) if ( MIDISHARE_SUPPORT )
set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} MidiShare: yes\n" ) set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} MidiShare: yes\n" )
else ( MIDISHARE_SUPPORT ) else ( MIDISHARE_SUPPORT )

View file

@ -14,11 +14,6 @@ https://stackoverflow.com/a/6251757
Developers: Developers:
- Settings can be deprecated by adding: <deprecated>SOME TEXT</deprecated> - Settings can be deprecated by adding: <deprecated>SOME TEXT</deprecated>
- Real-time settings can be marked with <realtime>SOME OPTIONAL TEXT</realtime>. - Real-time settings can be marked with <realtime>SOME OPTIONAL TEXT</realtime>.
ATTENTION: if you change anything in this file, make sure you also refresh
the doxygen/fluidsettings.txt file (used by fluidsynth.org API doc build)
and commit the results. Refresh with the following command:
xsltproc -o doxygen/fluidsettings.txt doxygen/fluidsettings.xsl fluidsettings.xml
--> -->
<?xml-stylesheet type="text/xsl" href="fluidsettings.xsl"?> <?xml-stylesheet type="text/xsl" href="fluidsettings.xsl"?>
<fluidsettings> <fluidsettings>
@ -607,6 +602,30 @@ and commit the results. Refresh with the following command:
Device to use for OSS audio output. Device to use for OSS audio output.
</desc> </desc>
</setting> </setting>
<setting>
<name>pipewire.media-category</name>
<type>str</type>
<def>Playback</def>
<desc>
The media category to use. This value will be passed to <code>PW_KEY_MEDIA_CATEGORY</code>, see Pipewire documentation for valid values.
</desc>
</setting>
<setting>
<name>pipewire.media-role</name>
<type>str</type>
<def>Music</def>
<desc>
The media role to use. This value will be passed to <code>PW_KEY_MEDIA_ROLE</code>, see Pipewire documentation for valid values.
</desc>
</setting>
<setting>
<name>pipewire.media-type</name>
<type>str</type>
<def>Audio</def>
<desc>
The media type to use. This value will be passed to <code>PW_KEY_MEDIA_TYPE</code>, see Pipewire documentation for valid values.
</desc>
</setting>
<setting> <setting>
<name>portaudio.device</name> <name>portaudio.device</name>
<type>str</type> <type>str</type>

View file

@ -8,8 +8,8 @@
\author David Henningsson \author David Henningsson
\author Tom Moebert \author Tom Moebert
\author Copyright &copy; 2003-2021 Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green, David Henningsson, Tom Moebert \author Copyright &copy; 2003-2021 Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green, David Henningsson, Tom Moebert
\version Revision 2.2.3 \version Revision 2.2.4
\date 2021-09-11 \date 2021-11-21
All the source code examples in this document are in the public domain; you can use them as you please. This document is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License. To view a copy of this license, visit https://creativecommons.org/licenses/by-sa/3.0/ . The FluidSynth library is distributed under the GNU Lesser General Public License. A copy of the GNU Lesser General Public License is contained in the FluidSynth package; if not, visit https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. All the source code examples in this document are in the public domain; you can use them as you please. This document is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License. To view a copy of this license, visit https://creativecommons.org/licenses/by-sa/3.0/ . The FluidSynth library is distributed under the GNU Lesser General Public License. A copy of the GNU Lesser General Public License is contained in the FluidSynth package; if not, visit https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

View file

@ -45,6 +45,11 @@ if ( JACK_SUPPORT )
set ( fluid_jack_SOURCES drivers/fluid_jack.c ) set ( fluid_jack_SOURCES drivers/fluid_jack.c )
endif ( JACK_SUPPORT ) endif ( JACK_SUPPORT )
if ( PIPEWIRE_SUPPORT )
set ( fluid_pipewire_SOURCES drivers/fluid_pipewire.c )
include_directories ( SYSTEM ${PIPEWIRE_INCLUDE_DIRS} )
endif ( PIPEWIRE_SUPPORT )
if ( PORTAUDIO_SUPPORT ) if ( PORTAUDIO_SUPPORT )
set ( fluid_portaudio_SOURCES drivers/fluid_portaudio.c ) set ( fluid_portaudio_SOURCES drivers/fluid_portaudio.c )
endif ( PORTAUDIO_SUPPORT ) endif ( PORTAUDIO_SUPPORT )
@ -232,6 +237,7 @@ add_library ( libfluidsynth-OBJ OBJECT
${fluid_dart_SOURCES} ${fluid_dart_SOURCES}
${fluid_dbus_SOURCES} ${fluid_dbus_SOURCES}
${fluid_jack_SOURCES} ${fluid_jack_SOURCES}
${fluid_pipewire_SOURCES}
${fluid_lash_SOURCES} ${fluid_lash_SOURCES}
${fluid_midishare_SOURCES} ${fluid_midishare_SOURCES}
${fluid_opensles_SOURCES} ${fluid_opensles_SOURCES}
@ -322,6 +328,7 @@ endif ( MACOSX_FRAMEWORK )
# Object Libraries may "link" to other libraries to get usage requirements, # Object Libraries may "link" to other libraries to get usage requirements,
# but since they do not have a link step nothing is done with their object files. # but since they do not have a link step nothing is done with their object files.
target_link_libraries ( libfluidsynth-OBJ PUBLIC target_link_libraries ( libfluidsynth-OBJ PUBLIC
${PIPEWIRE_LIBRARIES}
${DART_LIBS} ${DART_LIBS}
${COREAUDIO_LIBS} ${COREAUDIO_LIBS}
${COREMIDI_LIBS} ${COREMIDI_LIBS}

View file

@ -130,6 +130,9 @@
/* Define to enable JACK driver */ /* Define to enable JACK driver */
#cmakedefine JACK_SUPPORT @JACK_SUPPORT@ #cmakedefine JACK_SUPPORT @JACK_SUPPORT@
/* Define to enable PipeWire driver */
#cmakedefine PIPEWIRE_SUPPORT @PIPEWIRE_SUPPORT@
/* Include the LADSPA Fx unit */ /* Include the LADSPA Fx unit */
#cmakedefine LADSPA @LADSPA_SUPPORT@ #cmakedefine LADSPA @LADSPA_SUPPORT@

View file

@ -70,6 +70,16 @@ static const fluid_audriver_definition_t fluid_audio_drivers[] =
}, },
#endif #endif
#if PIPEWIRE_SUPPORT
{
"pipewire",
new_fluid_pipewire_audio_driver,
new_fluid_pipewire_audio_driver2,
delete_fluid_pipewire_audio_driver,
fluid_pipewire_audio_driver_settings
},
#endif
#if OSS_SUPPORT #if OSS_SUPPORT
{ {
"oss", "oss",

View file

@ -138,6 +138,14 @@ void fluid_jack_audio_driver_settings(fluid_settings_t *settings);
int fluid_jack_obtain_synth(fluid_settings_t *settings, fluid_synth_t **synth); int fluid_jack_obtain_synth(fluid_settings_t *settings, fluid_synth_t **synth);
#endif #endif
#if PIPEWIRE_SUPPORT
fluid_audio_driver_t *new_fluid_pipewire_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth);
fluid_audio_driver_t *new_fluid_pipewire_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func, void *data);
void delete_fluid_pipewire_audio_driver(fluid_audio_driver_t *p);
void fluid_pipewire_audio_driver_settings(fluid_settings_t *settings);
#endif
#if SNDMAN_SUPPORT #if SNDMAN_SUPPORT
fluid_audio_driver_t *new_fluid_sndmgr_audio_driver(fluid_settings_t *settings, fluid_audio_driver_t *new_fluid_sndmgr_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth); fluid_synth_t *synth);

View file

@ -0,0 +1,324 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
* Copyright (C) 2021 E. "sykhro" Melucci
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
/* fluid_pipewire.c
*
* Audio driver for PipeWire.
*
*/
#include "fluid_synth.h"
#include "fluid_adriver.h"
#include "fluid_settings.h"
#if PIPEWIRE_SUPPORT
#include <pipewire/pipewire.h>
#include <spa/param/audio/format-utils.h>
/* At the moment, only stereo is supported */
#define NUM_CHANNELS 2
static const int stride = sizeof(float) * NUM_CHANNELS;
typedef struct
{
fluid_audio_driver_t driver;
fluid_audio_func_t user_callback;
void *data;
/* Used only with the user-provided callback */
float *lbuf, *rbuf;
int buffer_period;
struct spa_pod_builder *builder;
struct pw_thread_loop *pw_loop;
struct pw_stream *pw_stream;
struct pw_stream_events *events;
} fluid_pipewire_audio_driver_t;
/* Fast-path rendering routine with no user processing callbacks */
static void fluid_pipewire_event_process(void *data)
{
fluid_pipewire_audio_driver_t *drv = data;
struct pw_buffer *pwb;
struct spa_buffer *buf;
float *dest;
pwb = pw_stream_dequeue_buffer(drv->pw_stream);
if(!pwb)
{
FLUID_LOG(FLUID_WARN, "No buffers!");
return;
}
buf = pwb->buffer;
dest = buf->datas[0].data;
if(!dest)
{
return;
}
fluid_synth_write_float(drv->data, drv->buffer_period, dest, 0, 2, dest, 1, 2);
buf->datas[0].chunk->offset = 0;
buf->datas[0].chunk->stride = stride;
buf->datas[0].chunk->size = drv->buffer_period * stride;
pw_stream_queue_buffer(drv->pw_stream, pwb);
}
/* Rendering routine with support for user-defined audio manipulation */
static void fluid_pipewire_event_process2(void *data)
{
fluid_pipewire_audio_driver_t *drv = data;
struct pw_buffer *pwb;
struct spa_buffer *buf;
float *dest;
float *channels[NUM_CHANNELS] = { drv->lbuf, drv->rbuf };
int i;
pwb = pw_stream_dequeue_buffer(drv->pw_stream);
if(!pwb)
{
FLUID_LOG(FLUID_WARN, "No buffers!");
return;
}
buf = pwb->buffer;
dest = buf->datas[0].data;
if(!dest)
{
return;
}
FLUID_MEMSET(drv->lbuf, 0, drv->buffer_period * sizeof(float));
FLUID_MEMSET(drv->rbuf, 0, drv->buffer_period * sizeof(float));
(*drv->user_callback)(drv->data, drv->buffer_period, 0, NULL, NUM_CHANNELS, channels);
/* Interleave the floating point data */
for(i = 0; i < drv->buffer_period; i++)
{
dest[i * 2] = drv->lbuf[i];
dest[i * 2 + 1] = drv->rbuf[i];
}
buf->datas[0].chunk->offset = 0;
buf->datas[0].chunk->stride = stride;
buf->datas[0].chunk->size = drv->buffer_period * stride;
pw_stream_queue_buffer(drv->pw_stream, pwb);
}
fluid_audio_driver_t *new_fluid_pipewire_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
{
return new_fluid_pipewire_audio_driver2(settings, NULL, synth);
}
fluid_audio_driver_t *
new_fluid_pipewire_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func, void *data)
{
fluid_pipewire_audio_driver_t *drv;
int period_size;
int buffer_length;
int res;
int pw_flags;
int realtime_prio = 0;
double sample_rate;
char *media_role = NULL;
char *media_type = NULL;
char *media_category = NULL;
float *buffer = NULL;
const struct spa_pod *params[1];
drv = FLUID_NEW(fluid_pipewire_audio_driver_t);
if(!drv)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
FLUID_MEMSET(drv, 0, sizeof(*drv));
fluid_settings_getint(settings, "audio.period-size", &period_size);
fluid_settings_getint(settings, "audio.realtime-prio", &realtime_prio);
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
fluid_settings_dupstr(settings, "audio.pipewire.media-role", &media_role);
fluid_settings_dupstr(settings, "audio.pipewire.media-type", &media_type);
fluid_settings_dupstr(settings, "audio.pipewire.media-category", &media_category);
drv->data = data;
drv->user_callback = func;
drv->buffer_period = period_size;
drv->events = FLUID_NEW(struct pw_stream_events);
if(!drv->events)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto driver_cleanup;
}
FLUID_MEMSET(drv->events, 0, sizeof(*drv->events));
drv->events->version = PW_VERSION_STREAM_EVENTS;
drv->events->process = func ? fluid_pipewire_event_process2 : fluid_pipewire_event_process;
drv->pw_loop = pw_thread_loop_new("fluid_pipewire", NULL);
if(!drv->pw_loop)
{
FLUID_LOG(FLUID_ERR, "Failed to allocate PipeWire loop");
goto driver_cleanup;
}
drv->pw_stream = pw_stream_new_simple(
pw_thread_loop_get_loop(drv->pw_loop),
"FluidSynth",
pw_properties_new(PW_KEY_MEDIA_TYPE, media_type, PW_KEY_MEDIA_CATEGORY, media_category, PW_KEY_MEDIA_ROLE, media_role, NULL),
drv->events,
drv);
if(!drv->pw_stream)
{
FLUID_LOG(FLUID_ERR, "Failed to allocate PipeWire stream");
goto driver_cleanup;
}
buffer = FLUID_ARRAY(float, NUM_CHANNELS * period_size);
if(!buffer)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto driver_cleanup;
}
buffer_length = period_size * sizeof(float) * NUM_CHANNELS;
drv->builder = FLUID_NEW(struct spa_pod_builder);
if(!drv->builder)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto driver_cleanup;
}
FLUID_MEMSET(drv->builder, 0, sizeof(*drv->builder));
drv->builder->data = buffer;
drv->builder->size = buffer_length;
if(func)
{
drv->lbuf = FLUID_ARRAY(float, period_size);
drv->rbuf = FLUID_ARRAY(float, period_size);
if(!drv->lbuf || !drv->rbuf)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto driver_cleanup;
}
}
params[0] = spa_format_audio_raw_build(drv->builder,
SPA_PARAM_EnumFormat,
&SPA_AUDIO_INFO_RAW_INIT(.format = SPA_AUDIO_FORMAT_F32,
.channels = 2,
.rate = sample_rate));
pw_flags = PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS;
pw_flags |= realtime_prio ? PW_STREAM_FLAG_RT_PROCESS : 0;
res = pw_stream_connect(drv->pw_stream, PW_DIRECTION_OUTPUT, PW_ID_ANY, pw_flags, params, 1);
if(res < 0)
{
FLUID_LOG(FLUID_ERR, "PipeWire stream connection failed");
goto driver_cleanup;
}
res = pw_thread_loop_start(drv->pw_loop);
if(res != 0)
{
FLUID_LOG(FLUID_ERR, "Failed starting PipeWire loop");
goto driver_cleanup;
}
FLUID_LOG(FLUID_INFO, "Using PipeWire audio driver");
FLUID_FREE(media_role);
FLUID_FREE(media_type);
FLUID_FREE(media_category);
return (fluid_audio_driver_t *)drv;
driver_cleanup:
FLUID_FREE(media_role);
FLUID_FREE(media_type);
FLUID_FREE(media_category);
delete_fluid_pipewire_audio_driver((fluid_audio_driver_t *)drv);
return NULL;
}
void delete_fluid_pipewire_audio_driver(fluid_audio_driver_t *p)
{
fluid_pipewire_audio_driver_t *drv = (fluid_pipewire_audio_driver_t *)p;
fluid_return_if_fail(drv);
if(drv->pw_stream)
{
pw_stream_destroy(drv->pw_stream);
}
if(drv->pw_loop)
{
pw_thread_loop_destroy(drv->pw_loop);
}
FLUID_FREE(drv->lbuf);
FLUID_FREE(drv->rbuf);
if(drv->builder)
{
FLUID_FREE(drv->builder->data);
}
FLUID_FREE(drv->builder);
FLUID_FREE(drv->events);
FLUID_FREE(drv);
}
void fluid_pipewire_audio_driver_settings(fluid_settings_t *settings)
{
fluid_settings_register_str(settings, "audio.pipewire.media-role", "Music", 0);
fluid_settings_register_str(settings, "audio.pipewire.media-type", "Audio", 0);
fluid_settings_register_str(settings, "audio.pipewire.media-category", "Playback", 0);
}
#endif

View file

@ -2200,6 +2200,9 @@ fluid_player_callback(void *data, unsigned int msec)
* Activates play mode for a MIDI player if not already playing. * Activates play mode for a MIDI player if not already playing.
* @param player MIDI player instance * @param player MIDI player instance
* @return #FLUID_OK on success, #FLUID_FAILED otherwise * @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* If the list of files added to the player has completed its requested number of loops,
* the playlist will be restarted from the beginning with a loop count of 1.
*/ */
int int
fluid_player_play(fluid_player_t *player) fluid_player_play(fluid_player_t *player)
@ -2215,10 +2218,17 @@ fluid_player_play(fluid_player_t *player)
fluid_sample_timer_reset(player->synth, player->sample_timer); fluid_sample_timer_reset(player->synth, player->sample_timer);
} }
/* If we're at the end of the playlist and there are no loops left, loop once */
if(player->currentfile == NULL && player->loop == 0)
{
player->loop = 1;
}
fluid_atomic_int_set(&player->status, FLUID_PLAYER_PLAYING); fluid_atomic_int_set(&player->status, FLUID_PLAYER_PLAYING);
return FLUID_OK; return FLUID_OK;
} }
/** /**
* Pauses the MIDI playback. * Pauses the MIDI playback.
* *