From f26258cd1f17ff29d8e0883cb42da5a116d10550 Mon Sep 17 00:00:00 2001 From: carlo-bramini Date: Sat, 25 Nov 2017 14:50:52 +0100 Subject: [PATCH 1/9] Unified BSD socket source, for WIN32 and POSIX. --- src/utils/fluid_sys.c | 285 ++++++++++++------------------------------ src/utils/fluid_sys.h | 4 + 2 files changed, 81 insertions(+), 208 deletions(-) diff --git a/src/utils/fluid_sys.c b/src/utils/fluid_sys.c index a1ed04bf..3e567451 100644 --- a/src/utils/fluid_sys.c +++ b/src/utils/fluid_sys.c @@ -32,7 +32,12 @@ /* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket. * Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */ -#define WIN32_SOCKET_FLAG 0x40000000 +#ifdef _WIN32 + #define FLUID_SOCKET_FLAG 0x40000000 +#else + #define FLUID_SOCKET_FLAG 0x00000000 + #define SOCKET_ERROR -1 +#endif /* SCHED_FIFO priority for high priority timer threads */ #define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL 10 @@ -854,14 +859,14 @@ fluid_istream_gets (fluid_istream_t in, char* buf, int len) if (n == -1) return -1; #else /* Handle read differently depending on if its a socket or file descriptor */ - if (!(in & WIN32_SOCKET_FLAG)) + if (!(in & FLUID_SOCKET_FLAG)) { n = read(in, &c, 1); if (n == -1) return -1; } else { - n = recv(in & ~WIN32_SOCKET_FLAG, &c, 1, 0); + n = recv(in & ~FLUID_SOCKET_FLAG, &c, 1, 0); if (n == SOCKET_ERROR) return -1; } #endif @@ -923,11 +928,11 @@ fluid_ostream_printf (fluid_ostream_t out, char* format, ...) int retval; /* Handle write differently depending on if its a socket or file descriptor */ - if (!(out & WIN32_SOCKET_FLAG)) + if (!(out & FLUID_SOCKET_FLAG)) return write(out, buf, strlen (buf)); /* Socket */ - retval = send (out & ~WIN32_SOCKET_FLAG, buf, strlen (buf), 0); + retval = send (out & ~FLUID_SOCKET_FLAG, buf, strlen (buf), 0); return retval != SOCKET_ERROR ? retval : -1; } @@ -939,191 +944,55 @@ int fluid_server_socket_join(fluid_server_socket_t *server_socket) return fluid_thread_join (server_socket->thread); } +int fluid_socket_init(void) +{ +#ifdef _WIN32 + WSADATA wsaData; + int res = WSAStartup(MAKEWORD(2,2), &wsaData); -#ifndef WIN32 // Not win32? + if (res != 0) { + FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", res); + return FLUID_FAILED; + } +#endif -#define SOCKET_ERROR -1 + return FLUID_OK; +} + +void fluid_socket_cleanup(void) +{ +#ifdef _WIN32 + WSACleanup(); +#endif +} + +int fluid_socket_get_error(void) +{ +#ifdef _WIN32 + return (int)WSAGetLastError(); +#else + return errno; +#endif +} fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock) { - return sock; + return sock | FLUID_SOCKET_FLAG; } fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock) { - return sock; -} - -void fluid_socket_close(fluid_socket_t sock) -{ - if (sock != INVALID_SOCKET) - close (sock); -} - -static fluid_thread_return_t -fluid_server_socket_run (void *data) -{ - fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data; - fluid_socket_t client_socket; -#ifdef IPV6_SUPPORT - struct sockaddr_in6 addr; - char straddr[INET6_ADDRSTRLEN]; -#else - struct sockaddr_in addr; - char straddr[INET_ADDRSTRLEN]; -#endif - socklen_t addrlen = sizeof (addr); - int retval; - FLUID_MEMSET((char *)&addr, 0, sizeof(addr)); - - FLUID_LOG (FLUID_DBG, "Server listening for connections"); - - while (server_socket->cont) - { - client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen); - - FLUID_LOG (FLUID_DBG, "New client connection"); - - if (client_socket == INVALID_SOCKET) - { - if (server_socket->cont) - FLUID_LOG(FLUID_ERR, "Failed to accept connection"); - - server_socket->cont = 0; - return FLUID_THREAD_RETURN_VALUE; - } else { -#ifdef HAVE_INETNTOP -#ifdef IPV6_SUPPORT - inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr)); -#else - inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr)); -#endif -#endif -#ifdef HAVE_INETNTOP - retval = server_socket->func (server_socket->data, client_socket, - straddr); -#else - retval = server_socket->func (server_socket->data, client_socket, - inet_ntoa (addr.sin_addr)); -#endif - - if (retval != 0) - fluid_socket_close(client_socket); - } - } - - FLUID_LOG(FLUID_DBG, "Server closing"); - - return FLUID_THREAD_RETURN_VALUE; -} - -fluid_server_socket_t* -new_fluid_server_socket(int port, fluid_server_func_t func, void* data) -{ - fluid_server_socket_t* server_socket; -#ifdef IPV6_SUPPORT - struct sockaddr_in6 addr; -#else - struct sockaddr_in addr; -#endif - fluid_socket_t sock; - - g_return_val_if_fail (func != NULL, NULL); -#ifdef IPV6_SUPPORT - sock = socket(AF_INET6, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) { - FLUID_LOG(FLUID_ERR, "Failed to create server socket"); - return NULL; - } - - FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in6)); - addr.sin6_family = AF_INET6; - addr.sin6_addr = in6addr_any; - addr.sin6_port = htons(port); -#else - - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) { - FLUID_LOG(FLUID_ERR, "Failed to create server socket"); - return NULL; - } - - FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(port); -#endif - if (bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) { - FLUID_LOG(FLUID_ERR, "Failed to bind server socket"); - fluid_socket_close(sock); - return NULL; - } - - if (listen(sock, 10) == SOCKET_ERROR) { - FLUID_LOG(FLUID_ERR, "Failed listen on server socket"); - fluid_socket_close(sock); - return NULL; - } - - server_socket = FLUID_NEW(fluid_server_socket_t); - if (server_socket == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - fluid_socket_close(sock); - return NULL; - } - - server_socket->socket = sock; - server_socket->func = func; - server_socket->data = data; - server_socket->cont = 1; - - server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket, - 0, FALSE); - if (server_socket->thread == NULL) { - FLUID_FREE(server_socket); - fluid_socket_close(sock); - return NULL; - } - - return server_socket; -} - -void delete_fluid_server_socket(fluid_server_socket_t* server_socket) -{ - fluid_return_if_fail(server_socket != NULL); - - server_socket->cont = 0; - if (server_socket->socket != INVALID_SOCKET) { - fluid_socket_close(server_socket->socket); - } - if (server_socket->thread) { - delete_fluid_thread(server_socket->thread); - } - FLUID_FREE(server_socket); -} - - -#else // Win32 is "special" - - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock) -{ - return sock | WIN32_SOCKET_FLAG; -} - -fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock) -{ - return sock | WIN32_SOCKET_FLAG; + return sock | FLUID_SOCKET_FLAG; } void fluid_socket_close (fluid_socket_t sock) { if (sock != INVALID_SOCKET) - closesocket (sock); +#ifdef _WIN32 + closesocket(sock); +#else + close(sock); +#endif } static fluid_thread_return_t fluid_server_socket_run (void *data) @@ -1132,13 +1001,18 @@ static fluid_thread_return_t fluid_server_socket_run (void *data) fluid_socket_t client_socket; #ifdef IPV6_SUPPORT struct sockaddr_in6 addr; - char straddr[INET6_ADDRSTRLEN]; #else struct sockaddr_in addr; +#endif + #ifdef HAVE_INETNTOP +#ifdef IPV6_SUPPORT + char straddr[INET6_ADDRSTRLEN]; +#else char straddr[INET_ADDRSTRLEN]; -#endif -#endif +#endif /* HAVE_INETNTOP */ +#endif /* IPV6_SUPPORT */ + socklen_t addrlen = sizeof (addr); int r; FLUID_MEMSET((char *)&addr, 0, sizeof(addr)); @@ -1154,7 +1028,7 @@ static fluid_thread_return_t fluid_server_socket_run (void *data) if (client_socket == INVALID_SOCKET) { if (server_socket->cont) - FLUID_LOG (FLUID_ERR, "Failed to accept connection: %ld", WSAGetLastError ()); + FLUID_LOG (FLUID_ERR, "Failed to accept connection: %ld", fluid_socket_get_error()); server_socket->cont = 0; return FLUID_THREAD_RETURN_VALUE; @@ -1162,13 +1036,13 @@ static fluid_thread_return_t fluid_server_socket_run (void *data) else { #ifdef HAVE_INETNTOP + #ifdef IPV6_SUPPORT inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr)); #else inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr)); #endif -#endif -#ifdef HAVE_INETNTOP + r = server_socket->func (server_socket->data, client_socket, straddr); #else @@ -1182,7 +1056,7 @@ static fluid_thread_return_t fluid_server_socket_run (void *data) FLUID_LOG (FLUID_DBG, "Server closing"); - return FLUID_THREAD_RETURN_VALUE; + return FLUID_THREAD_RETURN_VALUE; } fluid_server_socket_t* @@ -1196,29 +1070,25 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data) #endif fluid_socket_t sock; - WSADATA wsaData; - int retval; - g_return_val_if_fail (func != NULL, NULL); + fluid_return_val_if_fail (func != NULL, NULL); - // Win32 requires initialization of winsock - retval = WSAStartup (MAKEWORD (2,2), &wsaData); - - if (retval != 0) + if (fluid_socket_init() != FLUID_OK) { - FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", retval); return NULL; } #ifdef IPV6_SUPPORT sock = socket (AF_INET6, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { - FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ()); - WSACleanup (); + FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error()); + fluid_socket_cleanup(); return NULL; } + + FLUID_MEMSET(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; - addr.sin6_port = htons (port); + addr.sin6_port = htons ((uint16_t)port); addr.sin6_addr = in6addr_any; #else @@ -1226,30 +1096,30 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data) if (sock == INVALID_SOCKET) { - FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ()); - WSACleanup (); + FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error()); + fluid_socket_cleanup(); return NULL; } + FLUID_MEMSET(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - addr.sin_port = htons (port); + addr.sin_port = htons ((uint16_t)port); addr.sin_addr.s_addr = htonl (INADDR_ANY); #endif - retval = bind (sock, (struct sockaddr *)&addr, sizeof (addr)); - if (retval == SOCKET_ERROR) + if (bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) { - FLUID_LOG (FLUID_ERR, "Failed to bind server socket: %ld", WSAGetLastError ()); + FLUID_LOG (FLUID_ERR, "Failed to bind server socket: %ld", fluid_socket_get_error()); fluid_socket_close (sock); - WSACleanup (); + fluid_socket_cleanup(); return NULL; } if (listen (sock, SOMAXCONN) == SOCKET_ERROR) { - FLUID_LOG (FLUID_ERR, "Failed to listen on server socket: %ld", WSAGetLastError ()); + FLUID_LOG (FLUID_ERR, "Failed to listen on server socket: %ld", fluid_socket_get_error()); fluid_socket_close (sock); - WSACleanup (); + fluid_socket_cleanup(); return NULL; } @@ -1259,7 +1129,7 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data) { FLUID_LOG (FLUID_ERR, "Out of memory"); fluid_socket_close (sock); - WSACleanup (); + fluid_socket_cleanup(); return NULL; } @@ -1274,7 +1144,7 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data) { FLUID_FREE (server_socket); fluid_socket_close (sock); - WSACleanup (); + fluid_socket_cleanup(); return NULL; } @@ -1295,7 +1165,6 @@ void delete_fluid_server_socket(fluid_server_socket_t *server_socket) FLUID_FREE (server_socket); - WSACleanup (); // Should be called the same number of times as WSAStartup + // Should be called the same number of times as fluid_socket_init() + fluid_socket_cleanup(); } - -#endif diff --git a/src/utils/fluid_sys.h b/src/utils/fluid_sys.h index 7407ce29..c08ff281 100644 --- a/src/utils/fluid_sys.h +++ b/src/utils/fluid_sys.h @@ -355,6 +355,10 @@ void fluid_socket_close(fluid_socket_t sock); fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock); fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock); +int fluid_socket_init(void); +void fluid_socket_cleanup(void); +int fluid_socket_get_error(void); + /* Profiling */ From 763b1f39a5df44ca20e8fc5501d0dcdf4ffca442 Mon Sep 17 00:00:00 2001 From: carlo-bramini Date: Sat, 25 Nov 2017 14:54:28 +0100 Subject: [PATCH 2/9] Minor fix, no need to include glib.h, fluidsynth_priv.h includes it already. --- src/utils/fluid_sys.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/fluid_sys.h b/src/utils/fluid_sys.h index c08ff281..080810c5 100644 --- a/src/utils/fluid_sys.h +++ b/src/utils/fluid_sys.h @@ -36,7 +36,6 @@ #ifndef _FLUID_SYS_H #define _FLUID_SYS_H -#include #include "fluidsynth_priv.h" #ifdef LADSPA From 4ccf7217b06b519b94594f65ee0a5d436cf9d1b8 Mon Sep 17 00:00:00 2001 From: carlo-bramini Date: Sun, 26 Nov 2017 11:02:24 +0100 Subject: [PATCH 3/9] Fix comment to the right #endif --- src/utils/fluid_sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/fluid_sys.c b/src/utils/fluid_sys.c index 3e567451..2ab24c51 100644 --- a/src/utils/fluid_sys.c +++ b/src/utils/fluid_sys.c @@ -1010,8 +1010,8 @@ static fluid_thread_return_t fluid_server_socket_run (void *data) char straddr[INET6_ADDRSTRLEN]; #else char straddr[INET_ADDRSTRLEN]; -#endif /* HAVE_INETNTOP */ #endif /* IPV6_SUPPORT */ +#endif /* HAVE_INETNTOP */ socklen_t addrlen = sizeof (addr); int r; From 44985b121282841eaf34cd73c3e12e23ee1ab2f7 Mon Sep 17 00:00:00 2001 From: carlo-bramini Date: Sun, 26 Nov 2017 11:07:09 +0100 Subject: [PATCH 4/9] INVALID_SOCKET can be into fluid_sys.c, near SOCKET_ERROR. No need to have it in fluidsynth_priv.h --- src/utils/fluid_sys.c | 1 + src/utils/fluidsynth_priv.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/fluid_sys.c b/src/utils/fluid_sys.c index 2ab24c51..1c622ffc 100644 --- a/src/utils/fluid_sys.c +++ b/src/utils/fluid_sys.c @@ -37,6 +37,7 @@ #else #define FLUID_SOCKET_FLAG 0x00000000 #define SOCKET_ERROR -1 + #define INVALID_SOCKET -1 #endif /* SCHED_FIFO priority for high priority timer threads */ diff --git a/src/utils/fluidsynth_priv.h b/src/utils/fluidsynth_priv.h index b67c8f47..bf2e7609 100644 --- a/src/utils/fluidsynth_priv.h +++ b/src/utils/fluidsynth_priv.h @@ -174,7 +174,6 @@ typedef double fluid_real_t; typedef SOCKET fluid_socket_t; #else typedef int fluid_socket_t; -#define INVALID_SOCKET -1 #endif #if defined(SUPPORTS_VLA) From c564fd6d5a27f52aa4ba1773fbcd41c1ced7a01e Mon Sep 17 00:00:00 2001 From: jjceresa <32781294+jjceresa@users.noreply.github.com> Date: Sun, 26 Nov 2017 13:39:01 +0100 Subject: [PATCH 5/9] Portaudio driver - unique device identification (#289) Changes the format of portaudio device names to ensure uniqueness of device names. Without uniqueness of device names the driver was unable to select the device chosen by the user. Fixes #284. --- src/drivers/fluid_portaudio.c | 151 +++++++++++++++++++++++++++------- 1 file changed, 123 insertions(+), 28 deletions(-) diff --git a/src/drivers/fluid_portaudio.c b/src/drivers/fluid_portaudio.c index 798ac6c9..043a2335 100644 --- a/src/drivers/fluid_portaudio.c +++ b/src/drivers/fluid_portaudio.c @@ -61,10 +61,63 @@ void delete_fluid_portaudio_driver (fluid_audio_driver_t *p); #define PORTAUDIO_DEFAULT_DEVICE "PortAudio Default" +/** + * Checks if device_num is a valid device and returns the name of the portaudio device. + * A device is valid if it is an output device with at least 2 channels. + * + * @param device_num index of the portaudio device to check. + * @param name_ptr if device_num is valid, set to a unique device name, ignored otherwise + * + * The name returned is unique for each num_device index, so this + * name is useful to identify any available host audio device. + * This name is convenient for audio.portaudio.device setting. + * + * The format of the name is: device_index:host_api_name:host_device_name + * + * example: 5:MME:SB PCI + * + * 5: is the portaudio device index. + * MME: is the host API name. + * SB PCI: is the host device name. + * + * @return #FLUID_OK if device_num is a valid output device, #FLUID_FAILED otherwise. + * When #FLUID_OK, the name is returned in allocated memory. The caller must check + * the name pointer for a valid memory allocation and should free the memory. + */ +static int fluid_portaudio_get_device_name(int device_num, char **name_ptr) +{ + const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo (device_num); + + if( deviceInfo->maxOutputChannels >= 2 ) + { + const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi ); + /* The size of the buffer name for the following format: + device_index:host_api_name:host_device_name. + */ + int i = device_num; + int size = 0; + do {size++; i = i/10 ;} while(i); /* index size */ + /* host API size + host device size + 2 separators + zero termination */ + size += strlen(hostInfo->name) + strlen(deviceInfo->name) + 3; + *name_ptr = FLUID_MALLOC (size); + if (*name_ptr) + { /* the name is filled if allocation is successful */ + FLUID_SPRINTF(*name_ptr,"%d:%s:%s",device_num, + hostInfo->name, deviceInfo->name); + } + return FLUID_OK; /* device_num is a valid device */ + } + else return FLUID_FAILED; /* device_num is an invalid device */ +} + +/** + * Initializes "audio.portaudio.device" setting with an options list of unique device names + * of available sound card devices. + * @param settings pointer to settings. + */ void fluid_portaudio_driver_settings (fluid_settings_t *settings) { - const PaDeviceInfo *deviceInfo; int numDevices; PaError err; int i; @@ -85,17 +138,27 @@ fluid_portaudio_driver_settings (fluid_settings_t *settings) if (numDevices < 0) { - FLUID_LOG (FLUID_ERR, "PortAudio returned unexpected device count %d", numDevices); - return; + FLUID_LOG (FLUID_ERR, "PortAudio returned unexpected device count %d", numDevices); } - - for (i = 0; i < numDevices; i++) + else for (i = 0; i < numDevices; i++) { - deviceInfo = Pa_GetDeviceInfo (i); - if ( deviceInfo->maxOutputChannels >= 2 ) - fluid_settings_add_option (settings, "audio.portaudio.device", - deviceInfo->name); - } + char * name; + if(fluid_portaudio_get_device_name(i, &name) == FLUID_OK) + { + /* the device i is a valid output device */ + if(name) + { + /* registers this name in the option list */ + fluid_settings_add_option (settings, "audio.portaudio.device", name); + FLUID_FREE (name); + } + else + { + FLUID_LOG (FLUID_ERR, "Out of memory"); + break; + } + } + } /* done with PortAudio for now, may get reopened later */ err = Pa_Terminate(); @@ -104,14 +167,22 @@ fluid_portaudio_driver_settings (fluid_settings_t *settings) printf ("PortAudio termination error: %s\n", Pa_GetErrorText (err) ); } +/** + * Creates the portaudio driver and opens the portaudio device + * indicated by audio.portaudio.device setting. + * + * @param settings pointer to settings + * @param synth the synthesizer instance + * @return pointer to the driver on success, NULL otherwise. + */ fluid_audio_driver_t * new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth) { fluid_portaudio_driver_t *dev = NULL; PaStreamParameters outputParams; - char *device = NULL; - double sample_rate; - int period_size; + char *device = NULL; /* the portaudio device name to work with */ + double sample_rate; /* intended sample rate */ + int period_size; /* intended buffer size */ PaError err; dev = FLUID_NEW (fluid_portaudio_driver_t); @@ -135,19 +206,20 @@ new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth) FLUID_MEMSET (dev, 0, sizeof (fluid_portaudio_driver_t)); dev->synth = synth; - + + /* gets audio parameters from the settings */ fluid_settings_getint (settings, "audio.period-size", &period_size); fluid_settings_getnum (settings, "synth.sample-rate", &sample_rate); fluid_settings_dupstr(settings, "audio.portaudio.device", &device); /* ++ alloc device name */ memset (&outputParams, 0, sizeof (outputParams)); - outputParams.channelCount = 2; + outputParams.channelCount = 2; /* For stereo output */ outputParams.suggestedLatency = (PaTime)period_size / sample_rate; /* Locate the device if specified */ if (strcmp (device, PORTAUDIO_DEFAULT_DEVICE) != 0) - { - const PaDeviceInfo *deviceInfo; + { /* The intended device is not the default device name, so we search + a device among available devices */ int numDevices; int i; @@ -161,23 +233,46 @@ new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth) for (i = 0; i < numDevices; i++) { - deviceInfo = Pa_GetDeviceInfo (i); + char * name; + if(fluid_portaudio_get_device_name(i, &name) == FLUID_OK ) + { + /* the device i is a valid output device */ + if(name) + { + /* We see if the name corresponds to audio.portaudio.device */ + char found = (strcmp (device, name) == 0); + FLUID_FREE (name); - if (strcmp (device, deviceInfo->name) == 0) - { - outputParams.device = i; - break; - } + if(found) + { + /* the device index is found */ + outputParams.device = i; + /* The search is finished */ + break; + } + } + else + { + FLUID_LOG (FLUID_ERR, "Out of memory"); + goto error_recovery; + } + } } - + if (i == numDevices) { FLUID_LOG (FLUID_ERR, "PortAudio device '%s' was not found", device); goto error_recovery; } } - else outputParams.device = Pa_GetDefaultOutputDevice(); + else + { /* the default device will be used */ + outputParams.device = Pa_GetDefaultOutputDevice(); + } + /* The device is found. We set the sample format and the audio rendering + function suited to this format. + */ if (fluid_settings_str_equal (settings, "audio.sample-format", "16bits")) { outputParams.sampleFormat = paInt16; @@ -199,11 +294,11 @@ new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth) /* Open an audio I/O stream. */ err = Pa_OpenStream (&dev->stream, NULL, /* Input parameters */ - &outputParams, + &outputParams, /* Output parameters */ sample_rate, period_size, paNoFlag, - fluid_portaudio_run, + fluid_portaudio_run, /* callback */ dev); if (err != paNoError) @@ -213,7 +308,7 @@ new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth) goto error_recovery; } - err = Pa_StartStream (dev->stream); + err = Pa_StartStream (dev->stream); /* starts the I/O stream */ if (err != paNoError) { From 99c03350fc91c83c52090759041c8ccf03bec638 Mon Sep 17 00:00:00 2001 From: derselbst Date: Sun, 26 Nov 2017 13:41:46 +0100 Subject: [PATCH 6/9] update API docs about unique portaudio device names --- doc/fluidsynth-v11-devdoc.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fluidsynth-v11-devdoc.txt b/doc/fluidsynth-v11-devdoc.txt index 68322c9a..591101f2 100644 --- a/doc/fluidsynth-v11-devdoc.txt +++ b/doc/fluidsynth-v11-devdoc.txt @@ -90,6 +90,7 @@ Changes in FluidSynth 2.0.0 concerning developers: - all public delete_* functions return void and are safe when called with NULL - the shell command handler was decoupled internally, as a consequence the param list of new_fluid_server() and new_fluid_cmd_handler() was adapted - reverb: roomsize is now limited to an upper threshold of 1.0 +- use unique device names for the "audio.portaudio.device" setting - add "synth.volenv" a setting for volume envelope processing - add "midi.autoconnect" a setting for automatically connecting fluidsynth to available MIDI input ports From 58a5f43d6a20f9a3807fa1033c7fec055f7ada35 Mon Sep 17 00:00:00 2001 From: derselbst Date: Sun, 26 Nov 2017 13:49:55 +0100 Subject: [PATCH 7/9] update fluidsettings about unique portaudio device names --- doc/fluidsettings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/fluidsettings.xml b/doc/fluidsettings.xml index dcdd2a35..8fe243af 100644 --- a/doc/fluidsettings.xml +++ b/doc/fluidsettings.xml @@ -364,7 +364,7 @@ https://stackoverflow.com/a/6251757 str PortAudio Default - Device to use for PortAudio driver output. Note that 'PortAudio Default' is a special value which outputs to the default PortAudio device. + Device to use for PortAudio driver output. Note that 'PortAudio Default' is a special value which outputs to the default PortAudio device. The format of the device name is: "<device_index>:<host_api_name>:<host_device_name>" e.g. "11:Windows DirectSound:SB PCI" From e7ff72df46c237ebffff2a3875b0a3ce32010b00 Mon Sep 17 00:00:00 2001 From: derselbst Date: Sun, 26 Nov 2017 14:05:22 +0100 Subject: [PATCH 8/9] make fluid_socket_*() helper functions static --- src/utils/fluid_sys.c | 6 +++--- src/utils/fluid_sys.h | 5 ----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/utils/fluid_sys.c b/src/utils/fluid_sys.c index 1c622ffc..d15d84eb 100644 --- a/src/utils/fluid_sys.c +++ b/src/utils/fluid_sys.c @@ -945,7 +945,7 @@ int fluid_server_socket_join(fluid_server_socket_t *server_socket) return fluid_thread_join (server_socket->thread); } -int fluid_socket_init(void) +static int fluid_socket_init(void) { #ifdef _WIN32 WSADATA wsaData; @@ -960,14 +960,14 @@ int fluid_socket_init(void) return FLUID_OK; } -void fluid_socket_cleanup(void) +static void fluid_socket_cleanup(void) { #ifdef _WIN32 WSACleanup(); #endif } -int fluid_socket_get_error(void) +static int fluid_socket_get_error(void) { #ifdef _WIN32 return (int)WSAGetLastError(); diff --git a/src/utils/fluid_sys.h b/src/utils/fluid_sys.h index 080810c5..d86d17ae 100644 --- a/src/utils/fluid_sys.h +++ b/src/utils/fluid_sys.h @@ -354,11 +354,6 @@ void fluid_socket_close(fluid_socket_t sock); fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock); fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock); -int fluid_socket_init(void); -void fluid_socket_cleanup(void); -int fluid_socket_get_error(void); - - /* Profiling */ From a13cb63103aa56b5e8bad816c7d13d6e01c0cd9f Mon Sep 17 00:00:00 2001 From: derselbst Date: Sun, 26 Nov 2017 22:12:12 +0100 Subject: [PATCH 9/9] avoid buffer overrun in fluid_synth_nwrite_float() --- src/synth/fluid_synth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/synth/fluid_synth.c b/src/synth/fluid_synth.c index 266d759a..14f6b21d 100644 --- a/src/synth/fluid_synth.c +++ b/src/synth/fluid_synth.c @@ -2752,10 +2752,10 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len, { #ifdef WITH_FLOAT if(fx_left != NULL) - FLUID_MEMCPY(fx_left[i + count], fx_left_in[i], bytes); + FLUID_MEMCPY(fx_left[i] + count, fx_left_in[i], bytes); if(fx_right != NULL) - FLUID_MEMCPY(fx_right[i + count], fx_right_in[i], bytes); + FLUID_MEMCPY(fx_right[i] + count, fx_right_in[i], bytes); #else //WITH_FLOAT int j; if(fx_left != NULL) {