audioconvert: make volume ramp parameters non-sticky

This mean the volume ramp parameters will have to be issued along with volume
every time. They will not be persistant.
This commit is contained in:
Ashok Sidipotu 2023-03-30 10:08:14 +05:30 committed by Wim Taymans
parent 737bc89ab9
commit 74872250e8

View file

@ -62,6 +62,14 @@ static void init_volumes(struct volumes *vol)
vol->volumes[i] = DEFAULT_VOLUME; vol->volumes[i] = DEFAULT_VOLUME;
} }
struct volume_ramp_params {
unsigned int volume_ramp_samples;
unsigned int volume_ramp_step_samples;
unsigned int volume_ramp_time;
unsigned int volume_ramp_step_time;
enum spa_audio_volume_ramp_scale scale;
};
struct props { struct props {
float volume; float volume;
float prev_volume; float prev_volume;
@ -70,15 +78,10 @@ struct props {
struct volumes channel; struct volumes channel;
struct volumes soft; struct volumes soft;
struct volumes monitor; struct volumes monitor;
unsigned int volume_ramp_samples; struct volume_ramp_params vrp;
unsigned int volume_ramp_step_samples;
unsigned int volume_ramp_time;
unsigned int volume_ramp_step_time;
enum spa_audio_volume_ramp_scale scale;
unsigned int have_soft_volume:1; unsigned int have_soft_volume:1;
unsigned int mix_disabled:1; unsigned int mix_disabled:1;
unsigned int resample_disabled:1; unsigned int resample_disabled:1;
unsigned int volume_ramp_enabled:1;
unsigned int resample_quality; unsigned int resample_quality;
double rate; double rate;
char wav_path[512]; char wav_path[512];
@ -97,7 +100,6 @@ static void props_reset(struct props *props)
props->have_soft_volume = false; props->have_soft_volume = false;
props->mix_disabled = false; props->mix_disabled = false;
props->resample_disabled = false; props->resample_disabled = false;
props->volume_ramp_enabled = false;
props->resample_quality = RESAMPLE_DEFAULT_QUALITY; props->resample_quality = RESAMPLE_DEFAULT_QUALITY;
props->rate = 1.0; props->rate = 1.0;
spa_zero(props->wav_path); spa_zero(props->wav_path);
@ -870,13 +872,13 @@ static int parse_prop_params(struct impl *this, struct spa_pod *params)
static unsigned int get_ramp_samples(struct impl *this) static unsigned int get_ramp_samples(struct impl *this)
{ {
struct props p = this->props; struct volume_ramp_params *vrp = &this->props.vrp;
if (p.volume_ramp_samples) if (vrp->volume_ramp_samples)
return p.volume_ramp_samples; return vrp->volume_ramp_samples;
else if (p.volume_ramp_time) { else if (vrp->volume_ramp_time) {
struct dir *d = &this->dir[SPA_DIRECTION_OUTPUT]; struct dir *d = &this->dir[SPA_DIRECTION_OUTPUT];
unsigned int sample_rate = d->format.info.raw.rate; unsigned int sample_rate = d->format.info.raw.rate;
unsigned int samples = (p.volume_ramp_time * sample_rate) / 1000; unsigned int samples = (vrp->volume_ramp_time * sample_rate) / 1000;
spa_log_info(this->log, "volume ramp samples calculated from time is %d", samples); spa_log_info(this->log, "volume ramp samples calculated from time is %d", samples);
return samples; return samples;
} }
@ -885,15 +887,15 @@ static unsigned int get_ramp_samples(struct impl *this)
static unsigned int get_ramp_step_samples(struct impl *this) static unsigned int get_ramp_step_samples(struct impl *this)
{ {
struct props p = this->props; struct volume_ramp_params *vrp = &this->props.vrp;
if (p.volume_ramp_step_samples) if (vrp->volume_ramp_step_samples)
return p.volume_ramp_step_samples; return vrp->volume_ramp_step_samples;
else if (p.volume_ramp_step_time) { else if (vrp->volume_ramp_step_time) {
struct dir *d = &this->dir[SPA_DIRECTION_OUTPUT]; struct dir *d = &this->dir[SPA_DIRECTION_OUTPUT];
int sample_rate = d->format.info.raw.rate; int sample_rate = d->format.info.raw.rate;
/* convert the step time which is in nano seconds to seconds */ /* convert the step time which is in nano seconds to seconds */
unsigned int samples = (p.volume_ramp_step_time/1000) * (sample_rate/1000); unsigned int samples = (vrp->volume_ramp_step_time/1000) * (sample_rate/1000);
spa_log_info(this->log, "volume ramp step samples calculated from time is %d", samples); spa_log_debug(this->log, "volume ramp step samples calculated from time is %d", samples);
return samples; return samples;
} }
return 0; return 0;
@ -901,34 +903,33 @@ static unsigned int get_ramp_step_samples(struct impl *this)
static double get_volume_at_scale(struct impl *this, double value) static double get_volume_at_scale(struct impl *this, double value)
{ {
struct props p = this->props; struct volume_ramp_params *vrp = &this->props.vrp;
if (p.scale == SPA_AUDIO_VOLUME_RAMP_LINEAR) if (vrp->scale == SPA_AUDIO_VOLUME_RAMP_LINEAR)
return value; return value;
else if (p.scale == SPA_AUDIO_VOLUME_RAMP_CUBIC) else if (vrp->scale == SPA_AUDIO_VOLUME_RAMP_CUBIC)
return (value * value * value); return (value * value * value);
return 0.0; return 0.0;
} }
static struct spa_pod *generate_vol_ramp_up_sequence(struct impl *this, const struct props *p) static struct spa_pod *generate_ramp_up_seq(struct impl *this)
{ {
uint8_t buffer[64 * 1024];
struct spa_pod_dynamic_builder b; struct spa_pod_dynamic_builder b;
struct spa_pod_frame f[1]; struct spa_pod_frame f[1];
struct props *p = &this->props;
double volume_accum = p->prev_volume; double volume_accum = p->prev_volume;
unsigned int ramp_samples = get_ramp_samples(this); unsigned int ramp_samples = get_ramp_samples(this);
unsigned int ramp_step_samples = get_ramp_step_samples(this); unsigned int ramp_step_samples = get_ramp_step_samples(this);
double volume_step = ((p->volume - p->prev_volume) / (ramp_samples / ramp_step_samples)); double volume_step = ((p->volume - p->prev_volume) / (ramp_samples / ramp_step_samples));
uint32_t volume_offs = 0; uint32_t volume_offs = 0;
spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); spa_pod_dynamic_builder_init(&b, NULL, 0, 4096);
spa_pod_builder_push_sequence(&b.b, &f[0], 0); spa_pod_builder_push_sequence(&b.b, &f[0], 0);
spa_log_info(this->log, "generating ramp up sequence from %f to %f with a step value %f at scale %d", spa_log_info(this->log, "generating ramp up sequence from %f to %f with a step value %f at scale %d",
p->prev_volume,p->volume, volume_step, p->scale); p->prev_volume,p->volume, volume_step, p->scale);
do { do {
// spa_log_info(this->log, "volume level %f offset %d", get_volume_at_scale(this, volume_accum), volume_offs); spa_log_info(this->log, "volume accum %f", get_volume_at_scale(this, volume_accum));
spa_pod_builder_control(&b.b, volume_offs, SPA_CONTROL_Properties); spa_pod_builder_control(&b.b, volume_offs, SPA_CONTROL_Properties);
spa_pod_builder_add_object(&b.b, spa_pod_builder_add_object(&b.b,
SPA_TYPE_OBJECT_Props, 0, SPA_TYPE_OBJECT_Props, 0,
@ -937,29 +938,27 @@ static struct spa_pod *generate_vol_ramp_up_sequence(struct impl *this, const st
volume_accum += volume_step; volume_accum += volume_step;
volume_offs += ramp_step_samples; volume_offs += ramp_step_samples;
} while (volume_accum < p->volume); } while (volume_accum < p->volume);
spa_pod_builder_pop(&b.b, &f[0]);
return spa_pod_builder_pop(&b.b, &f[0]); return spa_pod_builder_pop(&b.b, &f[0]);
} }
static struct spa_pod *generate_vol_ramp_down_sequence(struct impl *this, const struct props *p) static struct spa_pod *generate_ramp_down_seq(struct impl *this)
{ {
uint8_t buffer[64 * 1024];
struct spa_pod_dynamic_builder b; struct spa_pod_dynamic_builder b;
struct spa_pod_frame f[1]; struct spa_pod_frame f[1];
unsigned int ramp_samples = get_ramp_samples(this); unsigned int ramp_samples = get_ramp_samples(this);
unsigned int ramp_step_samples = get_ramp_step_samples(this); unsigned int ramp_step_samples = get_ramp_step_samples(this);
struct props *p = &this->props;
double volume_accum = p->prev_volume; double volume_accum = p->prev_volume;
double volume_step = ((p->prev_volume - p->volume) / (ramp_samples / ramp_step_samples)); double volume_step = ((p->prev_volume - p->volume) / (ramp_samples / ramp_step_samples));
uint32_t volume_offs = 0; uint32_t volume_offs = 0;
spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); spa_pod_dynamic_builder_init(&b, NULL, 0, 4096);
spa_pod_builder_push_sequence(&b.b, &f[0], 0); spa_pod_builder_push_sequence(&b.b, &f[0], 0);
spa_log_info(this->log, "generating ramp down sequence from %f to %f with a step value %f at scale %d", spa_log_info(this->log, "generating ramp down sequence from %f to %f with a step value %f at scale %d",
p->prev_volume, p->volume, volume_step, p->scale); p->prev_volume, p->volume, volume_step, p->vrp.scale);
do { do {
// spa_log_info(this->log, "volume level %f offset %d", get_volume_at_scale(this, volume_accum), volume_offs); spa_log_info(this->log, "volume accum %f", get_volume_at_scale(this, volume_accum));
spa_pod_builder_control(&b.b, volume_offs, SPA_CONTROL_Properties); spa_pod_builder_control(&b.b, volume_offs, SPA_CONTROL_Properties);
spa_pod_builder_add_object(&b.b, spa_pod_builder_add_object(&b.b,
SPA_TYPE_OBJECT_Props, 0, SPA_TYPE_OBJECT_Props, 0,
@ -969,16 +968,17 @@ static struct spa_pod *generate_vol_ramp_down_sequence(struct impl *this, const
volume_accum -= volume_step; volume_accum -= volume_step;
volume_offs += ramp_step_samples; volume_offs += ramp_step_samples;
} while (volume_accum > p->volume); } while (volume_accum > p->volume);
spa_pod_builder_pop(&b.b, &f[0]);
return spa_pod_builder_pop(&b.b, &f[0]); return spa_pod_builder_pop(&b.b, &f[0]);
} }
static struct spa_pod *generate_vol_ramp_sequence(struct impl *this, const struct props *p) static struct volume_ramp_params *reset_volume_ramp_params(struct impl *this)
{ {
if (p->volume > p->prev_volume) if (!this->vol_ramp_sequence) {
return generate_vol_ramp_up_sequence(this, p); struct volume_ramp_params *vrp = &this->props.vrp;
else spa_zero(this->props.vrp);
return generate_vol_ramp_down_sequence(this, p); return vrp;
}
return 0;
} }
static int apply_props(struct impl *this, const struct spa_pod *param) static int apply_props(struct impl *this, const struct spa_pod *param)
@ -989,6 +989,8 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
bool have_channel_volume = false; bool have_channel_volume = false;
bool have_soft_volume = false; bool have_soft_volume = false;
int changed = 0; int changed = 0;
int vol_ramp_params_changed = 0;
struct volume_ramp_params *vrp = reset_volume_ramp_params(this);
uint32_t n; uint32_t n;
int32_t value; int32_t value;
uint32_t id; uint32_t id;
@ -997,20 +999,10 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
switch (prop->key) { switch (prop->key) {
case SPA_PROP_volume: case SPA_PROP_volume:
p->prev_volume = p->volume; p->prev_volume = p->volume;
spa_log_debug(this->log, "%p previous volume %f", this, p->prev_volume);
if (spa_pod_get_float(&prop->value, &p->volume) == 0) { if (spa_pod_get_float(&prop->value, &p->volume) == 0) {
spa_log_debug(this->log, "%p current volume %f", this, p->volume); spa_log_debug(this->log, "%p new volume %f", this, p->volume);
if (p->volume_ramp_enabled && !this->vol_ramp_sequence) { changed++;
this->vol_ramp_sequence = (struct spa_pod_sequence *) generate_vol_ramp_sequence (this, p);
if (!this->vol_ramp_sequence) {
spa_log_error(this->log, "unable to generate sequence");
return EIO;
}
this->vol_ramp_offset = 0;
}
else
changed++;
} }
break; break;
case SPA_PROP_mute: case SPA_PROP_mute:
@ -1020,74 +1012,66 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
} }
break; break;
case SPA_PROP_volumeRampSamples: case SPA_PROP_volumeRampSamples:
if (this->vol_ramp_sequence) {
if (p->volume_ramp_enabled && this->vol_ramp_sequence) {
spa_log_error(this->log, "%p volume ramp sequence is being " spa_log_error(this->log, "%p volume ramp sequence is being "
"applied try again", this); "applied try again", this);
return EAGAIN; return -EAGAIN;
} }
if (spa_pod_get_int(&prop->value, &value) == 0 && value) { if (spa_pod_get_int(&prop->value, &value) == 0 && value) {
p->volume_ramp_samples = value; vrp->volume_ramp_samples = value;
spa_log_info(this->log, "%p volume ramp samples %d", this, spa_log_info(this->log, "%p volume ramp samples %d", this, value);
p->volume_ramp_samples); vol_ramp_params_changed++;
p->volume_ramp_enabled = true;
} }
break; break;
case SPA_PROP_volumeRampStepSamples: case SPA_PROP_volumeRampStepSamples:
if (p->volume_ramp_enabled && this->vol_ramp_sequence) { if (this->vol_ramp_sequence) {
spa_log_error(this->log, "%p volume ramp sequence is being " spa_log_error(this->log, "%p volume ramp sequence is being "
"applied try again", this); "applied try again", this);
return EAGAIN; return -EAGAIN;
} }
if (spa_pod_get_int(&prop->value, &value) == 0 && value) { if (spa_pod_get_int(&prop->value, &value) == 0 && value) {
p->volume_ramp_step_samples = value; vrp->volume_ramp_step_samples = value;
spa_log_info(this->log, "%p volume ramp step samples is %d", spa_log_info(this->log, "%p volume ramp step samples is %d",
this, p->volume_ramp_step_samples); this, value);
p->volume_ramp_enabled = true;
} }
break; break;
case SPA_PROP_volumeRampTime: case SPA_PROP_volumeRampTime:
if (p->volume_ramp_enabled && this->vol_ramp_sequence) { if (this->vol_ramp_sequence) {
spa_log_error(this->log, "%p volume ramp sequence is being " spa_log_error(this->log, "%p volume ramp sequence is being "
"applied try again", this); "applied try again", this);
return EAGAIN; return -EAGAIN;
} }
if (spa_pod_get_int(&prop->value, &value) == 0 && value) { if (spa_pod_get_int(&prop->value, &value) == 0 && value) {
p->volume_ramp_time = value; vrp->volume_ramp_time = value;
spa_log_info(this->log, "%p volume ramp time %d", this, spa_log_info(this->log, "%p volume ramp time %d", this, value);
p->volume_ramp_time); vol_ramp_params_changed++;
p->volume_ramp_enabled = true;
} }
break; break;
case SPA_PROP_volumeRampStepTime: case SPA_PROP_volumeRampStepTime:
if (p->volume_ramp_enabled && this->vol_ramp_sequence) { if (this->vol_ramp_sequence) {
spa_log_error(this->log, "%p volume ramp sequence is being " spa_log_error(this->log, "%p volume ramp sequence is being "
"applied try again", this); "applied try again", this);
return EAGAIN; return -EAGAIN;
} }
if (spa_pod_get_int(&prop->value, &value) == 0 && value) { if (spa_pod_get_int(&prop->value, &value) == 0 && value) {
p->volume_ramp_step_time = value; vrp->volume_ramp_step_time = value;
spa_log_info(this->log, "%p volume ramp time %d", this, spa_log_info(this->log, "%p volume ramp time %d", this, value);
p->volume_ramp_step_samples);
p->volume_ramp_enabled = true;
} }
break; break;
case SPA_PROP_volumeRampScale: case SPA_PROP_volumeRampScale:
if (p->volume_ramp_enabled && this->vol_ramp_sequence) { if (this->vol_ramp_sequence) {
spa_log_error(this->log, "%p volume ramp sequence is being " spa_log_error(this->log, "%p volume ramp sequence is being "
"applied try again", this); "applied try again", this);
return EAGAIN; return -EAGAIN;
} }
if (spa_pod_get_id(&prop->value, &id) == 0) { if (spa_pod_get_id(&prop->value, &id) == 0) {
p->scale = id; vrp->scale = id;
spa_log_info(this->log, "%p volume ramp scale %d", this, spa_log_info(this->log, "%p volume ramp scale %d", this, id);
p->scale);
p->volume_ramp_enabled = true;
} }
break; break;
case SPA_PROP_channelVolumes: case SPA_PROP_channelVolumes:
@ -1153,6 +1137,24 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
set_volume(this); set_volume(this);
} }
if (vol_ramp_params_changed) {
void *sequence = NULL;
if (p->volume == p->prev_volume) {
spa_log_error(this->log, "no change in volume, cannot ramp volume");
return EIO;
} else if (p->volume > p->prev_volume)
sequence = generate_ramp_up_seq(this);
else
sequence = generate_ramp_down_seq(this);
if (!sequence) {
spa_log_error(this->log, "unable to generate sequence");
return EIO;
}
this->vol_ramp_sequence = (struct spa_pod_sequence *) sequence;
this->vol_ramp_offset = 0;
}
return changed; return changed;
} }
@ -1449,7 +1451,7 @@ static void set_volume(struct impl *this)
float volumes[SPA_AUDIO_MAX_CHANNELS]; float volumes[SPA_AUDIO_MAX_CHANNELS];
struct dir *dir = &this->dir[this->direction]; struct dir *dir = &this->dir[this->direction];
spa_log_debug(this->log, "%p set volume %f have_format:%d", this, this->props.volume, dir->have_format); spa_log_info(this->log, "%p set volume %f have_format:%d", this, this->props.volume, dir->have_format);
if (dir->have_format) if (dir->have_format)
remap_volumes(this, &dir->format); remap_volumes(this, &dir->format);