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 |