mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	jack: use buffers for midi
Place the midi in application/control buffers instead of control IO.
This commit is contained in:
		
							parent
							
								
									1d2db89b9c
								
							
						
					
					
						commit
						cd2c8ceb31
					
				
					 1 changed files with 118 additions and 102 deletions
				
			
		| 
						 | 
				
			
			@ -164,10 +164,6 @@ struct mix {
 | 
			
		|||
	struct port *port;
 | 
			
		||||
 | 
			
		||||
	struct spa_io_buffers *io;
 | 
			
		||||
	struct spa_io_sequence *notify;
 | 
			
		||||
	size_t notify_size;
 | 
			
		||||
	struct spa_io_sequence *control;
 | 
			
		||||
	size_t control_size;
 | 
			
		||||
 | 
			
		||||
	struct buffer buffers[MAX_BUFFERS];
 | 
			
		||||
	uint32_t n_buffers;
 | 
			
		||||
| 
						 | 
				
			
			@ -184,6 +180,7 @@ struct port {
 | 
			
		|||
	uint32_t id;
 | 
			
		||||
	struct object *object;
 | 
			
		||||
 | 
			
		||||
	struct spa_io_buffers io;
 | 
			
		||||
	struct spa_list mix;
 | 
			
		||||
 | 
			
		||||
	bool have_format;
 | 
			
		||||
| 
						 | 
				
			
			@ -661,8 +658,6 @@ static void convert_to_midi(struct spa_pod_sequence *seq, void *midi)
 | 
			
		|||
{
 | 
			
		||||
	struct spa_pod_control *c;
 | 
			
		||||
 | 
			
		||||
	jack_midi_reset_buffer(midi);
 | 
			
		||||
 | 
			
		||||
	SPA_POD_SEQUENCE_FOREACH(seq, c) {
 | 
			
		||||
		switch(c->type) {
 | 
			
		||||
		case SPA_CONTROL_Midi:
 | 
			
		||||
| 
						 | 
				
			
			@ -675,18 +670,57 @@ static void convert_to_midi(struct spa_pod_sequence *seq, void *midi)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *get_buffer_output(struct client *c, struct port *p, uint32_t frames, uint32_t stride)
 | 
			
		||||
{
 | 
			
		||||
	struct mix *mix;
 | 
			
		||||
	void *ptr = NULL;
 | 
			
		||||
 | 
			
		||||
	p->io.status = -EPIPE;
 | 
			
		||||
	p->io.buffer_id = SPA_ID_INVALID;
 | 
			
		||||
 | 
			
		||||
	if ((mix = find_mix(c, p, -1)) != NULL) {
 | 
			
		||||
		struct buffer *b;
 | 
			
		||||
 | 
			
		||||
		pw_log_trace(NAME" %p: port %p %d get buffer %d n_buffers:%d",
 | 
			
		||||
				c, p, p->id, frames, mix->n_buffers);
 | 
			
		||||
 | 
			
		||||
		if ((b = dequeue_buffer(mix)) == NULL) {
 | 
			
		||||
			pw_log_warn("port %p: out of buffers", p);
 | 
			
		||||
			goto done;
 | 
			
		||||
		}
 | 
			
		||||
		reuse_buffer(c, mix, b->id);
 | 
			
		||||
		ptr = b->datas[0].data;
 | 
			
		||||
 | 
			
		||||
		b->datas[0].chunk->offset = 0;
 | 
			
		||||
		b->datas[0].chunk->size = frames * stride;
 | 
			
		||||
		b->datas[0].chunk->stride = stride;
 | 
			
		||||
 | 
			
		||||
		p->io.status = SPA_STATUS_HAVE_DATA;
 | 
			
		||||
		p->io.buffer_id = b->id;
 | 
			
		||||
	}
 | 
			
		||||
done:
 | 
			
		||||
	spa_list_for_each(mix, &p->mix, port_link) {
 | 
			
		||||
		struct spa_io_buffers *mio = mix->io;
 | 
			
		||||
		if (mio == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
		pw_log_trace(NAME" %p: port %p tee %d.%d get buffer %d io:%p",
 | 
			
		||||
				c, p, p->id, mix->id, frames, mio);
 | 
			
		||||
		*mio = p->io;
 | 
			
		||||
	}
 | 
			
		||||
	return ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void process_tee(struct client *c)
 | 
			
		||||
{
 | 
			
		||||
	struct port *p;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	spa_list_for_each(p, &c->ports[SPA_DIRECTION_OUTPUT], link) {
 | 
			
		||||
		struct mix *mix;
 | 
			
		||||
		spa_list_for_each(mix, &p->mix, port_link) {
 | 
			
		||||
			if (mix->notify == NULL)
 | 
			
		||||
				continue;
 | 
			
		||||
			convert_from_midi(p->emptyptr, mix->notify, mix->notify_size);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		if (p->object->port.type_id != 1)
 | 
			
		||||
			continue;
 | 
			
		||||
		void *ptr = get_buffer_output(c, p, BUFFER_SIZE_MAX, 1);
 | 
			
		||||
		if (ptr != NULL)
 | 
			
		||||
			convert_from_midi(p->emptyptr, ptr, BUFFER_SIZE_MAX);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1199,8 +1233,8 @@ static int param_enum_format(struct client *c, struct port *p,
 | 
			
		|||
	case 1:
 | 
			
		||||
		*param = spa_pod_builder_add_object(b,
 | 
			
		||||
			SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
 | 
			
		||||
			SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_stream),
 | 
			
		||||
			SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_midi));
 | 
			
		||||
			SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_application),
 | 
			
		||||
			SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1236,8 +1270,8 @@ static int param_format(struct client *c, struct port *p,
 | 
			
		|||
	case 1:
 | 
			
		||||
		*param = spa_pod_builder_add_object(b,
 | 
			
		||||
			SPA_TYPE_OBJECT_Format, SPA_PARAM_Format,
 | 
			
		||||
			SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_stream),
 | 
			
		||||
			SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_midi));
 | 
			
		||||
			SPA_FORMAT_mediaType,      SPA_POD_Id(SPA_MEDIA_TYPE_application),
 | 
			
		||||
			SPA_FORMAT_mediaSubtype,   SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1261,27 +1295,10 @@ static int param_buffers(struct client *c, struct port *p,
 | 
			
		|||
static int param_io(struct client *c, struct port *p,
 | 
			
		||||
		struct spa_pod **param, struct spa_pod_builder *b)
 | 
			
		||||
{
 | 
			
		||||
	switch (p->object->port.type_id) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		*param = spa_pod_builder_add_object(b,
 | 
			
		||||
			SPA_TYPE_OBJECT_ParamIO, SPA_PARAM_IO,
 | 
			
		||||
			SPA_PARAM_IO_id,	SPA_POD_Id(SPA_IO_Buffers),
 | 
			
		||||
			SPA_PARAM_IO_size,	SPA_POD_Int(sizeof(struct spa_io_buffers)));
 | 
			
		||||
		break;
 | 
			
		||||
	case 1:
 | 
			
		||||
		if (p->direction == SPA_DIRECTION_OUTPUT) {
 | 
			
		||||
			*param = spa_pod_builder_add_object(b,
 | 
			
		||||
				SPA_TYPE_OBJECT_ParamIO, SPA_PARAM_IO,
 | 
			
		||||
				SPA_PARAM_IO_id,	SPA_POD_Id(SPA_IO_Notify),
 | 
			
		||||
				SPA_PARAM_IO_size,	SPA_POD_Int(BUFFER_SIZE_MAX));
 | 
			
		||||
		} else {
 | 
			
		||||
			*param = spa_pod_builder_add_object(b,
 | 
			
		||||
				SPA_TYPE_OBJECT_ParamIO, SPA_PARAM_IO,
 | 
			
		||||
				SPA_PARAM_IO_id,	SPA_POD_Id(SPA_IO_Control),
 | 
			
		||||
				SPA_PARAM_IO_size,	SPA_POD_Int(sizeof(struct spa_io_sequence)));
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	*param = spa_pod_builder_add_object(b,
 | 
			
		||||
		SPA_TYPE_OBJECT_ParamIO, SPA_PARAM_IO,
 | 
			
		||||
		SPA_PARAM_IO_id,	SPA_POD_Id(SPA_IO_Buffers),
 | 
			
		||||
		SPA_PARAM_IO_size,	SPA_POD_Int(sizeof(struct spa_io_buffers)));
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1313,7 +1330,9 @@ static int port_set_format(struct client *c, struct port *p,
 | 
			
		|||
			p->rate = info.info.raw.rate;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SPA_MEDIA_TYPE_stream:
 | 
			
		||||
		case SPA_MEDIA_TYPE_application:
 | 
			
		||||
			if (info.media_subtype != SPA_MEDIA_SUBTYPE_control)
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
| 
						 | 
				
			
			@ -1486,11 +1505,12 @@ static int client_node_port_use_buffers(void *object,
 | 
			
		|||
						d->data, d->maxsize);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		init_buffer(p, p->emptyptr, BUFFER_SIZE_MAX);
 | 
			
		||||
		p->zeroed = true;
 | 
			
		||||
 | 
			
		||||
		SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT);
 | 
			
		||||
		if (direction == SPA_DIRECTION_OUTPUT) {
 | 
			
		||||
			init_buffer(p, b->datas[0].data, b->datas[0].maxsize);
 | 
			
		||||
		if (direction == SPA_DIRECTION_OUTPUT)
 | 
			
		||||
			reuse_buffer(c, mix, b->id);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	pw_log_debug(NAME" %p: have %d buffers", c, n_buffers);
 | 
			
		||||
| 
						 | 
				
			
			@ -1550,14 +1570,6 @@ static int client_node_port_set_io(void *object,
 | 
			
		|||
	case SPA_IO_Buffers:
 | 
			
		||||
                mix->io = ptr;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPA_IO_Notify:
 | 
			
		||||
                mix->notify = ptr;
 | 
			
		||||
                mix->notify_size = size;
 | 
			
		||||
		break;
 | 
			
		||||
	case SPA_IO_Control:
 | 
			
		||||
                mix->control = ptr;
 | 
			
		||||
                mix->control_size = size;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1728,11 +1740,9 @@ static void registry_event_global(void *data, uint32_t id,
 | 
			
		|||
 | 
			
		||||
		spa_dict_for_each(item, props) {
 | 
			
		||||
	                if (!strcmp(item->key, PW_KEY_PORT_DIRECTION)) {
 | 
			
		||||
				if (strcmp(item->value, "in") == 0 ||
 | 
			
		||||
				    strcmp(item->value, "control") == 0)
 | 
			
		||||
				if (strcmp(item->value, "in") == 0)
 | 
			
		||||
					flags |= JackPortIsInput;
 | 
			
		||||
				else if (strcmp(item->value, "out") == 0 ||
 | 
			
		||||
				    strcmp(item->value, "notify") == 0)
 | 
			
		||||
				else if (strcmp(item->value, "out") == 0)
 | 
			
		||||
					flags |= JackPortIsOutput;
 | 
			
		||||
			}
 | 
			
		||||
			else if (!strcmp(item->key, PW_KEY_PORT_PHYSICAL)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2739,30 +2749,62 @@ static void *mix_audio(struct client *c, struct port *p, jack_nframes_t frames)
 | 
			
		|||
static void *mix_midi(struct client *c, struct port *p, jack_nframes_t frames)
 | 
			
		||||
{
 | 
			
		||||
	struct mix *mix;
 | 
			
		||||
	struct spa_io_sequence *io;
 | 
			
		||||
	void *ptr = NULL;
 | 
			
		||||
	struct buffer *b;
 | 
			
		||||
	struct spa_io_buffers *io;
 | 
			
		||||
	void *ptr = p->emptyptr;
 | 
			
		||||
 | 
			
		||||
	jack_midi_reset_buffer(ptr);
 | 
			
		||||
 | 
			
		||||
	spa_list_for_each(mix, &p->mix, port_link) {
 | 
			
		||||
		pw_log_trace(NAME" %p: port %p mix %d.%d get buffer %d",
 | 
			
		||||
				c, p, p->id, mix->id, frames);
 | 
			
		||||
		io = mix->control;
 | 
			
		||||
		if (io == NULL)
 | 
			
		||||
 | 
			
		||||
		io = mix->io;
 | 
			
		||||
		if (io == NULL || io->buffer_id >= mix->n_buffers)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		ptr = p->emptyptr;
 | 
			
		||||
		convert_to_midi(&io->sequence, ptr);
 | 
			
		||||
		io->status = SPA_STATUS_NEED_DATA;
 | 
			
		||||
		b = &mix->buffers[io->buffer_id];
 | 
			
		||||
		/* FIXME, actually mix the midi */
 | 
			
		||||
		convert_to_midi(b->datas[0].data, ptr);
 | 
			
		||||
		p->zeroed = false;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void *get_buffer_input_float(struct client *c, struct port *p, jack_nframes_t frames)
 | 
			
		||||
{
 | 
			
		||||
	return mix_audio(c, p, frames);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void *get_buffer_input_midi(struct client *c, struct port *p, jack_nframes_t frames)
 | 
			
		||||
{
 | 
			
		||||
	return mix_midi(c, p, frames);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void *get_buffer_output_float(struct client *c, struct port *p, jack_nframes_t frames)
 | 
			
		||||
{
 | 
			
		||||
	void *ptr;
 | 
			
		||||
 | 
			
		||||
	ptr = get_buffer_output(c, p, frames, sizeof(float));
 | 
			
		||||
	if (ptr == NULL)
 | 
			
		||||
		ptr = p->emptyptr;
 | 
			
		||||
 | 
			
		||||
	return ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void *get_buffer_output_midi(struct client *c, struct port *p, jack_nframes_t frames)
 | 
			
		||||
{
 | 
			
		||||
	return p->emptyptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames)
 | 
			
		||||
{
 | 
			
		||||
	struct object *o = (struct object *) port;
 | 
			
		||||
	struct client *c;
 | 
			
		||||
	struct port *p;
 | 
			
		||||
	struct mix *mix;
 | 
			
		||||
	void *ptr = NULL;
 | 
			
		||||
 | 
			
		||||
	if (o == NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -2779,56 +2821,30 @@ void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames)
 | 
			
		|||
	if (p->direction == SPA_DIRECTION_INPUT) {
 | 
			
		||||
		switch (p->object->port.type_id) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			ptr = mix_audio(c, p, frames);
 | 
			
		||||
			ptr = get_buffer_input_float(c, p, frames);
 | 
			
		||||
			break;
 | 
			
		||||
		case 1:
 | 
			
		||||
			ptr = mix_midi(c, p, frames);
 | 
			
		||||
			ptr = get_buffer_input_midi(c, p, frames);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		struct spa_io_buffers io;
 | 
			
		||||
 | 
			
		||||
		io.status = -EPIPE;
 | 
			
		||||
		io.buffer_id = SPA_ID_INVALID;
 | 
			
		||||
 | 
			
		||||
		if ((mix = find_mix(c, p, -1)) != NULL) {
 | 
			
		||||
			struct buffer *b;
 | 
			
		||||
 | 
			
		||||
			pw_log_trace(NAME" %p: port %p %d get buffer %d n_buffers:%d",
 | 
			
		||||
					c, p, p->id, frames, mix->n_buffers);
 | 
			
		||||
 | 
			
		||||
			if ((b = dequeue_buffer(mix)) == NULL) {
 | 
			
		||||
				pw_log_warn("port %p: out of buffers", p);
 | 
			
		||||
				goto done;
 | 
			
		||||
		if (ptr == NULL) {
 | 
			
		||||
			ptr = p->emptyptr;
 | 
			
		||||
			if (!p->zeroed) {
 | 
			
		||||
				init_buffer(p, ptr, BUFFER_SIZE_MAX * sizeof(float));
 | 
			
		||||
				p->zeroed = true;
 | 
			
		||||
			}
 | 
			
		||||
			reuse_buffer(c, mix, b->id);
 | 
			
		||||
			ptr = b->datas[0].data;
 | 
			
		||||
 | 
			
		||||
			b->datas[0].chunk->offset = 0;
 | 
			
		||||
			b->datas[0].chunk->size = frames * sizeof(float);
 | 
			
		||||
			b->datas[0].chunk->stride = sizeof(float);
 | 
			
		||||
 | 
			
		||||
			io.status = SPA_STATUS_HAVE_DATA;
 | 
			
		||||
			io.buffer_id = b->id;
 | 
			
		||||
		}
 | 
			
		||||
      done:
 | 
			
		||||
		spa_list_for_each(mix, &p->mix, port_link) {
 | 
			
		||||
			struct spa_io_buffers *mio = mix->io;
 | 
			
		||||
			if (mio == NULL)
 | 
			
		||||
				continue;
 | 
			
		||||
			pw_log_trace(NAME" %p: port %p tee %d.%d get buffer %d io:%p",
 | 
			
		||||
					c, p, p->id, mix->id, frames, mio);
 | 
			
		||||
			*mio = io;
 | 
			
		||||
	} else {
 | 
			
		||||
		switch (p->object->port.type_id) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			ptr = get_buffer_output_float(c, p, frames);
 | 
			
		||||
			break;
 | 
			
		||||
		case 1:
 | 
			
		||||
			ptr = get_buffer_output_midi(c, p, frames);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ptr == NULL) {
 | 
			
		||||
		ptr = p->emptyptr;
 | 
			
		||||
		if (!p->zeroed) {
 | 
			
		||||
			init_buffer(p, ptr, BUFFER_SIZE_MAX * sizeof(float));
 | 
			
		||||
			p->zeroed = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	pw_log_trace(NAME" %p: port %p buffer %p", c, p, ptr);
 | 
			
		||||
	return ptr;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue