diff options
| author | Olivia Mackintosh <livvy@base.nu> | 2020-04-21 18:33:32 +0100 | 
|---|---|---|
| committer | Olivia Mackintosh <livvy@base.nu> | 2020-04-21 18:33:32 +0100 | 
| commit | ddd234ea1ff2924e587372aa12c4d5cda99a0ce0 (patch) | |
| tree | f5c6f28a18b726d04fcbb351341df4fb05714385 /src/track.c | |
| download | tiny-ddd234ea1ff2924e587372aa12c4d5cda99a0ce0.tar.gz | |
Initial commit
Diffstat (limited to 'src/track.c')
| -rw-r--r-- | src/track.c | 121 | 
1 files changed, 121 insertions, 0 deletions
| diff --git a/src/track.c b/src/track.c new file mode 100644 index 0000000..e0bbe9c --- /dev/null +++ b/src/track.c @@ -0,0 +1,121 @@ +#include <stdlib.h> +#include <assert.h> +#include <math.h> + +#include "sync.h" +#include "track.h" +#include "base.h" + +static double key_linear(const struct track_key k[2], double row) +{ +	double t = (row - k[0].row) / (k[1].row - k[0].row); +	return k[0].value + (k[1].value - k[0].value) * t; +} + +static double key_smooth(const struct track_key k[2], double row) +{ +	double t = (row - k[0].row) / (k[1].row - k[0].row); +	t = t * t * (3 - 2 * t); +	return k[0].value + (k[1].value - k[0].value) * t; +} + +static double key_ramp(const struct track_key k[2], double row) +{ +	double t = (row - k[0].row) / (k[1].row - k[0].row); +	t = pow(t, 2.0); +	return k[0].value + (k[1].value - k[0].value) * t; +} + +double sync_get_val(const struct sync_track *t, double row) +{ +	int idx, irow; + +	/* If we have no keys at all, return a constant 0 */ +	if (!t->num_keys) +		return 0.0f; + +	irow = (int)floor(row); +	idx = key_idx_floor(t, irow); + +	/* at the edges, return the first/last value */ +	if (idx < 0) +		return t->keys[0].value; +	if (idx > (int)t->num_keys - 2) +		return t->keys[t->num_keys - 1].value; + +	/* interpolate according to key-type */ +	switch (t->keys[idx].type) { +	case KEY_STEP: +		return t->keys[idx].value; +	case KEY_LINEAR: +		return key_linear(t->keys + idx, row); +	case KEY_SMOOTH: +		return key_smooth(t->keys + idx, row); +	case KEY_RAMP: +		return key_ramp(t->keys + idx, row); +	default: +		assert(0); +		return 0.0f; +	} +} + +int sync_find_key(const struct sync_track *t, int row) +{ +	int lo = 0, hi = t->num_keys; + +	/* binary search, t->keys is sorted by row */ +	while (lo < hi) { +		int mi = (lo + hi) / 2; +		assert(mi != hi); + +		if (t->keys[mi].row < row) +			lo = mi + 1; +		else if (t->keys[mi].row > row) +			hi = mi; +		else +			return mi; /* exact hit */ +	} +	assert(lo == hi); + +	/* return first key after row, negated and biased (to allow -0) */ +	return -lo - 1; +} + +#ifndef SYNC_PLAYER +int sync_set_key(struct sync_track *t, const struct track_key *k) +{ +	int idx = sync_find_key(t, k->row); +	if (idx < 0) { +		/* no exact hit, we need to allocate a new key */ +		void *tmp; +		idx = -idx - 1; +		tmp = realloc(t->keys, sizeof(struct track_key) * +		    (t->num_keys + 1)); +		if (!tmp) +			return -1; +		t->num_keys++; +		t->keys = tmp; +		memmove(t->keys + idx + 1, t->keys + idx, +		    sizeof(struct track_key) * (t->num_keys - idx - 1)); +	} +	t->keys[idx] = *k; +	return 0; +} + +int sync_del_key(struct sync_track *t, int pos) +{ +	void *tmp; +	int idx = sync_find_key(t, pos); +	assert(idx >= 0); +	memmove(t->keys + idx, t->keys + idx + 1, +	    sizeof(struct track_key) * (t->num_keys - idx - 1)); +	assert(t->keys); +	tmp = realloc(t->keys, sizeof(struct track_key) * +	    (t->num_keys - 1)); +	if (t->num_keys != 1 && !tmp) +		return -1; +	t->num_keys--; +	t->keys = tmp; +	return 0; +} +#endif | 
