Update sample D-Bus commands

Rename D-Bus LoudnessFilterActive property to Loudness and friends
Update sample D-Bus commands
Add D-Bus convolution filter controls -- enable convolution filters to be turned on and off or changed; enable convolution gain to be checked and changed; fix loudness control.
Fix D-Bus loudness switch silencing output. Rename LoudnessFiulterActive to Loudness. Add Convolution, ConvolutionGain and ConvolutionImpulseResponseFile properties to the D-Bus interface.
Bug fix: correct frame size entry for S24 format
This commit is contained in:
Mike Brady
2019-11-13 22:04:22 +00:00
parent c8ea68b8c8
commit 78c9331c2c
13 changed files with 1437 additions and 97 deletions
+59 -43
View File
@@ -1,69 +1,85 @@
#include "convolver.h"
#include <pthread.h>
#include <sndfile.h>
#include "convolver.h"
#include "FFTConvolver.h"
#include "Utilities.h"
extern "C" void _die(const char *filename, const int linenumber, const char *format, ...);
extern "C" void _warn(const char *filename, const int linenumber, const char *format, ...);
extern "C" void _debug(const char *filename, const int linenumber, int level, const char *format, ...);
#define die(...) _die(__FILE__, __LINE__, __VA_ARGS__)
#define warn(...) _warn(__FILE__, __LINE__, __VA_ARGS__)
#define debug(...) _debug(__FILE__, __LINE__, __VA_ARGS__)
static fftconvolver::FFTConvolver convolver_l;
static fftconvolver::FFTConvolver convolver_r;
fftconvolver::FFTConvolver convolver_l;
fftconvolver::FFTConvolver convolver_r;
// always lock use this when accessing the playing conn value
pthread_mutex_t convolver_lock = PTHREAD_MUTEX_INITIALIZER;
void convolver_init(const char* filename, int max_length)
{
int convolver_init(const char* filename, int max_length) {
int success = 0;
SF_INFO info;
assert(filename);
SNDFILE* file = sf_open(filename, SFM_READ, &info);
assert(file);
if (filename) {
SNDFILE* file = sf_open(filename, SFM_READ, &info);
if (file) {
if (info.samplerate != 44100)
die("Impulse file \"%s\" sample rate is %d Hz. Only 44100 Hz is supported", filename, info.samplerate);
if (info.samplerate == 44100) {
if ((info.channels == 1) || (info.channels == 2)) {
const size_t size = info.frames > max_length ? max_length : info.frames;
float buffer[size*info.channels];
if (info.channels != 1 && info.channels != 2)
die("Impulse file \"%s\" contains %d channels. Only 1 or 2 is supported.", filename, info.channels);
size_t l = sf_readf_float(file, buffer, size);
if (l != 0) {
pthread_mutex_lock(&convolver_lock);
convolver_l.reset(); // it is possible that init could be called more than once
convolver_r.reset(); // so it could be necessary to remove all previous settings
const size_t size = info.frames > max_length ? max_length : info.frames;
float buffer[size*info.channels];
size_t l = sf_readf_float(file, buffer, size);
assert(l == size);
if (info.channels == 1) {
convolver_l.init(352, buffer, size);
convolver_r.init(352, buffer, size);
} else {
// deinterleave
float buffer_l[size];
float buffer_r[size];
if (info.channels == 1) {
convolver_l.init(352, buffer, size);
convolver_r.init(352, buffer, size);
} else {
// deinterleave
float buffer_l[size];
float buffer_r[size];
unsigned int i;
for (i=0; i<size; ++i)
{
buffer_l[i] = buffer[2*i+0];
buffer_r[i] = buffer[2*i+1];
unsigned int i;
for (i=0; i<size; ++i)
{
buffer_l[i] = buffer[2*i+0];
buffer_r[i] = buffer[2*i+1];
}
convolver_l.init(352, buffer_l, size);
convolver_r.init(352, buffer_r, size);
}
pthread_mutex_unlock(&convolver_lock);
success = 1;
}
debug(1, "IR initialized from \"%s\" with %d channels and %d samples", filename, info.channels, size);
} else {
warn("Impulse file \"%s\" contains %d channels. Only 1 or 2 is supported.", filename, info.channels);
}
} else {
warn("Impulse file \"%s\" sample rate is %d Hz. Only 44100 Hz is supported", filename, info.samplerate);
}
sf_close(file);
}
convolver_l.init(352, buffer_l, size);
convolver_r.init(352, buffer_r, size);
}
debug(1, "IR initialized from \"%s\" with %d channels and %d samples", filename, info.channels, size);
sf_close(file);
return success;
}
void convolver_process_l(float* data, int length)
{
void convolver_process_l(float* data, int length) {
pthread_mutex_lock(&convolver_lock);
convolver_l.process(data, data, length);
pthread_mutex_unlock(&convolver_lock);
}
void convolver_process_r(float* data, int length)
{
void convolver_process_r(float* data, int length) {
pthread_mutex_lock(&convolver_lock);
convolver_r.process(data, data, length);
pthread_mutex_unlock(&convolver_lock);
}
+1 -1
View File
@@ -5,7 +5,7 @@
extern "C" {
#endif
void convolver_init(const char* file, int max_length);
int convolver_init(const char* file, int max_length);
void convolver_process_l(float* data, int length);
void convolver_process_r(float* data, int length);
+1 -1
View File
@@ -371,7 +371,7 @@ unsigned int auto_speed_output_rates[] = {
format_record fr[] = {
{SND_PCM_FORMAT_UNKNOWN, 0}, // unknown
{SND_PCM_FORMAT_S8, 2}, {SND_PCM_FORMAT_U8, 2}, {SND_PCM_FORMAT_S16, 4},
{SND_PCM_FORMAT_S16_LE, 4}, {SND_PCM_FORMAT_S16_BE, 4}, {SND_PCM_FORMAT_S24, 4},
{SND_PCM_FORMAT_S16_LE, 4}, {SND_PCM_FORMAT_S16_BE, 4}, {SND_PCM_FORMAT_S24, 8},
{SND_PCM_FORMAT_S24_LE, 8}, {SND_PCM_FORMAT_S24_BE, 8}, {SND_PCM_FORMAT_S24_3LE, 6},
{SND_PCM_FORMAT_S24_3BE, 6}, {SND_PCM_FORMAT_S32, 8}, {SND_PCM_FORMAT_S32_LE, 8},
{SND_PCM_FORMAT_S32_BE, 8}, {SND_PCM_FORMAT_UNKNOWN, 0}, // auto
+2 -1
View File
@@ -230,7 +230,8 @@ typedef struct {
#ifdef CONFIG_CONVOLUTION
int convolution;
const char *convolution_ir_file;
int convolver_valid;
char *convolution_ir_file;
float convolution_gain;
int convolution_max_length;
#endif
+1 -1
View File
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.50])
AC_INIT([shairport-sync], [3.3.4], [mikebrady@eircom.net])
AC_INIT([shairport-sync], [3.3.5], [mikebrady@eircom.net])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
+95 -9
View File
@@ -15,6 +15,10 @@
#include "dbus-service.h"
#ifdef CONFIG_CONVOLUTION
#include <FFTConvolver/convolver.h>
#endif
int service_is_running = 0;
ShairportSyncDiagnostics *shairportSyncDiagnosticsSkeleton = NULL;
@@ -413,14 +417,78 @@ gboolean notify_disable_standby_callback(ShairportSync *skeleton,
return TRUE;
}
gboolean notify_loudness_filter_active_callback(ShairportSync *skeleton,
#ifdef CONFIG_CONVOLUTION
gboolean notify_convolution_callback(ShairportSync *skeleton,
__attribute__((unused)) gpointer user_data) {
// debug(1, "\"notify_loudness_filter_active_callback\" called.");
if (shairport_sync_get_loudness_filter_active(skeleton)) {
debug(1, ">> activating loudness filter");
// debug(1, "\"notify_convolution_callback\" called.");
if (shairport_sync_get_convolution(skeleton)) {
debug(1, ">> activating convolution");
config.convolution = 1;
config.convolver_valid = convolver_init(config.convolution_ir_file, config.convolution_max_length);
} else {
debug(1, ">> deactivating convolution");
config.convolution = 0;
}
return TRUE;
}
#else
gboolean notify_convolution_callback(__attribute__((unused)) ShairportSync *skeleton,
__attribute__((unused)) gpointer user_data) {
warn(">> Convolution support is not built in to this build of Shairport Sync.");
return TRUE;
}
#endif
#ifdef CONFIG_CONVOLUTION
gboolean notify_convolution_gain_callback(ShairportSync *skeleton,
__attribute__((unused)) gpointer user_data) {
gdouble th = shairport_sync_get_convolution_gain(skeleton);
if ((th <= 0.0) && (th >= -100.0)) {
debug(1, ">> setting convolution gain to %f.", th);
config.convolution_gain = th;
} else {
debug(1, ">> invalid convolution gain: %f. Ignored.", th);
shairport_sync_set_convolution_gain(skeleton, config.convolution_gain);
}
return TRUE;
}
#else
gboolean notify_convolution_gain_callback(__attribute__((unused)) ShairportSync *skeleton,
__attribute__((unused)) gpointer user_data) {
warn(">> Convolution support is not built in to this build of Shairport Sync.");
return TRUE;
}
#endif
#ifdef CONFIG_CONVOLUTION
gboolean notify_convolution_impulse_response_file_callback(ShairportSync *skeleton,
__attribute__((unused)) gpointer user_data) {
char *th = (char *)shairport_sync_get_convolution_impulse_response_file(skeleton);
if (config.convolution_ir_file)
free(config.convolution_ir_file);
config.convolution_ir_file = strdup(th);
debug(1, ">> setting configuration impulse response filter file to \"%s\".", config.convolution_ir_file);
config.convolver_valid = convolver_init(config.convolution_ir_file, config.convolution_max_length);
return TRUE;
}
#else
gboolean notify_convolution_impulse_response_file_callback(__attribute__((unused)) ShairportSync *skeleton,
__attribute__((unused)) gpointer user_data) {
char *th = (char *)shairport_sync_get_convolution_impulse_response_file(skeleton);
return TRUE;
}
#endif
gboolean notify_loudness_callback(ShairportSync *skeleton,
__attribute__((unused)) gpointer user_data) {
// debug(1, "\"notify_loudness_callback\" called.");
if (shairport_sync_get_loudness(skeleton)) {
debug(1, ">> activating loudness");
config.loudness = 1;
} else {
debug(1, ">> deactivating loudness filter");
debug(1, ">> deactivating loudness");
config.loudness = 0;
}
return TRUE;
@@ -687,8 +755,14 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
G_CALLBACK(notify_volume_control_profile_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::disable-standby",
G_CALLBACK(notify_disable_standby_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::loudness-filter-active",
G_CALLBACK(notify_loudness_filter_active_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::convolution",
G_CALLBACK(notify_convolution_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::convolution-gain",
G_CALLBACK(notify_convolution_gain_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::convolution-impulse-response-file",
G_CALLBACK(notify_convolution_impulse_response_file_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::loudness",
G_CALLBACK(notify_loudness_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::loudness-threshold",
G_CALLBACK(notify_loudness_threshold_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::drift-tolerance",
@@ -824,11 +898,23 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
}
if (config.loudness == 0) {
shairport_sync_set_loudness_filter_active(SHAIRPORT_SYNC(shairportSyncSkeleton), FALSE);
shairport_sync_set_loudness(SHAIRPORT_SYNC(shairportSyncSkeleton), FALSE);
} else {
shairport_sync_set_loudness_filter_active(SHAIRPORT_SYNC(shairportSyncSkeleton), TRUE);
shairport_sync_set_loudness(SHAIRPORT_SYNC(shairportSyncSkeleton), TRUE);
}
#ifdef CONFIG_CONVOLUTION
if (config.convolution == 0) {
shairport_sync_set_convolution(SHAIRPORT_SYNC(shairportSyncSkeleton), FALSE);
} else {
shairport_sync_set_convolution(SHAIRPORT_SYNC(shairportSyncSkeleton), TRUE);
}
if (config.convolution_ir_file)
shairport_sync_set_convolution_impulse_response_file(SHAIRPORT_SYNC(shairportSyncSkeleton), config.convolution_ir_file);
// else
// shairport_sync_set_convolution_impulse_response_file(SHAIRPORT_SYNC(shairportSyncSkeleton), NULL);
#endif
shairport_sync_set_version(SHAIRPORT_SYNC(shairportSyncSkeleton), PACKAGE_VERSION);
char *vs = get_version_string();
shairport_sync_set_version_string(SHAIRPORT_SYNC(shairportSyncSkeleton), vs);
+42 -3
View File
@@ -24,10 +24,49 @@ dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/Shair
dbus-send --system --print-reply --type=method_call --dest=org.gnome.ShairportSync '/org/gnome/ShairportSync' org.gnome.ShairportSync.RemoteControl.Play
#Remote Control commands include: Play, Pause, PlayPause, Resume, Stop, Next, Previous, VolumeUp, VolumeDown, ToggleMute, FastForward, Rewind, ShuffleSongs
# Set Volume using Advanced Remote Control
dbus-send --system --print-reply --type=method_call --dest=org.gnome.ShairportSync '/org/gnome/ShairportSync' org.gnome.ShairportSync.AdvancedRemoteControl.SetVolume int32:50
# Get Drift Tolerance
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:DriftTolerance
# Set Drift Tolerance to 1 millisecond
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:DriftTolerance variant:double:0.001
# Is Loudness Enabled:
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:LoudnessThreshold
# Enable Loudness Filter
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:Loudness variant:boolean:true
# Get Loudness Threshold
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:LoudnessThreshold
# Set Loudness Threshold
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:LoudnessThreshold variant:double:-15.0
# Is Convolution enabled:
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:Convolution
# Enable Convolution
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:Convolution variant:boolean:true
# Get Convolution Gain:
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:ConvolutionGain
# Set Convolution Gain -- the gain applied before convolution is applied -- to -10.0 dB
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:ConvolutionGain variant:double:-10
# Get Convolution Impulse Response File:
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync string:ConvolutionImpulseResponseFile
# Set Convolution Impulse Response File:
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Set string:org.gnome.ShairportSync string:ConvolutionImpulseResponseFile variant:string:"/etc/shairport-sync/boom.wav"
# Some commands and properties are accessible only through the AdvancedRemoteControl interface.
# Unfortunately, only iTunes provides the functionality to allow the AdvancedRemoteControl interface to work.
# (The macOS "Music" app replacing iTunes appears to have no remote interface whatever (at least as far as is known).)
# You can check to see if AdvancedRemoteControl is available using the command:
dbus-send --print-reply --system --dest=org.gnome.ShairportSync /org/gnome/ShairportSync org.freedesktop.DBus.Properties.Get string:org.gnome.ShairportSync.AdvancedRemoteControl string:Available
# Set Volume using Advanced Remote Control -- only works if the org.gnome.ShairportSync.AdvancedRemoteControl is available.
dbus-send --system --print-reply --type=method_call --dest=org.gnome.ShairportSync '/org/gnome/ShairportSync' org.gnome.ShairportSync.AdvancedRemoteControl.SetVolume int32:50
+1 -1
View File
@@ -44,7 +44,7 @@ void loudness_set_volume(float volume) {
if (gain < 0)
gain = 0;
inform("Volume: %.1f dB - Loudness gain @10Hz: %.1f dB", volume, gain);
debug(2, "Volume: %.1f dB - Loudness gain @10Hz: %.1f dB", volume, gain);
_loudness_set_volume(&loudness_l, volume);
_loudness_set_volume(&loudness_r, volume);
}
+1194 -23
View File
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -5,8 +5,11 @@
<property name='Active' type='b' access='read'/>
<property name="DisableStandby" type="b" access="readwrite" />
<property name="DisableStandbyMode" type="s" access="readwrite" />
<property name="LoudnessFilterActive" type="b" access="readwrite" />
<property name="Loudness" type="b" access="readwrite" />
<property name="LoudnessThreshold" type="d" access="readwrite" />
<property name="Convolution" type="b" access="readwrite" />
<property name="ConvolutionGain" type="d" access="readwrite" />
<property name="ConvolutionImpulseResponseFile" type="s" access="readwrite" />
<property name="DriftTolerance" type="d" access="readwrite" />
<method name="RemoteCommand">
<arg name="command" type="s" direction="in" />
+26 -7
View File
@@ -2365,9 +2365,27 @@ void *player_thread_func(void *arg) {
amount_to_stuff = 0; // no stuffing if it's been disabled
// Apply DSP here
if (config.loudness
// check the state of loudness and convolution flags here and don't change them for the frame
int do_loudness = config.loudness;
#ifdef CONFIG_CONVOLUTION
|| config.convolution
int do_convolution = 0;
if ((config.convolution) && (config.convolver_valid))
do_convolution = 1;
// we will apply the convolution gain if convolution is enabled, even if there is no valid convolution happening
int convolution_is_enabled = 0;
if (config.convolution)
convolution_is_enabled = 1;
#endif
if (do_loudness
#ifdef CONFIG_CONVOLUTION
|| convolution_is_enabled
#endif
) {
int32_t *tbuf32 = (int32_t *)conn->tbuf;
@@ -2383,10 +2401,11 @@ void *player_thread_func(void *arg) {
#ifdef CONFIG_CONVOLUTION
// Apply convolution
if (config.convolution) {
if (do_convolution) {
convolver_process_l(fbuf_l, inbuflength);
convolver_process_r(fbuf_r, inbuflength);
}
if (convolution_is_enabled) {
float gain = pow(10.0, config.convolution_gain / 20.0);
for (i = 0; i < inbuflength; ++i) {
fbuf_l[i] *= gain;
@@ -2395,7 +2414,7 @@ void *player_thread_func(void *arg) {
}
#endif
if (config.loudness) {
if (do_loudness) {
// Apply volume and loudness
// Volume must be applied here because the loudness filter will increase the
// signal level and it would saturate the int32_t otherwise
@@ -2902,8 +2921,8 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
conn->fix_volume = temp_fix_volume;
if (config.loudness)
loudness_set_volume(software_attenuation / 100);
// if (config.loudness)
loudness_set_volume(software_attenuation / 100);
}
if (config.logOutputLevel) {
+3 -3
View File
@@ -40,11 +40,11 @@ void on_properties_changed(__attribute__((unused)) GDBusProxy *proxy, GVariant *
}
}
void notify_loudness_filter_active_callback(ShairportSync *proxy,
void notify_loudness_callback(ShairportSync *proxy,
__attribute__((unused)) gpointer user_data) {
// printf("\"notify_loudness_filter_active_callback\" called with a gpointer of
// printf("\"notify_loudness_callback\" called with a gpointer of
// %lx.\n",(int64_t)user_data);
gboolean ebl = shairport_sync_get_loudness_filter_active(proxy);
gboolean ebl = shairport_sync_get_loudness(proxy);
if (ebl == TRUE)
printf("Client reports loudness is enabled.\n");
else
+8 -3
View File
@@ -962,12 +962,12 @@ int parse_options(int argc, char **argv) {
}
if (config_lookup_string(config.cfg, "dsp.convolution_ir_file", &str)) {
config.convolution_ir_file = str;
convolver_init(config.convolution_ir_file, config.convolution_max_length);
config.convolution_ir_file = strdup(str);
config.convolver_valid = convolver_init(config.convolution_ir_file, config.convolution_max_length);
}
if (config.convolution && config.convolution_ir_file == NULL) {
die("Convolution enabled but no convolution_ir_file provided");
warn("Convolution enabled but no convolution_ir_file provided");
}
#endif
if (config_lookup_string(config.cfg, "dsp.loudness", &str)) {
@@ -1339,6 +1339,11 @@ Actually, there is no stop_mpris_service() function.
if (config.service_name)
free(config.service_name);
#ifdef CONFIG_CONVOLUTION
if (config.convolution_ir_file)
free(config.convolution_ir_file);
#endif
if (config.regtype)
free(config.regtype);