1 #include "internal/tarray.h"
2 
3 #include <string.h>
4 
5 	/*
6 	   Structures which contain the play times of each pattern and row combination in the song,
7 	   not guaranteed to be valid for the whole song until the loop status is no longer zero.
8 	   The initial count and restart count will both be zero on song start, then both will be
9 	   incremented until the song loops. Restart count will be reset to zero on loop for all
10 	   rows which have a time equal to or greater than the loop start point, so time keeping
11 	   functions will know which timestamp the song is currently located at.
12 
13 	   Timestamp lists are guaranteed to be allocated in blocks of 16 timestamps at a time.
14 	*/
15 
16 	/*
17 	   We don't need full timekeeping because the player loop only wants the first play time
18 	   of the loop start order/row. We also don't really want full timekeeping because it
19 	   involves a lot of memory allocations, which is also slow.
20 	*/
21 
22 #undef FULL_TIMEKEEPING
23 
24 typedef struct DUMB_IT_ROW_TIME
25 {
26 	unsigned int count, restart_count;
27 #ifndef FULL_TIMEKEEPING
28 	LONG_LONG first_time;
29 #else
30 	LONG_LONG * times;
31 #endif
32 } DUMB_IT_ROW_TIME;
33 
timekeeping_array_create(size_t size)34 void * timekeeping_array_create(size_t size)
35 {
36 	size_t * _size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * size );
37 	if ( _size ) {
38 		*_size = size;
39 	}
40 	return _size;
41 }
42 
timekeeping_array_destroy(void * array)43 void timekeeping_array_destroy(void * array)
44 {
45 #ifdef FULL_TIMEKEEPING
46 	size_t i;
47 	size_t * size = (size_t *) array;
48 	DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
49 
50 	for (i = 0; i < *size; i++) {
51 		if (s[i].times) free(s[i].times);
52 	}
53 #endif
54 
55     free(array);
56 }
57 
timekeeping_array_dup(void * array)58 void * timekeeping_array_dup(void * array)
59 {
60 	size_t i;
61 	size_t * size = (size_t *) array;
62 	DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
63 	size_t * new_size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * *size );
64 	if ( new_size ) {
65 		DUMB_IT_ROW_TIME * new_s = (DUMB_IT_ROW_TIME *)(new_size + 1);
66 
67 		*new_size = *size;
68 
69 		for (i = 0; i < *size; i++) {
70 			new_s[i].count = s[i].count;
71 			new_s[i].restart_count = s[i].restart_count;
72 
73 #ifndef FULL_TIMEKEEPING
74 			new_s[i].first_time = s[i].first_time;
75 #else
76 			if ( s[i].times ) {
77 				size_t time_count = ( s[i].count + 15 ) & ~15;
78 				new_s[i].times = (LONG_LONG *) malloc( sizeof(LONG_LONG) * time_count );
79 				if ( new_s[i].times == (void *)0 ) {
80 					timekeeping_array_destroy( new_size );
81 					return (void *) 0;
82 				}
83 				memcpy( new_s[i].times, s[i].times, sizeof(LONG_LONG) * s[i].count );
84 			}
85 #endif
86 		}
87 	}
88 
89 	return new_size;
90 }
91 
timekeeping_array_reset(void * array,size_t loop_start)92 void timekeeping_array_reset(void * array, size_t loop_start)
93 {
94 	size_t i;
95 	size_t * size = (size_t *) array;
96 	DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
97 
98 	DUMB_IT_ROW_TIME * s_loop_start = s + loop_start;
99 	LONG_LONG loop_start_time;
100 
101 	if ( loop_start >= *size || s_loop_start->count < 1 ) return;
102 
103 #ifndef FULL_TIMEKEEPING
104 	loop_start_time = s_loop_start->first_time;
105 #else
106 	loop_start_time = s_loop_start->times[0];
107 #endif
108 
109 	for ( i = 0; i < *size; i++ ) {
110 #ifndef FULL_TIMEKEEPING
111 		if ( s[i].count && s[i].first_time >= loop_start_time ) {
112 #else
113 		if ( s[i].count && s[i].times[0] >= loop_start_time ) {
114 #endif
115 			s[i].restart_count = 0;
116 		}
117 	}
118 }
119 
120 void timekeeping_array_push(void * array, size_t index, LONG_LONG time)
121 {
122 #ifdef FULL_TIMEKEEPING
123 	size_t i;
124     size_t time_count;
125 #endif
126     size_t * size = (size_t *) array;
127 	DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
128 
129 	if (index >= *size) return;
130 
131 #ifndef FULL_TIMEKEEPING
132 	if ( !s[index].count++ )
133 		s[index].first_time = time;
134 #else
135 	time_count = ( s[index].count + 16 ) & ~15;
136 
137 	s[index].times = (LONG_LONG *) realloc( s[index].times, sizeof(LONG_LONG) * time_count );
138 
139 	s[index].times[s[index].count++] = time;
140 #endif
141 }
142 
143 void timekeeping_array_bump(void * array, size_t index)
144 {
145 	size_t * size = (size_t *) array;
146 	DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
147 
148 	if (index >= *size) return;
149 
150 	s[index].restart_count++;
151 }
152 
153 unsigned int timekeeping_array_get_count(void * array, size_t index)
154 {
155 	size_t * size = (size_t *) array;
156 	DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
157 
158 	if (index >= *size) return 0;
159 
160 	return s[index].count;
161 }
162 
163 LONG_LONG timekeeping_array_get_item(void * array, size_t index)
164 {
165 	size_t * size = (size_t *) array;
166 	DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
167 
168 	if (index >= *size || s[index].restart_count >= s[index].count) return 0;
169 
170 #ifndef FULL_TIMEKEEPING
171 	return s[index].first_time;
172 #else
173 	return s[index].times[s[index].restart_count];
174 #endif
175 }
176