1 /*
2  * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
3  *
4  * This is free software: you can redistribute it and/or modify
5  * it under the terms of the Artistic License 2.0 as published by
6  * The Perl Foundation.
7  *
8  * This source is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * Artistic License 2.0 for more details.
12  *
13  * You should have received a copy of the Artistic License 2.0
14  * along the source as a COPYING file. If not, obtain it from
15  * http://www.perlfoundation.org/artistic_license_2_0.
16  */
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <math.h>
21 
22 #include <orbit.h>
23 #include <timely.h>
24 #include <props.h>
25 
26 #define MAX_NPROPS 7
27 
28 #define BUF_SIZE 0x1000000 // 16 MB
29 #define BUF_PERCENT (100.f / (BUF_SIZE - sizeof(LV2_Atom)))
30 
31 typedef enum _punchmode_t punchmode_t;
32 typedef struct _plugstate_t plugstate_t;
33 typedef struct _plughandle_t plughandle_t;
34 
35 enum _punchmode_t {
36 	PUNCH_BEAT				= 0,
37 	PUNCH_BAR					= 1
38 };
39 
40 struct _plugstate_t {
41 	int32_t punch;
42 	int32_t width;
43 	int32_t mute;
44 	int32_t switsch;
45 
46 	int32_t play_capacity;
47 	int32_t rec_capacity;
48 	int32_t position;
49 };
50 
51 struct _plughandle_t {
52 	LV2_URID_Map *map;
53 	LV2_Atom_Forge forge;
54 	LV2_Atom_Forge_Ref ref;
55 
56 	struct {
57 		LV2_URID play_capacity;
58 		LV2_URID rec_capacity;
59 		LV2_URID position;
60 		LV2_URID beat_time;
61 	} urid;
62 
63 	timely_t timely;
64 
65 	plugstate_t state;
66 	plugstate_t stash;
67 
68 	const LV2_Atom_Sequence *event_in;
69 	LV2_Atom_Sequence *event_out;
70 
71 	float window;
72 	int64_t offset;
73 	int64_t last;
74 
75 	PROPS_T(props, MAX_NPROPS);
76 
77 	unsigned play;
78 	bool rolling;
79 	bool mute;
80 	uint8_t buf [2][BUF_SIZE];
81 
82 	LV2_Atom_Event *play_ev_next;
83 	LV2_Atom_Event *play_ev_prev;
_seq_spin_lock(plughandle_t * handle)84 
85 	LV2_Atom_Event *rec_ev_next;
86 	LV2_Atom_Event *rec_ev_prev;
87 };
88 
89 static inline void
90 _window_refresh(plughandle_t *handle)
91 {
92 	timely_t *timely = &handle->timely;
_seq_try_lock(plughandle_t * handle)93 
94 	if(handle->state.punch == PUNCH_BEAT)
95 		handle->window = 100.f / (handle->state.width * TIMELY_FRAMES_PER_BEAT(timely));
96 	else if(handle->state.punch == PUNCH_BAR)
97 		handle->window = 100.f / (handle->state.width * TIMELY_FRAMES_PER_BAR(timely));
98 }
_seq_unlock(plughandle_t * handle)99 
100 static void
101 _intercept(void *data, int64_t frames, props_impl_t *impl)
102 {
103 	plughandle_t *handle = data;
104 
105 	_window_refresh(handle);
106 }
107 
108 static const props_def_t defs [MAX_NPROPS] = {
109 	{
110 		.property = ORBIT_URI"#looper_punch",
111 		.offset = offsetof(plugstate_t, punch),
112 		.type = LV2_ATOM__Int,
113 		.event_cb = _intercept
114 	},
115 	{
116 		.property = ORBIT_URI"#looper_width",
117 		.offset = offsetof(plugstate_t, width),
118 		.type = LV2_ATOM__Int,
119 		.event_cb = _intercept
120 	},
121 	{
122 		.property = ORBIT_URI"#looper_mute",
123 		.offset = offsetof(plugstate_t, mute),
_request(plughandle_t * handle,int32_t size)124 		.type = LV2_ATOM__Bool,
125 	},
126 	{
127 		.property = ORBIT_URI"#looper_switch",
128 		.offset = offsetof(plugstate_t, switsch),
129 		.type = LV2_ATOM__Bool,
130 	},
131 	{
132 		.property = ORBIT_URI"#looper_play_capacity",
133 		.offset = offsetof(plugstate_t, play_capacity),
134 		.access = LV2_PATCH__readable,
135 		.type = LV2_ATOM__Int,
136 	},
137 	{
138 		.property = ORBIT_URI"#looper_rec_capacity",
139 		.offset = offsetof(plugstate_t, rec_capacity),
140 		.access = LV2_PATCH__readable,
_play(plughandle_t * handle,int64_t to,uint32_t capacity)141 		.type = LV2_ATOM__Int,
142 	},
143 	{
144 		.property = ORBIT_URI"#looper_position",
145 		.offset = offsetof(plugstate_t, position),
146 		.access = LV2_PATCH__readable,
147 		.type = LV2_ATOM__Int,
148 	}
149 };
150 
151 #define LV2_ATOM_SEQUENCE_FOREACH_FROM(seq, from, iter) \
152 	for (LV2_Atom_Event* (iter) = (from); \
153 	     !lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \
154 	     (iter) = lv2_atom_sequence_next(iter))
155 
156 static inline void
157 _play(plughandle_t *handle, int64_t to, uint32_t capacity)
158 {
159 	const LV2_Atom_Sequence *play_seq = (LV2_Atom_Sequence *)handle->buf[handle->play];
160 
161 	const int64_t rel = handle->offset - to; // beginning of current period
162 
163 	if(handle->play_ev_next)
164 	{
165 		LV2_ATOM_SEQUENCE_FOREACH_FROM(play_seq, handle->play_ev_next, ev)
166 		{
167 			const int64_t beat_frames = ev->time.beats * TIMELY_FRAMES_PER_BEAT(&handle->timely);
168 
169 			if(beat_frames >= handle->offset)
170 				break; // event not part of this period
171 
172 			const int64_t frames = beat_frames - rel;
173 
174 			// check for time jump! skip out-of-order event, as it probably has already been forged...
175 			if(frames >= handle->last) //TODO can this be solved more elegantly?
_rec(plughandle_t * handle,const LV2_Atom_Event * ev)176 			{
177 				// append event
178 				const LV2_Atom *atom = &ev->body;
179 				if(handle->ref)
180 					handle->ref = lv2_atom_forge_frame_time(&handle->forge, frames);
181 				if(handle->ref)
182 					handle->ref = lv2_atom_forge_write(&handle->forge, atom, lv2_atom_total_size(atom));
183 
184 				handle->last = frames; // advance frame time head
185 			}
186 
187 			handle->play_ev_prev = ev;
188 			handle->play_ev_next = lv2_atom_sequence_next(ev);
189 		}
190 	}
191 }
192 
193 static inline void
194 _rec(plughandle_t *handle, const LV2_Atom_Event *ev)
195 {
196 	LV2_Atom_Sequence *rec_seq = (LV2_Atom_Sequence *)handle->buf[!handle->play];
197 
198 	LV2_Atom_Event *e = lv2_atom_sequence_append_event(rec_seq, BUF_SIZE, ev);
199 	if(e)
200 	{
201 		e->time.beats = handle->offset / TIMELY_FRAMES_PER_BEAT(&handle->timely);
202 
203 		handle->rec_ev_prev = handle->rec_ev_next;
204 		handle->rec_ev_next = e;
205 	}
206 	else
207 	{
208 		// overflow
209 	}
210 }
211 
212 static inline void
213 _reposition_play(plughandle_t *handle)
214 {
215 	LV2_Atom_Sequence *play_seq = (LV2_Atom_Sequence *)handle->buf[handle->play];
216 	LV2_Atom_Event *from = lv2_atom_sequence_begin(&play_seq->body);
217 
218 	if(handle->play_ev_prev && handle->play_ev_next)
_reposition_play(plughandle_t * handle)219 	{
220 		const int64_t beat_frames = handle->play_ev_prev->time.beats * TIMELY_FRAMES_PER_BEAT(&handle->timely);
221 
222 		if(beat_frames < handle->offset)
223 			from = handle->play_ev_prev; // search from here, not beginning
224 		else
225 			;//printf("play not positioned\n");
226 	}
227 
228 	LV2_ATOM_SEQUENCE_FOREACH_FROM(play_seq, from, ev)
229 	{
230 		const int64_t beat_frames = ev->time.beats * TIMELY_FRAMES_PER_BEAT(&handle->timely);
231 
232 		if(beat_frames >= handle->offset)
233 		{
234 			// reposition here
235 			handle->play_ev_prev = handle->play_ev_next;
236 			handle->play_ev_next = ev;
237 
238 			return;
_reposition_rec(plughandle_t * handle)239 		}
240 	}
241 
242 	//printf("play null\n");
243 	handle->play_ev_prev = NULL;
244 	handle->play_ev_next = NULL;
245 }
246 
247 static inline void
248 _reposition_rec(plughandle_t *handle)
249 {
250 	LV2_Atom_Sequence *rec_seq = (LV2_Atom_Sequence *)handle->buf[!handle->play];
251 	LV2_Atom_Event *from = lv2_atom_sequence_begin(&rec_seq->body);
252 
253 	if(handle->rec_ev_prev && handle->rec_ev_next)
254 	{
255 		const int64_t beat_frames = handle->rec_ev_prev->time.beats * TIMELY_FRAMES_PER_BEAT(&handle->timely);
256 
_cb(timely_t * timely,int64_t frames,LV2_URID type,void * data)257 		if(beat_frames < handle->offset)
258 			from = handle->rec_ev_prev; // search from here, not beginning
259 		else
260 			;//printf("rec not positioned\n");
261 	}
262 
263 	LV2_ATOM_SEQUENCE_FOREACH_FROM(rec_seq, from, ev)
264 	{
265 		const int64_t beat_frames = ev->time.beats * TIMELY_FRAMES_PER_BEAT(&handle->timely);
266 
267 		if(beat_frames >= handle->offset)
268 		{
269 			handle->rec_ev_prev = handle->rec_ev_next; //FIXME check
270 			handle->rec_ev_next = ev; //FIXME check
271 
272 			// truncate sequence here
273 			rec_seq->atom.size = (uintptr_t)ev - (uintptr_t)&rec_seq->body;
274 
275 			return;
276 		}
277 	}
278 
279 	//printf("rec null\n");
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)280 	handle->rec_ev_prev = NULL;
281 	handle->rec_ev_next = NULL;
282 }
283 
284 static void
285 _cb(timely_t *timely, int64_t frames, LV2_URID type, void *data)
286 {
287 	plughandle_t *handle = data;
288 
289 	if(type == TIMELY_URI_SPEED(timely))
290 	{
291 		handle->rolling = TIMELY_SPEED(timely) > 0.f ? true : false;
292 	}
293 	else if(type == TIMELY_URI_BAR_BEAT(timely))
294 	{
295 		double beats = (double)TIMELY_BAR(timely) * TIMELY_BEATS_PER_BAR(timely)
296 			+ TIMELY_BAR_BEAT_RAW(timely);
297 
298 		if(handle->state.punch == PUNCH_BEAT)
299 			handle->offset = fmod(beats, handle->state.width) * TIMELY_FRAMES_PER_BEAT(timely);
300 		else if(handle->state.punch == PUNCH_BAR)
301 			handle->offset = fmod(beats, handle->state.width * TIMELY_BEATS_PER_BAR(timely))
302 				* TIMELY_FRAMES_PER_BEAT(timely);
303 
304 		if(handle->offset == 0)
305 		{
306 			if(handle->state.switsch)
307 				handle->play ^= 1;
308 
309 			handle->mute = handle->state.mute;
310 		}
311 
312 		if(beats == 0.0) // clear sequence buffers when transport is rewound
313 		{
314 			LV2_Atom_Sequence *play_seq = (LV2_Atom_Sequence *)handle->buf[handle->play];
315 			LV2_Atom_Sequence *rec_seq = (LV2_Atom_Sequence *)handle->buf[!handle->play];
316 
317 			lv2_atom_sequence_clear(play_seq);
318 			lv2_atom_sequence_clear(rec_seq);
319 		}
320 
321 		_reposition_rec(handle);
322 		_reposition_play(handle);
323 	}
324 
325 	_window_refresh(handle);
326 }
327 
328 static LV2_Handle
329 instantiate(const LV2_Descriptor* descriptor, double rate,
330 	const char *bundle_path, const LV2_Feature *const *features)
331 {
332 	plughandle_t *handle = calloc(1, sizeof(plughandle_t));
333 	if(!handle)
334 		return NULL;
335 	mlock(handle, sizeof(plughandle_t));
336 
337 	for(unsigned i=0; features[i]; i++)
338 	{
connect_port(LV2_Handle instance,uint32_t port,void * data)339 		if(!strcmp(features[i]->URI, LV2_URID__map))
340 			handle->map = features[i]->data;
341 	}
342 
343 	if(!handle->map)
344 	{
345 		fprintf(stderr,
346 			"%s: Host does not support urid:map\n", descriptor->URI);
347 		free(handle);
348 		return NULL;
349 	}
350 
351 	handle->urid.beat_time = handle->map->map(handle->map->handle, LV2_ATOM__beatTime);
352 
353 	timely_mask_t mask = TIMELY_MASK_BAR_BEAT
354 		//| TIMELY_MASK_BAR
355 		| TIMELY_MASK_BEAT_UNIT
356 		| TIMELY_MASK_BEATS_PER_BAR
activate(LV2_Handle instance)357 		| TIMELY_MASK_BEATS_PER_MINUTE
358 		| TIMELY_MASK_FRAMES_PER_SECOND
359 		| TIMELY_MASK_SPEED
360 		| TIMELY_MASK_BAR_BEAT_WHOLE;
361 	timely_init(&handle->timely, handle->map, rate, mask, _cb, handle);
362 	lv2_atom_forge_init(&handle->forge, handle->map);
363 
364 	if(!props_init(&handle->props, descriptor->URI,
365 		defs, MAX_NPROPS, &handle->state, &handle->stash,
366 		handle->map, handle))
367 	{
368 		fprintf(stderr, "failed to initialize property structure\n");
369 		free(handle);
370 		return NULL;
371 	}
372 
373 	handle->urid.play_capacity = props_map(&handle->props, ORBIT_URI"#looper_play_capacity");
374 	handle->urid.rec_capacity = props_map(&handle->props, ORBIT_URI"#looper_rec_capacity");
375 	handle->urid.position = props_map(&handle->props, ORBIT_URI"#looper_position");
376 
377 	return handle;
378 }
379 
380 static void
381 connect_port(LV2_Handle instance, uint32_t port, void *data)
382 {
run(LV2_Handle instance,uint32_t nsamples)383 	plughandle_t *handle = (plughandle_t *)instance;
384 
385 	switch(port)
386 	{
387 		case 0:
388 			handle->event_in = (const LV2_Atom_Sequence *)data;
389 			break;
390 		case 1:
391 			handle->event_out = (LV2_Atom_Sequence *)data;
392 			break;
393 		default:
394 			break;
395 	}
396 }
397 
398 static void
399 activate(LV2_Handle instance)
400 {
401 	plughandle_t *handle = instance;
402 
403 	handle->offset = 0.f;
404 	handle->play = 0;
405 	handle->mute = false;
406 	handle->rolling = false;
407 
408 	LV2_Atom_Sequence *play_seq = (LV2_Atom_Sequence *)handle->buf[handle->play];
409 	LV2_Atom_Sequence *rec_seq = (LV2_Atom_Sequence *)handle->buf[!handle->play];
410 
411 	play_seq->atom.type = handle->forge.Sequence;
412 	play_seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
413 	play_seq->body.unit = handle->urid.beat_time;
414 	play_seq->body.pad = 0;
415 
416 	rec_seq->atom.type = handle->forge.Sequence;
417 	rec_seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
418 	rec_seq->body.unit = handle->urid.beat_time;
419 	rec_seq->body.pad = 0;
420 }
421 
422 static void
423 run(LV2_Handle instance, uint32_t nsamples)
424 {
425 	plughandle_t *handle = instance;
426 
427 	handle->last = 0; // reset frame time head
428 
429 	const uint32_t capacity = handle->event_out->atom.size;
430 	LV2_Atom_Forge_Frame frame;
431 	lv2_atom_forge_set_buffer(&handle->forge, (uint8_t *)handle->event_out, capacity);
432 	handle->ref = lv2_atom_forge_sequence_head(&handle->forge, &frame, 0);
433 
434 	props_idle(&handle->props, &handle->forge, 0, &handle->ref);
435 
436 	int64_t last_t = 0;
437 	LV2_ATOM_SEQUENCE_FOREACH(handle->event_in, ev)
deactivate(LV2_Handle instance)438 	{
439 		if(handle->rolling)
440 			handle->offset += ev->time.frames - last_t;
441 
442 		const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
443 		int handled = timely_advance(&handle->timely, obj, last_t, ev->time.frames);
444 		if(!handled)
445 			handled = props_advance(&handle->props, &handle->forge, ev->time.frames, obj, &handle->ref);
446 
447 		if(!handled && handle->rolling)
448 			_rec(handle, ev); // dont' record time position signals and patch messages
449 
450 		if(!handle->mute && handle->rolling)
451 			_play(handle, ev->time.frames, capacity);
452 
453 		last_t = ev->time.frames;
454 	}
455 
456 	if(handle->rolling)
457 		handle->offset += nsamples - last_t;
_state_save(LV2_Handle instance,LV2_State_Store_Function store,LV2_State_Handle state,uint32_t flags,const LV2_Feature * const * features)458 	timely_advance(&handle->timely, NULL, last_t, nsamples);
459 	if(!handle->mute && handle->rolling)
460 		_play(handle, nsamples, capacity);
461 
462 	LV2_Atom_Sequence *play_seq = (LV2_Atom_Sequence *)handle->buf[handle->play];
463 	LV2_Atom_Sequence *rec_seq = (LV2_Atom_Sequence *)handle->buf[!handle->play];
464 
465 	const int32_t play_capacity = BUF_PERCENT * play_seq->atom.size;
466 	const int32_t rec_capacity = BUF_PERCENT * rec_seq->atom.size;
467 	const int32_t position = handle->offset * handle->window;
468 
469 	if(handle->ref && (play_capacity != handle->state.play_capacity) )
470 	{
471 		handle->state.play_capacity = play_capacity;
472 		props_set(&handle->props, &handle->forge, nsamples-1, handle->urid.play_capacity, &handle->ref);
_state_restore(LV2_Handle instance,LV2_State_Retrieve_Function retrieve,LV2_State_Handle state,uint32_t flags,const LV2_Feature * const * features)473 	}
474 	if(handle->ref && (rec_capacity != handle->state.rec_capacity) )
475 	{
476 		handle->state.rec_capacity = rec_capacity;
477 		props_set(&handle->props, &handle->forge, nsamples-1, handle->urid.rec_capacity, &handle->ref);
478 	}
479 	if(handle->ref && (position != handle->state.position) )
480 	{
481 		handle->state.position = position;
482 		props_set(&handle->props, &handle->forge, nsamples-1, handle->urid.position, &handle->ref);
483 	}
484 
485 	if(handle->ref)
486 		lv2_atom_forge_pop(&handle->forge, &frame);
487 	else
488 		lv2_atom_sequence_clear(handle->event_out);
489 }
490 
491 static void
492 cleanup(LV2_Handle instance)
493 {
494 	plughandle_t *handle = instance;
495 
496 	munlock(handle, sizeof(plughandle_t));
497 	free(handle);
498 }
499 
500 static LV2_State_Status
501 _state_save(LV2_Handle instance, LV2_State_Store_Function store,
502 	LV2_State_Handle state, uint32_t flags,
503 	const LV2_Feature *const *features)
504 {
505 	plughandle_t *handle = instance;
506 
507 	return props_save(&handle->props, store, state, flags, features);
508 }
509 
510 static LV2_State_Status
511 _state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
512 	LV2_State_Handle state, uint32_t flags,
513 	const LV2_Feature *const *features)
_work(LV2_Handle instance,LV2_Worker_Respond_Function respond,LV2_Worker_Respond_Handle worker,uint32_t size,const void * body)514 {
515 	plughandle_t *handle = instance;
516 
517 	return props_restore(&handle->props, retrieve, state, flags, features);
518 }
519 
520 static const LV2_State_Interface state_iface = {
521 	.save = _state_save,
522 	.restore = _state_restore
523 };
524 
525 static const void*
526 extension_data(const char* uri)
527 {
528 	if(!strcmp(uri, LV2_STATE__interface))
529 		return &state_iface;
530 
531 	return NULL;
532 }
533 
534 const LV2_Descriptor orbit_looper = {
535 	.URI						= ORBIT_LOOPER_URI,
536 	.instantiate		= instantiate,
537 	.connect_port		= connect_port,
538 	.activate				= activate,
539 	.run						= run,
540 	.deactivate			= NULL,
541 	.cleanup				= cleanup,
542 	.extension_data	= extension_data
543 };
544