Cog/Frameworks/Dumb/dumb/src/helpers/tarray.c

181 lines
4.9 KiB
C
Raw Normal View History

2013-09-28 00:24:23 -03:00
#include "internal/tarray.h"
#include <string.h>
2017-09-26 20:11:54 -03:00
/*
Structures which contain the play times of each pattern and row combination
in the song, not guaranteed to be valid for the whole song until the loop
status is no longer zero. The initial count and restart count will both be
zero on song start, then both will be incremented until the song loops.
Restart count will be reset to zero on loop for all rows which have a time
equal to or greater than the loop start point, so time keeping functions will
know which timestamp the song is currently located at.
Timestamp lists are guaranteed to be allocated in blocks of 16 timestamps at
a time.
*/
/*
We don't need full timekeeping because the player loop only wants the first
play time of the loop start order/row. We also don't really want full
timekeeping because it involves a lot of memory allocations, which is also
slow.
*/
2013-09-28 00:24:23 -03:00
#undef FULL_TIMEKEEPING
2017-09-26 20:11:54 -03:00
typedef struct DUMB_IT_ROW_TIME {
unsigned int count, restart_count;
2013-09-28 00:24:23 -03:00
#ifndef FULL_TIMEKEEPING
2017-09-26 20:11:54 -03:00
LONG_LONG first_time;
2013-09-28 00:24:23 -03:00
#else
2017-09-26 20:11:54 -03:00
LONG_LONG *times;
2013-09-28 00:24:23 -03:00
#endif
} DUMB_IT_ROW_TIME;
2017-09-26 20:11:54 -03:00
void *timekeeping_array_create(size_t size) {
size_t *_size =
(size_t *)calloc(1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * size);
if (_size) {
*_size = size;
}
return _size;
2013-09-28 00:24:23 -03:00
}
2017-09-26 20:11:54 -03:00
void timekeeping_array_destroy(void *array) {
2013-09-28 00:24:23 -03:00
#ifdef FULL_TIMEKEEPING
2017-09-26 20:11:54 -03:00
size_t i;
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
for (i = 0; i < *size; i++) {
if (s[i].times)
free(s[i].times);
}
2013-09-28 00:24:23 -03:00
#endif
free(array);
}
2017-09-26 20:11:54 -03:00
void *timekeeping_array_dup(void *array) {
size_t i;
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
size_t *new_size =
(size_t *)calloc(1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * *size);
if (new_size) {
DUMB_IT_ROW_TIME *new_s = (DUMB_IT_ROW_TIME *)(new_size + 1);
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
*new_size = *size;
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
for (i = 0; i < *size; i++) {
new_s[i].count = s[i].count;
new_s[i].restart_count = s[i].restart_count;
2013-09-28 00:24:23 -03:00
#ifndef FULL_TIMEKEEPING
2017-09-26 20:11:54 -03:00
new_s[i].first_time = s[i].first_time;
2013-09-28 00:24:23 -03:00
#else
2017-09-26 20:11:54 -03:00
if (s[i].times) {
size_t time_count = (s[i].count + 15) & ~15;
new_s[i].times =
(LONG_LONG *)malloc(sizeof(LONG_LONG) * time_count);
if (new_s[i].times == (void *)0) {
timekeeping_array_destroy(new_size);
return (void *)0;
}
memcpy(new_s[i].times, s[i].times,
sizeof(LONG_LONG) * s[i].count);
}
2013-09-28 00:24:23 -03:00
#endif
2017-09-26 20:11:54 -03:00
}
}
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
return new_size;
2013-09-28 00:24:23 -03:00
}
2017-09-26 20:11:54 -03:00
void timekeeping_array_reset(void *array, size_t loop_start) {
size_t i;
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
DUMB_IT_ROW_TIME *s_loop_start = s + loop_start;
LONG_LONG loop_start_time;
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
if (loop_start >= *size || s_loop_start->count < 1)
return;
2013-09-28 00:24:23 -03:00
#ifndef FULL_TIMEKEEPING
2017-09-26 20:11:54 -03:00
loop_start_time = s_loop_start->first_time;
2013-09-28 00:24:23 -03:00
#else
2017-09-26 20:11:54 -03:00
loop_start_time = s_loop_start->times[0];
2013-09-28 00:24:23 -03:00
#endif
2017-09-26 20:11:54 -03:00
for (i = 0; i < *size; i++) {
2013-09-28 00:24:23 -03:00
#ifndef FULL_TIMEKEEPING
2017-09-26 20:11:54 -03:00
if (s[i].count && s[i].first_time >= loop_start_time) {
2013-09-28 00:24:23 -03:00
#else
2017-09-26 20:11:54 -03:00
if (s[i].count && s[i].times[0] >= loop_start_time) {
2013-09-28 00:24:23 -03:00
#endif
2017-09-26 20:11:54 -03:00
s[i].restart_count = 0;
}
}
2013-09-28 00:24:23 -03:00
}
2017-09-26 20:11:54 -03:00
void timekeeping_array_push(void *array, size_t index, LONG_LONG time) {
2013-09-28 00:24:23 -03:00
#ifdef FULL_TIMEKEEPING
2017-09-26 20:11:54 -03:00
size_t i;
2013-09-28 00:24:23 -03:00
size_t time_count;
#endif
2017-09-26 20:11:54 -03:00
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
if (index >= *size)
return;
2013-09-28 00:24:23 -03:00
#ifndef FULL_TIMEKEEPING
2017-09-26 20:11:54 -03:00
if (!s[index].count++)
s[index].first_time = time;
2013-09-28 00:24:23 -03:00
#else
2017-09-26 20:11:54 -03:00
time_count = (s[index].count + 16) & ~15;
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
s[index].times =
(LONG_LONG *)realloc(s[index].times, sizeof(LONG_LONG) * time_count);
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
s[index].times[s[index].count++] = time;
2013-09-28 00:24:23 -03:00
#endif
}
2017-09-26 20:11:54 -03:00
void timekeeping_array_bump(void *array, size_t index) {
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
if (index >= *size)
return;
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
s[index].restart_count++;
2013-09-28 00:24:23 -03:00
}
2017-09-26 20:11:54 -03:00
unsigned int timekeeping_array_get_count(void *array, size_t index) {
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
if (index >= *size)
return 0;
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
return s[index].count;
2013-09-28 00:24:23 -03:00
}
2017-09-26 20:11:54 -03:00
LONG_LONG timekeeping_array_get_item(void *array, size_t index) {
size_t *size = (size_t *)array;
DUMB_IT_ROW_TIME *s = (DUMB_IT_ROW_TIME *)(size + 1);
2013-09-28 00:24:23 -03:00
2017-09-26 20:11:54 -03:00
if (index >= *size || s[index].restart_count >= s[index].count)
return 0;
2013-09-28 00:24:23 -03:00
#ifndef FULL_TIMEKEEPING
2017-09-26 20:11:54 -03:00
return s[index].first_time;
2013-09-28 00:24:23 -03:00
#else
2017-09-26 20:11:54 -03:00
return s[index].times[s[index].restart_count];
2013-09-28 00:24:23 -03:00
#endif
}