mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	audioconvert: add support for volume ramp time params
This commit is contained in:
		
							parent
							
								
									075fd49ccc
								
							
						
					
					
						commit
						b0f6c4a8c0
					
				
					 2 changed files with 77 additions and 28 deletions
				
			
		| 
						 | 
					@ -60,11 +60,15 @@ enum spa_prop {
 | 
				
			||||||
	SPA_PROP_waveType,
 | 
						SPA_PROP_waveType,
 | 
				
			||||||
	SPA_PROP_frequency,
 | 
						SPA_PROP_frequency,
 | 
				
			||||||
	SPA_PROP_volume,			/**< a volume (Float), 0.0 silence, 1.0 normal */
 | 
						SPA_PROP_volume,			/**< a volume (Float), 0.0 silence, 1.0 normal */
 | 
				
			||||||
	SPA_PROP_volumeRampSamples,			/**< Samples to ramp the volume over */
 | 
						SPA_PROP_volumeRampSamples,		/**< Samples to ramp the volume over
 | 
				
			||||||
	SPA_PROP_volumeRampStepSamples,			/**< Step or incremental Samples to ramp the volume over */
 | 
											  *-1 is invalid, 0 ramps over instantly*/
 | 
				
			||||||
	SPA_PROP_volumeRampTime,			/**< Time to ramp the volume over */
 | 
						SPA_PROP_volumeRampStepSamples,		/**< Step or incremental Samples to ramp the volume over
 | 
				
			||||||
	SPA_PROP_volumeRampStepTime,			/**< Step or incremental Time to ramp the volume over */
 | 
											  *-1 is invalid, 0 ramps over instantly */
 | 
				
			||||||
	SPA_PROP_volumeRampScale,			/**< the scale or graph to used to ramp the volume */
 | 
						SPA_PROP_volumeRampTime,		/**< Time in millisec to ramp the volume over
 | 
				
			||||||
 | 
											  *-1 is invalid, 0 ramps over instantly*/
 | 
				
			||||||
 | 
						SPA_PROP_volumeRampStepTime,		/**< Step or incremental Time in nano seconds to ramp the
 | 
				
			||||||
 | 
											  *volume over -1 is invalid, 0 ramps over instantly */
 | 
				
			||||||
 | 
						SPA_PROP_volumeRampScale,		/**< the scale or graph to used to ramp the volume */
 | 
				
			||||||
	SPA_PROP_mute,				/**< mute (Bool) */
 | 
						SPA_PROP_mute,				/**< mute (Bool) */
 | 
				
			||||||
	SPA_PROP_patternType,
 | 
						SPA_PROP_patternType,
 | 
				
			||||||
	SPA_PROP_ditherType,
 | 
						SPA_PROP_ditherType,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,6 +46,8 @@ static struct spa_log_topic *log_topic = &SPA_LOG_TOPIC(0, "spa.audioconvert");
 | 
				
			||||||
#define DEFAULT_MUTE	false
 | 
					#define DEFAULT_MUTE	false
 | 
				
			||||||
#define DEFAULT_VOLUME	VOLUME_NORM
 | 
					#define DEFAULT_VOLUME	VOLUME_NORM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define INVALID	-1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct volumes {
 | 
					struct volumes {
 | 
				
			||||||
	bool mute;
 | 
						bool mute;
 | 
				
			||||||
	uint32_t n_volumes;
 | 
						uint32_t n_volumes;
 | 
				
			||||||
| 
						 | 
					@ -69,10 +71,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;
 | 
						int volume_ramp_samples;
 | 
				
			||||||
	unsigned int volume_ramp_step_samples;
 | 
						int volume_ramp_step_samples;
 | 
				
			||||||
	unsigned int volume_ramp_time;
 | 
						int volume_ramp_time;
 | 
				
			||||||
	unsigned int volume_ramp_step_time;
 | 
						int volume_ramp_step_time;
 | 
				
			||||||
	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;
 | 
				
			||||||
| 
						 | 
					@ -865,26 +867,62 @@ static int parse_prop_params(struct impl *this, struct spa_pod *params)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return changed;
 | 
						return changed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned int get_ramp_samples(struct impl *this)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct props p = this->props;
 | 
				
			||||||
 | 
						if (p.volume_ramp_samples != INVALID)
 | 
				
			||||||
 | 
							return p.volume_ramp_samples;
 | 
				
			||||||
 | 
						else if (p.volume_ramp_time != INVALID) {
 | 
				
			||||||
 | 
							struct dir *d = &this->dir[SPA_DIRECTION_OUTPUT];
 | 
				
			||||||
 | 
							unsigned int sample_rate = d->format.info.raw.rate;
 | 
				
			||||||
 | 
							unsigned int samples = (p.volume_ramp_time * sample_rate) / 1000;
 | 
				
			||||||
 | 
							spa_log_info(this->log, "volume ramp samples calculated from time is %d", samples);
 | 
				
			||||||
 | 
							return samples;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned int get_ramp_step_samples(struct impl *this)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct props p = this->props;
 | 
				
			||||||
 | 
						if (p.volume_ramp_step_samples != INVALID)
 | 
				
			||||||
 | 
							return p.volume_ramp_step_samples;
 | 
				
			||||||
 | 
						else if (p.volume_ramp_step_time != INVALID) {
 | 
				
			||||||
 | 
							struct dir *d = &this->dir[SPA_DIRECTION_OUTPUT];
 | 
				
			||||||
 | 
							int sample_rate = d->format.info.raw.rate;
 | 
				
			||||||
 | 
							/* convert the step time which is in nano seconds to seconds */
 | 
				
			||||||
 | 
							unsigned int samples = (p.volume_ramp_step_time/1000) * (sample_rate/1000);
 | 
				
			||||||
 | 
							spa_log_info(this->log, "volume ramp step samples calculated from time is %d", samples);
 | 
				
			||||||
 | 
							return samples;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct spa_pod *generate_vol_ramp_up_sequence(struct impl *this, const struct props *p)
 | 
					static struct spa_pod *generate_vol_ramp_up_sequence(struct impl *this, const struct props *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint8_t buffer[64 * 1024 * 10];
 | 
						uint8_t buffer[64 * 1024 * 10];
 | 
				
			||||||
	struct spa_pod_builder b;
 | 
						struct spa_pod_builder b;
 | 
				
			||||||
	struct spa_pod_frame f[1];
 | 
						struct spa_pod_frame f[1];
 | 
				
			||||||
	double volume_accum = p->prev_volume;
 | 
						double volume_accum = p->prev_volume;
 | 
				
			||||||
	double volume_step = (p->volume - p->prev_volume) / (p->volume_ramp_samples / p->volume_ramp_step_samples);
 | 
						unsigned int ramp_samples = get_ramp_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));
 | 
				
			||||||
	uint32_t volume_offs = 0;
 | 
						uint32_t volume_offs = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_pod_builder_init(&b, buffer, sizeof(buffer));
 | 
						spa_pod_builder_init(&b, buffer, sizeof(buffer));
 | 
				
			||||||
	spa_pod_builder_push_sequence(&b, &f[0], 0);
 | 
						spa_pod_builder_push_sequence(&b, &f[0], 0);
 | 
				
			||||||
	spa_log_debug(this->log, "generating ramp up sequence from %f to %f with a step value %f",
 | 
						spa_log_info(this->log, "generating volume ramp up sequence from %f to %f with a step value %f",
 | 
				
			||||||
				p->volume, p->prev_volume, volume_step);
 | 
								p->prev_volume,p->volume, volume_step);
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
 | 
							// spa_log_info(this->log, "volume level %f offset %d", volume_accum, volume_offs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		spa_pod_builder_control(&b, volume_offs, SPA_CONTROL_Properties);
 | 
							spa_pod_builder_control(&b, volume_offs, SPA_CONTROL_Properties);
 | 
				
			||||||
		spa_pod_builder_add_object(&b,
 | 
							spa_pod_builder_add_object(&b,
 | 
				
			||||||
				SPA_TYPE_OBJECT_Props, 0,
 | 
									SPA_TYPE_OBJECT_Props, 0,
 | 
				
			||||||
				SPA_PROP_volume, SPA_POD_Float(volume_accum));
 | 
									SPA_PROP_volume, SPA_POD_Float(volume_accum));
 | 
				
			||||||
		volume_accum += volume_step;
 | 
							volume_accum += volume_step;
 | 
				
			||||||
		volume_offs += p->volume_ramp_step_samples;
 | 
							volume_offs += ramp_step_samples;
 | 
				
			||||||
	} while (volume_accum < p->volume);
 | 
						} while (volume_accum < p->volume);
 | 
				
			||||||
	spa_pod_builder_pop(&b, &f[0]);
 | 
						spa_pod_builder_pop(&b, &f[0]);
 | 
				
			||||||
	return spa_pod_builder_pop(&b, &f[0]);
 | 
						return spa_pod_builder_pop(&b, &f[0]);
 | 
				
			||||||
| 
						 | 
					@ -895,21 +933,24 @@ static struct spa_pod *generate_vol_ramp_down_sequence(struct impl *this, const
 | 
				
			||||||
	uint8_t buffer[64 * 1024 * 10];
 | 
						uint8_t buffer[64 * 1024 * 10];
 | 
				
			||||||
	struct spa_pod_builder b;
 | 
						struct spa_pod_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_step_samples = get_ramp_step_samples(this);
 | 
				
			||||||
	double volume_accum = p->prev_volume;
 | 
						double volume_accum = p->prev_volume;
 | 
				
			||||||
	double volume_step = (p->prev_volume - p->volume) / (p->volume_ramp_samples / p->volume_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_builder_init(&b, buffer, sizeof(buffer));
 | 
						spa_pod_builder_init(&b, buffer, sizeof(buffer));
 | 
				
			||||||
	spa_pod_builder_push_sequence(&b, &f[0], 0);
 | 
						spa_pod_builder_push_sequence(&b, &f[0], 0);
 | 
				
			||||||
	spa_log_debug(this->log, "generating ramp up sequence from %f to %f with a step value %f",
 | 
						spa_log_info(this->log, "generating volume ramp down sequence from %f to %f with a step value %f",
 | 
				
			||||||
			p->prev_volume, p->volume, volume_step);
 | 
								p->prev_volume, p->volume, volume_step);
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
 | 
							// spa_log_info(this->log, "volume level %f offset %d", volume_accum, volume_offs);
 | 
				
			||||||
		spa_pod_builder_control(&b, volume_offs, SPA_CONTROL_Properties);
 | 
							spa_pod_builder_control(&b, volume_offs, SPA_CONTROL_Properties);
 | 
				
			||||||
		spa_pod_builder_add_object(&b,
 | 
							spa_pod_builder_add_object(&b,
 | 
				
			||||||
				SPA_TYPE_OBJECT_Props, 0,
 | 
									SPA_TYPE_OBJECT_Props, 0,
 | 
				
			||||||
				SPA_PROP_volume, SPA_POD_Float(volume_accum));
 | 
									SPA_PROP_volume, SPA_POD_Float(volume_accum));
 | 
				
			||||||
		volume_accum -= volume_step;
 | 
							volume_accum -= volume_step;
 | 
				
			||||||
		volume_offs += p->volume_ramp_step_samples;
 | 
							volume_offs += ramp_step_samples;
 | 
				
			||||||
	} while (volume_accum > p->volume);
 | 
						} while (volume_accum > p->volume);
 | 
				
			||||||
	spa_pod_builder_pop(&b, &f[0]);
 | 
						spa_pod_builder_pop(&b, &f[0]);
 | 
				
			||||||
	return spa_pod_builder_pop(&b, &f[0]);
 | 
						return spa_pod_builder_pop(&b, &f[0]);
 | 
				
			||||||
| 
						 | 
					@ -967,9 +1008,10 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
 | 
				
			||||||
				return EAGAIN;
 | 
									return EAGAIN;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (spa_pod_get_int(&prop->value, &value) == 0) {
 | 
								if (spa_pod_get_int(&prop->value, &value) == 0 && value != INVALID) {
 | 
				
			||||||
				p->volume_ramp_samples = value;
 | 
									p->volume_ramp_samples = value;
 | 
				
			||||||
				spa_log_debug(this->log, "volume ramp samples %d", p->volume_ramp_samples);
 | 
									p->volume_ramp_time = INVALID;
 | 
				
			||||||
 | 
									spa_log_info(this->log, "volume ramp samples %d", p->volume_ramp_samples);
 | 
				
			||||||
				p->volume_ramp_enabled = true;
 | 
									p->volume_ramp_enabled = true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
| 
						 | 
					@ -979,9 +1021,10 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
 | 
				
			||||||
				return EAGAIN;
 | 
									return EAGAIN;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (spa_pod_get_int(&prop->value, &value) == 0) {
 | 
								if (spa_pod_get_int(&prop->value, &value) == 0 && value != INVALID) {
 | 
				
			||||||
				p->volume_ramp_step_samples = value;
 | 
									p->volume_ramp_step_samples = value;
 | 
				
			||||||
				spa_log_info(this->log, "here_we_are  volume ramp step time is %d",
 | 
									p->volume_ramp_step_time = INVALID;
 | 
				
			||||||
 | 
									spa_log_info(this->log, "volume ramp step samples is %d",
 | 
				
			||||||
						p->volume_ramp_step_samples);
 | 
											p->volume_ramp_step_samples);
 | 
				
			||||||
				p->volume_ramp_enabled = true;
 | 
									p->volume_ramp_enabled = true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -992,9 +1035,10 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
 | 
				
			||||||
				return EAGAIN;
 | 
									return EAGAIN;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (spa_pod_get_int(&prop->value, &value) == 0) {
 | 
								if (spa_pod_get_int(&prop->value, &value) == 0 && value != INVALID) {
 | 
				
			||||||
				p->volume_ramp_time = value;
 | 
									p->volume_ramp_time = value;
 | 
				
			||||||
				spa_log_debug(this->log, "volume ramp time %d", p->volume_ramp_time);
 | 
									p->volume_ramp_samples = INVALID;
 | 
				
			||||||
 | 
									spa_log_info(this->log, "volume ramp time %d", p->volume_ramp_time);
 | 
				
			||||||
				p->volume_ramp_enabled = true;
 | 
									p->volume_ramp_enabled = true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
| 
						 | 
					@ -1004,10 +1048,11 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
 | 
				
			||||||
				return EAGAIN;
 | 
									return EAGAIN;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (spa_pod_get_int(&prop->value, &value) == 0) {
 | 
								if (spa_pod_get_int(&prop->value, &value) == 0 && value != INVALID) {
 | 
				
			||||||
				spa_log_debug(this->log, "volume ramp step time %d",
 | 
					 | 
				
			||||||
						p->volume_ramp_step_time);
 | 
					 | 
				
			||||||
				p->volume_ramp_step_time = value;
 | 
									p->volume_ramp_step_time = value;
 | 
				
			||||||
 | 
									spa_log_info(this->log, "volume ramp step time %d",
 | 
				
			||||||
 | 
											p->volume_ramp_step_time);
 | 
				
			||||||
 | 
									p->volume_ramp_step_samples = INVALID;
 | 
				
			||||||
				p->volume_ramp_enabled = true;
 | 
									p->volume_ramp_enabled = true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
| 
						 | 
					@ -2316,7 +2361,7 @@ static void handle_wav(struct impl *this, const void **src, uint32_t n_samples)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int channelmix_process_apply_sequence (struct impl *this,
 | 
					static int channelmix_process_apply_sequence(struct impl *this,
 | 
				
			||||||
			const struct spa_pod_sequence *sequence, uint32_t *processed_offset,
 | 
								const struct spa_pod_sequence *sequence, uint32_t *processed_offset,
 | 
				
			||||||
			void *SPA_RESTRICT dst[], const void *SPA_RESTRICT src[],
 | 
								void *SPA_RESTRICT dst[], const void *SPA_RESTRICT src[],
 | 
				
			||||||
			uint32_t n_samples)
 | 
								uint32_t n_samples)
 | 
				
			||||||
| 
						 | 
					@ -2754,13 +2799,13 @@ static int impl_node_process(void *object)
 | 
				
			||||||
		spa_log_trace_fp(this->log, "%p: channelmix %d %d %d", this, n_samples,
 | 
							spa_log_trace_fp(this->log, "%p: channelmix %d %d %d", this, n_samples,
 | 
				
			||||||
				resample_passthrough, out_passthrough);
 | 
									resample_passthrough, out_passthrough);
 | 
				
			||||||
		if (ctrlport != NULL && ctrlport->ctrl != NULL) {
 | 
							if (ctrlport != NULL && ctrlport->ctrl != NULL) {
 | 
				
			||||||
			if (channelmix_process_apply_sequence (this, ctrlport->ctrl,
 | 
								if (channelmix_process_apply_sequence(this, ctrlport->ctrl,
 | 
				
			||||||
						&ctrlport->ctrl_offset, out_datas, in_datas, n_samples) == 1) {
 | 
											&ctrlport->ctrl_offset, out_datas, in_datas, n_samples) == 1) {
 | 
				
			||||||
				ctrlio->status = SPA_STATUS_OK;
 | 
									ctrlio->status = SPA_STATUS_OK;
 | 
				
			||||||
				ctrlport->ctrl = NULL;
 | 
									ctrlport->ctrl = NULL;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if (this->vol_ramp_sequence) {
 | 
							} else if (this->vol_ramp_sequence) {
 | 
				
			||||||
			if (channelmix_process_apply_sequence (this, this->vol_ramp_sequence,
 | 
								if (channelmix_process_apply_sequence(this, this->vol_ramp_sequence,
 | 
				
			||||||
					&this->vol_ramp_offset, out_datas, in_datas, n_samples) == 1) {
 | 
										&this->vol_ramp_offset, out_datas, in_datas, n_samples) == 1) {
 | 
				
			||||||
				this->vol_ramp_sequence = NULL;
 | 
									this->vol_ramp_sequence = NULL;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue