diff options
| author | 2024-04-09 11:24:01 -0400 | |
|---|---|---|
| committer | 2024-04-09 11:24:01 -0400 | |
| commit | 02f3d3565602146bbbfce85b2719246f24036cb9 (patch) | |
| tree | c6588ffe297b777e36260effa4fa42b958ca6ba3 /src/list | |
| parent | bbf3314165182e402ff25acccddc004a87f81ef0 (diff) | |
| download | camu-02f3d3565602146bbbfce85b2719246f24036cb9.tar.gz camu-02f3d3565602146bbbfce85b2719246f24036cb9.tar.bz2 camu-02f3d3565602146bbbfce85b2719246f24036cb9.zip | |
Massive restructure and many changes
- The server-side list concept is still a wip
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'src/list')
| -rw-r--r-- | src/list/list.c | 172 | ||||
| -rw-r--r-- | src/list/list.h | 54 | ||||
| -rw-r--r-- | src/list/meson.build | 5 |
3 files changed, 231 insertions, 0 deletions
diff --git a/src/list/list.c b/src/list/list.c new file mode 100644 index 0000000..3af75e4 --- /dev/null +++ b/src/list/list.c @@ -0,0 +1,172 @@ +#include <al/random.h> +#include <aki/thread.h> + +#include "../libsink/common.h" + +#include "list.h" + +void camu_list_init(struct camu_list *list, str *name) +{ + al_str_clone(&list->name, name); + list->current = -1; + list->idle = true; + list->sequence = 0; + al_array_init(list->entries); + al_array_init(list->sinks); +} + +static void camu_list_pump(struct camu_list *list) +{ + s32 size = (s32)list->entries.size; + if (list->current == -1 || size <= list->current) return; + struct camu_list_entry *entry = al_array_at(list->entries, list->current); + struct camu_list_entry *upcoming = NULL; + if (list->current + 1 < size) { + upcoming = al_array_at(list->entries, list->current + 1); + } + struct camu_list_sink *sink; + al_array_foreach(list->sinks, i, sink) { + if (sink->set != list->current) { + sink->callback(sink->userdata, CAMU_SINK_SET, entry->opaque, entry->sequence); + sink->set = list->current; + } + if (upcoming) { + sink->callback(sink->userdata, CAMU_SINK_QUEUE, upcoming->opaque, upcoming->sequence); + } + } +} + +void camu_list_add_sink(struct camu_list *list, void (*callback)(void *, u8, void *, s32), + void *userdata) +{ + struct camu_list_sink *sink = al_alloc_object(struct camu_list_sink); + sink->set = -1; + sink->callback = callback; + sink->userdata = userdata; + al_array_push(list->sinks, sink); + camu_list_pump(list); +} + +void camu_list_remove_sink(struct camu_list *list, void *userdata) +{ + struct camu_list_sink *sink; + al_array_foreach(list->sinks, i, sink) { + if (sink->userdata == userdata) { + al_array_remove_at_iter(list->sinks, i); + break; + } + } +} + +void camu_list_add(struct camu_list *list, void *opaque, void (*callback)(void *, u8, void *), + u64 duration, bool set) +{ + s32 size = (s32)list->entries.size; + struct camu_list_entry *entry = al_alloc_object(struct camu_list_entry); + entry->sequence = list->sequence++; + entry->opaque = opaque; + entry->callback = callback; + entry->duration = duration; + entry->start = aki_get_timestamp(); + if (!list->idle) { + struct camu_list_entry *prev = al_array_at(list->entries, size - 1); + u64 end = prev->start + prev->duration; + if (end > entry->start) { + u64 diff = end - entry->start; + entry->start += diff; + } + } + al_array_push(list->entries, entry); + if (set) list->current = size; + else if (list->idle) { + list->current++; + list->idle = false; + } + camu_list_pump(list); + struct camu_list_timing timing = { + .start = entry->start + }; + entry->callback(entry->opaque, CAMU_LIST_ENTRY_IMPULSE, &timing); +} + +static s32 index_of_entry_from_sequence(struct camu_list *list, s32 sequence) +{ + if (sequence != CAMU_SEQUENCE_INVALID) { + struct camu_list_entry *entry; + al_array_foreach(list->entries, i, entry) { + if (entry->sequence == sequence) return i; + } + } + return CAMU_SEQUENCE_INVALID; +} + +void camu_list_skip(struct camu_list *list, s32 sequence, s32 n) +{ + s32 size = (s32)list->entries.size; + s32 index = index_of_entry_from_sequence(list, sequence); + if (index == CAMU_SEQUENCE_INVALID) index = list->current; + if (index + n < 0 || index + n >= size || index + n == list->current) return; + list->current = index + n; + struct camu_list_entry *entry = al_array_at(list->entries, list->current); + struct camu_list_timing timing = { + .start = aki_get_timestamp() + }; + entry->callback(entry->opaque, CAMU_LIST_ENTRY_IMPULSE, &timing); + camu_list_pump(list); +} + +void camu_list_skipto(struct camu_list *list, s32 i) +{ + s32 size = (s32)list->entries.size; + if (i < 0 || i >= size) return; + list->current = i; + camu_list_pump(list); +} + +void camu_list_toggle_pause(struct camu_list *list, s32 sequence, u64 pos) +{ + s32 index = index_of_entry_from_sequence(list, sequence); + if (index == CAMU_SEQUENCE_INVALID) return; + struct camu_list_entry *entry = al_array_at(list->entries, index); + entry->callback(entry->opaque, CAMU_LIST_ENTRY_TOGGLE_PAUSE, &pos); +} + +void camu_list_seek(struct camu_list *list, s32 sequence, f64 percent) +{ + s32 index = index_of_entry_from_sequence(list, sequence); + if (index == CAMU_SEQUENCE_INVALID) return; + list->idle = false; + struct camu_list_entry *entry = al_array_at(list->entries, index); + u64 pos = percent * entry->duration; + entry->callback(entry->opaque, CAMU_LIST_ENTRY_SEEK, &pos); +} + +void camu_list_finished(struct camu_list *list, s32 sequence) +{ + s32 size = (s32)list->entries.size; + s32 index = index_of_entry_from_sequence(list, sequence); + if (index == CAMU_SEQUENCE_INVALID) return; + if (index + 1 >= size) { + list->idle = true; + return; + } + list->current = index + 1; + camu_list_pump(list); +} + +void camu_list_shuffle(struct camu_list *list) +{ + u32 size = list->entries.size; + if (size == 0) return; + for (u32 i = 0; i < size - 1; i++) { + u32 j = i + al_rand() / (AL_RAND_MAX / (size - i) + 1); + struct camu_list_entry *tmp = al_array_at(list->entries, j); + al_array_at(list->entries, j) = al_array_at(list->entries, i); + al_array_at(list->entries, i) = tmp; + } + struct camu_list_sink *sink; + al_array_foreach(list->sinks, i, sink) { + sink->set = -1; + } + camu_list_pump(list); +} diff --git a/src/list/list.h b/src/list/list.h new file mode 100644 index 0000000..edd0218 --- /dev/null +++ b/src/list/list.h @@ -0,0 +1,54 @@ +#pragma once + +#include <al/str.h> +#include <al/array.h> + +#define CAMU_SEQUENCE_INVALID INT32_MAX + +enum { + CAMU_LIST_ENTRY_IMPULSE = 0, + CAMU_LIST_ENTRY_TOGGLE_PAUSE, + CAMU_LIST_ENTRY_SEEK +}; + +struct camu_list_timing { + u64 start; +}; + +struct camu_list_entry { + s32 sequence; + void *opaque; + void (*callback)(void *, u8, void *); + u64 duration; + u64 start; + u64 paused_at; +}; + +struct camu_list_sink { + s32 set; + bool (*action)(void *, u8, void *); + void (*callback)(void *, u8, void *, s32); + void *userdata; +}; + +struct camu_list { + str name; + s32 current; + bool idle; + s32 sequence; // Next entry sequence. + array(struct camu_list_entry *) entries; + array(struct camu_list_sink *) sinks; +}; + +void camu_list_init(struct camu_list *list, str *name); +void camu_list_add_sink(struct camu_list *list, void (*callback)(void *, u8, void *, s32), + void *userdata); +void camu_list_remove_sink(struct camu_list *list, void *userdata); +void camu_list_add(struct camu_list *list, void *opaque, void (*callback)(void *, u8, void *), + u64 duration, bool set); +void camu_list_skip(struct camu_list *list, s32 sequence, s32 n); +void camu_list_skipto(struct camu_list *list, s32 i); +void camu_list_toggle_pause(struct camu_list *list, s32 sequence, u64 pos); +void camu_list_seek(struct camu_list *list, s32 sequence, f64 percent); +void camu_list_finished(struct camu_list *list, s32 sequence); +void camu_list_shuffle(struct camu_list *list); diff --git a/src/list/meson.build b/src/list/meson.build new file mode 100644 index 0000000..c61ac39 --- /dev/null +++ b/src/list/meson.build @@ -0,0 +1,5 @@ +list_src = [ + 'list.c' +] +list_deps = [common_deps] +list = declare_dependency(sources: list_src, dependencies: list_deps) |