PA_MODULE_AUTHOR("Niels Ole Salscheider");
PA_MODULE_DESCRIPTION(_("Virtual surround sink"));
PA_MODULE_VERSION(PACKAGE_VERSION);
-PA_MODULE_LOAD_ONCE(FALSE);
+PA_MODULE_LOAD_ONCE(false);
PA_MODULE_USAGE(
_("sink_name=<name for the sink> "
"sink_properties=<properties for the sink> "
pa_module *module;
/* FIXME: Uncomment this and take "autoloaded" as a modarg if this is a filter */
- /* pa_bool_t autoloaded; */
+ /* bool autoloaded; */
pa_sink *sink;
pa_sink_input *sink_input;
pa_memblockq *memblockq;
- pa_bool_t auto_desc;
+ bool auto_desc;
unsigned channels;
unsigned hrir_channels;
/* Just hand this one over to the master sink */
pa_sink_input_request_rewind(u->sink_input,
s->thread_info.rewind_nbytes +
- pa_memblockq_get_length(u->memblockq), TRUE, FALSE, FALSE);
+ pa_memblockq_get_length(u->memblockq), true, false, false);
}
/* Called from I/O thread context */
!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
return;
- pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, TRUE);
+ pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, true);
}
/* Called from main context */
u->sink->thread_info.rewind_nbytes = 0;
if (amount > 0) {
- pa_memblockq_seek(u->memblockq, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
+ pa_memblockq_seek(u->memblockq, - (int64_t) amount, PA_SEEK_RELATIVE, true);
/* Reset the input buffer */
memset(u->input_buffer, 0, u->hrir_samples * u->sink_fs);
pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency);
- pa_sink_set_max_request_within_thread(u->sink, pa_sink_input_get_max_request(i));
+ pa_sink_set_max_request_within_thread(u->sink, pa_sink_input_get_max_request(i) * u->sink_fs / u->fs);
/* FIXME: Too small max_rewind:
* https://bugs.freedesktop.org/show_bug.cgi?id=53709 */
- pa_sink_set_max_rewind_within_thread(u->sink, pa_sink_input_get_max_rewind(i));
+ pa_sink_set_max_rewind_within_thread(u->sink, pa_sink_input_get_max_rewind(i) * u->sink_fs / u->fs);
pa_sink_attach_within_thread(u->sink);
}
pa_sink_unref(u->sink);
u->sink = NULL;
- pa_module_unload_request(u->module, TRUE);
+ pa_module_unload_request(u->module, true);
}
/* Called from IO thread context */
if (PA_SINK_INPUT_IS_LINKED(state) &&
i->thread_info.state == PA_SINK_INPUT_INIT) {
pa_log_debug("Requesting rewind due to state change.");
- pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
+ pa_sink_input_request_rewind(i, 0, false, true, true);
}
}
-/* Called from main context */
-static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
- struct userdata *u;
-
- pa_sink_input_assert_ref(i);
- pa_assert_se(u = i->userdata);
-
- return u->sink != dest;
-}
-
/* Called from main context */
static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
struct userdata *u;
}
}
+static void normalize_hrir(struct userdata *u) {
+ /* normalize hrir to avoid audible clipping
+ *
+ * The following heuristic tries to avoid audible clipping. It cannot avoid
+ * clipping in the worst case though, because the scaling factor would
+ * become too large resulting in a too quiet signal.
+ * The idea of the heuristic is to avoid clipping when a single click is
+ * played back on all channels. The scaling factor describes the additional
+ * factor that is necessary to avoid clipping for "normal" signals.
+ *
+ * This algorithm doesn't pretend to be perfect, it's just something that
+ * appears to work (not too quiet, no audible clipping) on the material that
+ * it has been tested on. If you find a real-world example where this
+ * algorithm results in audible clipping, please write a patch that adjusts
+ * the scaling factor constants or improves the algorithm (or if you can't
+ * write a patch, at least report the problem to the PulseAudio mailing list
+ * or bug tracker). */
+
+ const float scaling_factor = 2.5;
+
+ float hrir_sum, hrir_max;
+ unsigned i, j;
+
+ hrir_max = 0;
+ for (i = 0; i < u->hrir_samples; i++) {
+ hrir_sum = 0;
+ for (j = 0; j < u->hrir_channels; j++)
+ hrir_sum += fabs(u->hrir_data[i * u->hrir_channels + j]);
+
+ if (hrir_sum > hrir_max)
+ hrir_max = hrir_sum;
+ }
+
+ for (i = 0; i < u->hrir_samples; i++) {
+ for (j = 0; j < u->hrir_channels; j++)
+ u->hrir_data[i * u->hrir_channels + j] /= hrir_max * scaling_factor;
+ }
+}
+
int pa__init(pa_module*m) {
struct userdata *u;
pa_sample_spec ss, sink_input_ss;
pa_sink *master=NULL;
pa_sink_input_new_data sink_input_data;
pa_sink_new_data sink_data;
- pa_bool_t use_volume_sharing = TRUE;
- pa_bool_t force_flat_volume = FALSE;
+ bool use_volume_sharing = true;
+ bool force_flat_volume = false;
pa_memchunk silence;
const char *hrir_file;
unsigned i, j, found_channel_left, found_channel_right;
- float hrir_sum, hrir_max;
float *hrir_data;
pa_sample_spec hrir_ss;
/* Initialize hrir and input buffer */
/* this is the hrir file for the left ear! */
- hrir_file = pa_modargs_get_value(ma, "hrir", NULL);
-
if (!(hrir_file = pa_modargs_get_value(ma, "hrir", NULL))) {
pa_log("The mandatory 'hrir' module argument is missing.");
goto fail;
pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb);
if (!use_volume_sharing) {
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
- pa_sink_enable_decibel_volume(u->sink, TRUE);
+ pa_sink_enable_decibel_volume(u->sink, true);
}
/* Normally this flag would be enabled automatically be we can force it. */
if (force_flat_volume)
pa_sink_input_new_data_init(&sink_input_data);
sink_input_data.driver = __FILE__;
sink_input_data.module = m;
- pa_sink_input_new_data_set_sink(&sink_input_data, master, FALSE);
+ pa_sink_input_new_data_set_sink(&sink_input_data, master, false);
sink_input_data.origin_sink = u->sink;
pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Surround Sink Stream from %s", pa_proplist_gets(u->sink->proplist, PA_PROP_DEVICE_DESCRIPTION));
pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
u->sink_input->attach = sink_input_attach_cb;
u->sink_input->detach = sink_input_detach_cb;
u->sink_input->state_change = sink_input_state_change_cb;
- u->sink_input->may_move_to = sink_input_may_move_to_cb;
u->sink_input->moving = sink_input_moving_cb;
u->sink_input->volume_changed = use_volume_sharing ? NULL : sink_input_volume_changed_cb;
u->sink_input->mute_changed = sink_input_mute_changed_cb;
/* add silence to the hrir until we get enough samples out of the resampler */
while (hrir_copied_length < hrir_total_length) {
pa_resampler_run(resampler, &hrir_temp_chunk, &hrir_temp_chunk_resampled);
- /* Silence input block */
- pa_silence_memblock(hrir_temp_chunk.memblock, &hrir_temp_ss);
+ if (hrir_temp_chunk.memblock != hrir_temp_chunk_resampled.memblock) {
+ /* Silence input block */
+ pa_silence_memblock(hrir_temp_chunk.memblock, &hrir_temp_ss);
+ }
if (hrir_temp_chunk_resampled.memblock) {
/* Copy hrir data */
goto fail;
}
- /* normalize hrir to avoid clipping */
- hrir_max = 0;
- for (i = 0; i < u->hrir_samples; i++) {
- hrir_sum = 0;
- for (j = 0; j < u->hrir_channels; j++)
- hrir_sum += fabs(u->hrir_data[i * u->hrir_channels + j]);
-
- if (hrir_sum > hrir_max)
- hrir_max = hrir_sum;
- }
- if (hrir_max > 1) {
- for (i = 0; i < u->hrir_samples; i++) {
- for (j = 0; j < u->hrir_channels; j++)
- u->hrir_data[i * u->hrir_channels + j] /= hrir_max * 1.2;
- }
- }
+ normalize_hrir(u);
/* create mapping between hrir and input */
u->mapping_left = (unsigned *) pa_xnew0(unsigned, u->channels);