File: lv2api.c

package info (click to toggle)
naspro-bridges 0.5.1-2
  • links: PTS
  • area: main
  • in suites: buster, stretch
  • size: 2,372 kB
  • ctags: 217
  • sloc: sh: 11,337; ansic: 1,270; makefile: 45
file content (229 lines) | stat: -rw-r--r-- 4,856 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/*
 * NASPRO - The NASPRO Architecture for Sound PROcessing
 * A collection of bridges to LV2
 * DSSI bridge
 *
 * Copyright (C) 2007-2014 Stefano D'Angelo
 *
 * See the COPYING file for license conditions.
 */

#include "internal.h"

/* libdssialsacompat has this one commented out */
void snd_midi_event_init(snd_midi_event_t *dev);

/* Taken from ALSA */
#define MAX_MIDI_EVENT_BUF	256

#define MAX_MIDI_EVENTS		4096

typedef struct
  {
	LADSPA_Handle		 handle;
	DSSI_Descriptor		*descriptor;
	LV2_URID		 urid_midi;
	LV2_Atom_Sequence	*atom_seq;
	snd_midi_event_t	*alsa_ev_parser;
	snd_seq_event_t		 alsa_ev_buf[MAX_MIDI_EVENTS];
  } instance_t;

static LV2_Handle
instantiate(const LV2_Descriptor *descriptor, double sample_rate,
	    const char *bundle_path, const LV2_Feature * const *features)
{
	instance_t *ret;
	DSSI_Descriptor *ddesc;
	LV2_URID_Map *map;
	size_t i;

	ddesc = nabrit_plugin_get_opaque(
			nabrit_plugin_from_descriptor(descriptor));

	ret = malloc(sizeof(instance_t));
	if (ret == NULL)
		return NULL;

	if (ddesc->run_synth != NULL)
	  {
		map = NULL;
		for (i = 0; features[i] != NULL; i++)
		  {
			if (strcmp(features[i]->URI, LV2_URID__map) == 0)
				map = features[i]->data;
		  }

		ret->urid_midi = map->map(map->handle, LV2_MIDI__MidiEvent);
		if (ret->urid_midi == 0)
		  {
			free(ret);
			return NULL;
		  }

		if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &ret->alsa_ev_parser)
		    < 0)
		  {
			free(ret);
			return NULL;
		  }
		snd_midi_event_init(ret->alsa_ev_parser);
	  }
	else
		ret->alsa_ev_parser = NULL;

	ret->descriptor = ddesc;
	ret->handle = ddesc->LADSPA_Plugin->instantiate(ddesc->LADSPA_Plugin,
							sample_rate);
	if (ret->handle == NULL)
	  {
		free(ret);
		return NULL;
	  }

	return (LV2_Handle)ret;
}

static void
connect_port(LV2_Handle instance, uint32_t port, void *data_location)
{
	instance_t *i;

	/* This is needed to avoid a little incompatibility beetween LADSPA and
	   LV2. LADSPA's connect_port() does not specify whether data_location
	   is valid at the time it is being run, while LV2 mandates the plugin
	   not to trust the memory location indicated by the pointer at the time
	   connect_port() is run. */
	if (data_location == NULL)
		return;

	i = (instance_t *)instance;

	if (port == i->descriptor->LADSPA_Plugin->PortCount)
		i->atom_seq = (LV2_Atom_Sequence *)data_location;
	else
		i->descriptor->LADSPA_Plugin->connect_port(i->handle, port,
							   data_location);
}

static void
activate(LV2_Handle instance)
{
	instance_t *i;

	i = (instance_t *)instance;

	i->descriptor->LADSPA_Plugin->activate(i->handle);
}

static void
run(LV2_Handle instance, uint32_t sample_count)
{
	instance_t *i;

	i = (instance_t *)instance;

	i->descriptor->LADSPA_Plugin->run(i->handle, sample_count);
}

static void
deactivate(LV2_Handle instance)
{
	instance_t *i;

	i = (instance_t *)instance;

	i->descriptor->LADSPA_Plugin->deactivate(i->handle);
}

static void
cleanup(LV2_Handle instance)
{
	instance_t *i;

	i = (instance_t *)instance;

	if (i->alsa_ev_parser != NULL)
		snd_midi_event_free(i->alsa_ev_parser);

	i->descriptor->LADSPA_Plugin->cleanup(i->handle);

	free(i);
}

NACORE_PRIVATE LV2_Descriptor stub_desc =
  {
	/* .URI			= */ NULL,
	/* .instantiate		= */ instantiate,
	/* .connect_port	= */ connect_port,
	/* .activate		= */ activate,
	/* .run			= */ run,
	/* .deactivate		= */ deactivate,
	/* .cleanup		= */ cleanup,
	/* .extension_data	= */ NULL
  };

static int
cmp_stamp(const void *v1, const void *v2)
{
	snd_seq_event_t *e1, *e2;

	e1 = (snd_seq_event_t *)v1;
	e2 = (snd_seq_event_t *)v2;

	return ((e1->time.tick < e2->time.tick)
		? -1 : ((e1->time.tick > e2->time.tick) ? 1 : 0));
}

NACORE_PRIVATE void
run_synth(LV2_Handle instance, uint32_t sample_count)
{
	instance_t *i;
	snd_seq_event_t *alsa_ev;
	snd_seq_event_t alsa_tmp_ev;
	unsigned char *data;
	unsigned long count;

	i = (instance_t *)instance;

	/* Convert MIDI events to ALSA Sequencer events */
	alsa_ev = i->alsa_ev_buf;
	count = 0;
	LV2_ATOM_SEQUENCE_FOREACH(i->atom_seq, ev)
	  {
		if (ev->body.type != i->urid_midi)
			continue;

		data = LV2_ATOM_BODY(&ev->body);

		if (snd_midi_event_encode(i->alsa_ev_parser, data,
					  ev->body.size, &alsa_tmp_ev) < 0)
		  {
			snd_midi_event_reset_encode(i->alsa_ev_parser);
			continue;
		  }

		if ((alsa_tmp_ev.type == SND_SEQ_EVENT_CONTROLLER)
		    || (alsa_tmp_ev.type == SND_SEQ_EVENT_PGMCHANGE))
			continue;

		alsa_tmp_ev.time.tick = ev->time.frames;
		*alsa_ev = alsa_tmp_ev;

		alsa_ev++;
		count++;
	  }

	/* Order events by timestamp */
	if (count > 1)
		qsort(i->alsa_ev_buf, count, sizeof(snd_seq_event_t),
		      cmp_stamp);

	i->descriptor->run_synth(i->handle, sample_count, i->alsa_ev_buf,
				 count);
}

API const LV2_Descriptor *
lv2_descriptor(uint32_t index)
{
	return nabrit_bridge_get_descriptor(bridge, index);
}