[pulseaudio-discuss,v3,4/6] mix: Use time variable as a member of pa_cvolume_ramp_int structure

Submitted by Sangchul Lee on April 4, 2017, 2:36 p.m.

Details

Message ID 1491316616-21358-5-git-send-email-sangchul1011@gmail.com
State New
Headers show
Series "volume ramping" ( rev: 3 ) in PulseAudio

Not browsing as part of any series.

Commit Message

Sangchul Lee April 4, 2017, 2:36 p.m.
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@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(-)

Patch hide | download patch | download mbox

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)