Previously there was a member variable for fixed number of samples used to calculate ramping but it has limitation in case of a stream with variable sample rate. It is modified to set time(microseconds) for ramping duration instead of the number of samples and it will be used in pa_sink_input_peek function so that current sample rate can be applied even if it has variable sample rate. Signed-off-by: Sangchul Lee <sc11.lee at samsung.com> --- src/pulse/volume.c | 14 ++++---- src/pulse/volume.h | 6 ++-- src/pulsecore/mix.c | 82 +++++++++++++++++++++++++--------------------- src/pulsecore/mix.h | 8 ++--- src/pulsecore/sink-input.c | 7 ++-- 5 files changed, 60 insertions(+), 57 deletions(-) diff --git a/src/pulse/volume.c b/src/pulse/volume.c index 5f9c4ed..923c967 100644 --- a/src/pulse/volume.c +++ b/src/pulse/volume.c @@ -991,7 +991,7 @@ int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b) { for (i = 0; i < a->channels; i++) { if (a->ramps[i].type != b->ramps[i].type || - a->ramps[i].length != b->ramps[i].length || + a->ramps[i].duration != b->ramps[i].duration || a->ramps[i].target != b->ramps[i].target) return 0; } @@ -1008,40 +1008,38 @@ pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp) { for (c = 0; c < PA_CHANNELS_MAX; c++) { ramp->ramps[c].type = PA_VOLUME_RAMP_TYPE_LINEAR; - ramp->ramps[c].length = 0; + ramp->ramps[c].duration = 0; ramp->ramps[c].target = PA_VOLUME_INVALID; } return ramp; } -pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channels, pa_volume_ramp_type_t type, long time, pa_volume_t vol) { +pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channels, pa_volume_ramp_type_t type, pa_usec_t duration, pa_volume_t vol) { int i; pa_assert(ramp); pa_assert(channels > 0); - pa_assert(time >= 0); pa_assert(channels <= PA_CHANNELS_MAX); ramp->channels = (uint8_t) channels; for (i = 0; i < ramp->channels; i++) { ramp->ramps[i].type = type; - ramp->ramps[i].length = time; + ramp->ramps[i].duration = duration; ramp->ramps[i].target = PA_CLAMP_VOLUME(vol); } return ramp; } -pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol) { +pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, pa_usec_t duration, pa_volume_t vol) { pa_assert(ramp); pa_assert(channel <= ramp->channels); - pa_assert(time >= 0); ramp->ramps[channel].type = type; - ramp->ramps[channel].length = time; + ramp->ramps[channel].duration = duration; ramp->ramps[channel].target = PA_CLAMP_VOLUME(vol); return ramp; diff --git a/src/pulse/volume.h b/src/pulse/volume.h index 1b66427..672c8c4 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -442,7 +442,7 @@ typedef enum pa_volume_ramp_type { /** A structure encapsulating a volume ramp */ typedef struct pa_volume_ramp { pa_volume_ramp_type_t type; - long length; + pa_usec_t duration; pa_volume_t target; } pa_volume_ramp; @@ -459,10 +459,10 @@ int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b); pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp); /** Set first n channels of ramp struct to certain value */ -pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol); +pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, pa_usec_t duration, pa_volume_t vol); /** Set individual channel in the channel struct */ -pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol); +pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, pa_usec_t duration, pa_volume_t vol); PA_C_DECL_END diff --git a/src/pulsecore/mix.c b/src/pulsecore/mix.c index b87f9ff..2516eab 100644 --- a/src/pulsecore/mix.c +++ b/src/pulsecore/mix.c @@ -771,10 +771,10 @@ static const pa_calc_volume_no_mapping_func_t calc_volume_table_no_mapping[] = { static float calc_volume_ramp_linear(pa_volume_ramp_int *ramp) { pa_assert(ramp); - pa_assert(ramp->length > 0); + pa_assert(ramp->duration > 0); /* basic linear interpolation */ - return ramp->start + (ramp->length - ramp->left) * (ramp->end - ramp->start) / (float) ramp->length; + return ramp->start + (ramp->duration - ramp->left) * (ramp->end - ramp->start) / (float) ramp->duration; } static float calc_volume_ramp_logarithmic(pa_volume_ramp_int *ramp) { @@ -782,14 +782,14 @@ static float calc_volume_ramp_logarithmic(pa_volume_ramp_int *ramp) { long temp; pa_assert(ramp); - pa_assert(ramp->length > 0); + pa_assert(ramp->duration > 0); if (ramp->end > ramp->start) { temp = ramp->left; s = ramp->end; e = ramp->start; } else { - temp = ramp->length - ramp->left; + temp = ramp->duration - ramp->left; s = ramp->start; e = ramp->end; } @@ -797,7 +797,7 @@ static float calc_volume_ramp_logarithmic(pa_volume_ramp_int *ramp) { x_val = temp == 0 ? 0.0 : powf(temp, 10); /* base 10 logarithmic interpolation */ - return s + x_val * (e - s) / powf(ramp->length, 10); + return s + x_val * (e - s) / powf(ramp->duration, 10); } static float calc_volume_ramp_cubic(pa_volume_ramp_int *ramp) { @@ -805,14 +805,14 @@ static float calc_volume_ramp_cubic(pa_volume_ramp_int *ramp) { long temp; pa_assert(ramp); - pa_assert(ramp->length > 0); + pa_assert(ramp->duration > 0); if (ramp->end > ramp->start) { temp = ramp->left; s = ramp->end; e = ramp->start; } else { - temp = ramp->length - ramp->left; + temp = ramp->duration - ramp->left; s = ramp->start; e = ramp->end; } @@ -820,7 +820,7 @@ static float calc_volume_ramp_cubic(pa_volume_ramp_int *ramp) { x_val = temp == 0 ? 0.0 : cbrtf(temp); /* cubic interpolation */ - return s + x_val * (e - s) / cbrtf(ramp->length); + return s + x_val * (e - s) / cbrtf(ramp->duration); } typedef float (*pa_calc_volume_ramp_func_t) (pa_volume_ramp_int *); @@ -831,18 +831,21 @@ static const pa_calc_volume_ramp_func_t calc_volume_ramp_table[] = { [PA_VOLUME_RAMP_TYPE_CUBIC] = (pa_calc_volume_ramp_func_t) calc_volume_ramp_cubic }; -static void calc_volume_ramps(pa_cvolume_ramp_int *ramp, float *vol) +static void calc_volume_ramps(pa_cvolume_ramp_int *ramp, float *vol, pa_usec_t consumed) { int i; for (i = 0; i < ramp->channels; i++) { - if (ramp->ramps[i].left <= 0) { + if (ramp->ramps[i].left == 0) { if (ramp->ramps[i].target == PA_VOLUME_NORM) { vol[i] = 1.0; } } else { vol[i] = ramp->ramps[i].curr = calc_volume_ramp_table[ramp->ramps[i].type] (&ramp->ramps[i]); - ramp->ramps[i].left--; + if (ramp->ramps[i].left >= consumed) + ramp->ramps[i].left -= consumed; + else + ramp->ramps[i].left = 0; } } } @@ -857,6 +860,7 @@ void pa_volume_ramp_memchunk( float vol[PA_CHANNELS_MAX + VOLUME_PADDING]; pa_do_volume_func_t do_volume; long length_in_frames; + pa_usec_t time_of_frames; int i; pa_assert(c); @@ -865,11 +869,14 @@ void pa_volume_ramp_memchunk( pa_assert(ramp); length_in_frames = c->length / pa_sample_size_of_format(spec->format) / spec->channels; + time_of_frames = length_in_frames * 1000000 / spec->rate; if (pa_memblock_is_silence(c->memblock)) { for (i = 0; i < ramp->channels; i++) { - if (ramp->ramps[i].length > 0) - ramp->ramps[i].length -= length_in_frames; + if (ramp->ramps[i].duration >= time_of_frames) + ramp->ramps[i].duration -= time_of_frames; + else + ramp->ramps[i].duration = 0; } return; } @@ -885,7 +892,7 @@ void pa_volume_ramp_memchunk( ptr = (uint8_t*) pa_memblock_acquire(c->memblock) + c->index; for (i = 0; i < length_in_frames; i++) { - calc_volume_ramps(ramp, vol); + calc_volume_ramps(ramp, vol, time_of_frames / length_in_frames); calc_volume_table_no_mapping[spec->format] ((void *)linear, vol, spec->channels); /* we only process one frame per iteration */ @@ -899,7 +906,7 @@ void pa_volume_ramp_memchunk( pa_memblock_release(c->memblock); } -pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst, int sample_rate) { +pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst) { int i, j, channels, remaining_channels; float temp; @@ -907,17 +914,15 @@ pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvol if (dst->channels < src->channels) { channels = dst->channels; remaining_channels = 0; - } - else { + } else { channels = src->channels; remaining_channels = dst->channels; } for (i = 0; i < channels; i++) { dst->ramps[i].type = src->ramps[i].type; - /* ms to samples */ - dst->ramps[i].length = src->ramps[i].length * sample_rate / 1000; - dst->ramps[i].left = dst->ramps[i].length; + dst->ramps[i].duration = src->ramps[i].duration; + dst->ramps[i].left = dst->ramps[i].duration; dst->ramps[i].start = dst->ramps[i].end; dst->ramps[i].target = src->ramps[i].target; /* scale to pulse internal mapping so that when ramp is over there's no glitch in volume */ @@ -929,7 +934,7 @@ pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvol for (i--; j < remaining_channels; j++) { dst->ramps[j].type = dst->ramps[i].type; - dst->ramps[j].length = dst->ramps[i].length; + dst->ramps[j].duration = dst->ramps[i].duration; dst->ramps[j].left = dst->ramps[i].left; dst->ramps[j].start = dst->ramps[i].start; dst->ramps[j].target = dst->ramps[i].target; @@ -987,32 +992,33 @@ pa_cvolume_ramp_int* pa_cvolume_ramp_start_from(pa_cvolume_ramp_int *src, pa_cvo return dst; } -pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, int channels) { +pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, uint8_t channels) { int i; - float temp; + float tmp_start, tmp_end, tmp_curr; src->channels = channels; for (i = 0; i < channels; i++) { src->ramps[i].type = PA_VOLUME_RAMP_TYPE_LINEAR; - src->ramps[i].length = 0; + src->ramps[i].duration = 0; src->ramps[i].left = 0; if (vol == PA_VOLUME_NORM) { - src->ramps[i].start = 1.0; - src->ramps[i].end = 1.0; - src->ramps[i].curr = 1.0; - } - else if (vol == PA_VOLUME_MUTED) { - src->ramps[i].start = 0.0; - src->ramps[i].end = 0.0; - src->ramps[i].curr = 0.0; - } - else { - temp = vol / (float)0x10000U; - src->ramps[i].start = temp * temp * temp; - src->ramps[i].end = src->ramps[i].start; - src->ramps[i].curr = src->ramps[i].start; + tmp_start = 1.0; + tmp_end = 1.0; + tmp_curr = 1.0; + } else if (vol == PA_VOLUME_MUTED) { + tmp_start = 0.0; + tmp_end = 0.0; + tmp_curr = 0.0; + } else { + tmp_start = vol / (float)0x10000U; + tmp_start = tmp_start * tmp_start * tmp_start; + tmp_end = tmp_start; + tmp_curr = tmp_start; } + src->ramps[i].start = tmp_start; + src->ramps[i].end = tmp_end; + src->ramps[i].curr = tmp_curr; src->ramps[i].target = vol; } diff --git a/src/pulsecore/mix.h b/src/pulsecore/mix.h index ccd8255..b8fad17 100644 --- a/src/pulsecore/mix.h +++ b/src/pulsecore/mix.h @@ -61,8 +61,8 @@ void pa_volume_memchunk( typedef struct pa_volume_ramp_int { pa_volume_ramp_type_t type; - long length; - long left; + pa_usec_t duration; + pa_usec_t left; float start; float end; float curr; @@ -74,11 +74,11 @@ typedef struct pa_cvolume_ramp_int { pa_volume_ramp_int ramps[PA_CHANNELS_MAX]; } pa_cvolume_ramp_int; -pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst, int sample_rate); +pa_cvolume_ramp_int* pa_cvolume_ramp_convert(const pa_cvolume_ramp *src, pa_cvolume_ramp_int *dst); bool pa_cvolume_ramp_active(pa_cvolume_ramp_int *ramp); bool pa_cvolume_ramp_target_active(pa_cvolume_ramp_int *ramp); pa_cvolume_ramp_int* pa_cvolume_ramp_start_from(pa_cvolume_ramp_int *src, pa_cvolume_ramp_int *dst); -pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, int channels); +pa_cvolume_ramp_int* pa_cvolume_ramp_int_init(pa_cvolume_ramp_int *src, pa_volume_t vol, uint8_t channels); pa_cvolume * pa_cvolume_ramp_get_targets(pa_cvolume_ramp_int *ramp, pa_cvolume *volume); void pa_volume_ramp_memchunk( diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index f18e4f9..a36373a 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -1389,12 +1389,11 @@ void pa_sink_input_set_volume_ramp( pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(ramp); - pa_cvolume_ramp_convert(ramp, &i->ramp, i->sample_spec.rate); + pa_cvolume_ramp_convert(ramp, &i->ramp); - pa_log_debug("setting volume ramp with target vol:%d and length:%ld", + pa_log_debug("setting volume ramp with target vol:%d and duration:%lu(usec)", i->ramp.ramps[0].target, - i->ramp.ramps[0].length); - + i->ramp.ramps[0].duration); /* This tells the sink that volume ramp changed */ if (send_msg) -- 2.7.4