ref: 153721b1c9f4cde62fa17d6aef56f782b37384bf
parent: 99111038210a07af485be94a6e85dc43faa10eff
author: Chris Moeller <kode54@gmail.com>
date: Mon Jun 3 14:41:31 EDT 2013
- Implemented loop-accurate time position reporting into DUMB - Implemented get samples stopping short on loops
--- a/dumb/include/dumb.h
+++ b/dumb/include/dumb.h
@@ -585,6 +585,10 @@
sample_t *samples
);
+typedef long (*DUH_SIGRENDERER_GET_POSITION)(
+ sigrenderer_t *sigrenderer
+);
+
typedef void (*DUH_END_SIGRENDERER)(sigrenderer_t *sigrenderer);
typedef void (*DUH_UNLOAD_SIGDATA)(sigdata_t *sigdata);
@@ -600,6 +604,7 @@
DUH_SIGRENDERER_SET_SIGPARAM sigrenderer_set_sigparam;
DUH_SIGRENDERER_GENERATE_SAMPLES sigrenderer_generate_samples;
DUH_SIGRENDERER_GET_CURRENT_SAMPLE sigrenderer_get_current_sample;
+ DUH_SIGRENDERER_GET_POSITION sigrenderer_get_position;
DUH_END_SIGRENDERER end_sigrenderer;
DUH_UNLOAD_SIGDATA unload_sigdata;
}
--- a/dumb/include/internal/it.h
+++ b/dumb/include/internal/it.h
@@ -33,6 +33,7 @@
#include <stddef.h>
#include "barray.h"
+#include "tarray.h"
/** TO DO: THINK ABOUT THE FOLLOWING:
@@ -722,6 +723,21 @@
#ifdef BIT_ARRAY_BULLSHIT
/* bit array, which rows are played, only checked by pattern break or loop commands */
void * played;
+
+ /*
+ Loop indicator for internal processes, may also be useful for external processes
+ 0 - Not looped
+ 1 - Looped
+ -1 - Continued past loop
+ */
+ int looped;
+
+ /*
+ Kept until looped
+ */
+ LONG_LONG time_played;
+
+ void * row_timekeeper;
#endif
long gvz_time;
--- /dev/null
+++ b/dumb/include/internal/tarray.h
@@ -1,0 +1,21 @@
+#ifndef _T_ARRAY_H_
+#define _T_ARRAY_H_
+
+#include <stdlib.h>
+
+#include "../dumb.h"
+
+void * timekeeping_array_create(size_t size);
+void timekeeping_array_destroy(void * array);
+void * timekeeping_array_dup(void * array);
+
+void timekeeping_array_reset(void * array, size_t loop_start);
+
+void timekeeping_array_push(void * array, size_t index, LONG_LONG time);
+void timekeeping_array_bump(void * array, size_t index);
+
+unsigned int timekeeping_array_get_count(void * array, size_t index);
+
+LONG_LONG timekeeping_array_get_item(void * array, size_t index);
+
+#endif
--- a/dumb/prj/dumb/dumb.pro
+++ b/dumb/prj/dumb/dumb.pro
@@ -36,6 +36,7 @@
../../src/helpers/clickrem.c \
../../src/helpers/blip_buf.c \
../../src/helpers/barray.c \
+ ../../src/helpers/tarray.c \
../../src/it/xmeffect.c \
../../src/it/readxm2.c \
../../src/it/readxm.c \
@@ -108,6 +109,7 @@
../../include/internal/dumb.h \
../../include/internal/blip_buf.h \
../../include/internal/barray.h \
+ ../../include/internal/tarray.h \
../../include/internal/aldumb.h \
../../include/internal/fir_resampler.h \
../../include/internal/stack_alloc.h \
--- a/dumb/src/core/rendsig.c
+++ b/dumb/src/core/rendsig.c
@@ -143,7 +143,15 @@
long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer)
{
- return sigrenderer ? sigrenderer->pos : -1;
+ DUH_SIGRENDERER_GET_POSITION proc;
+
+ if (!sigrenderer) return -1;
+
+ proc = sigrenderer->desc->sigrenderer_get_position;
+ if (proc)
+ return (*proc)(sigrenderer->sigrenderer);
+ else
+ return sigrenderer->pos;
}
--- /dev/null
+++ b/dumb/src/helpers/tarray.c
@@ -1,0 +1,176 @@
+#include "internal/tarray.h"
+
+#include <string.h>
+
+ /*
+ 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.
+ */
+
+#undef FULL_TIMEKEEPING
+
+typedef struct DUMB_IT_ROW_TIME
+{
+ unsigned int count, restart_count;
+#ifndef FULL_TIMEKEEPING
+ LONG_LONG first_time;
+#else
+ LONG_LONG * times;
+#endif
+} DUMB_IT_ROW_TIME;
+
+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;
+}
+
+void timekeeping_array_destroy(void * array)
+{
+ size_t i;
+ size_t * size = (size_t *) array;
+ DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
+
+#ifdef FULL_TIMEKEEPING
+ for (i = 0; i < *size; i++) {
+ if (s[i].times) free(s[i].times);
+ }
+#endif
+
+ free(size);
+}
+
+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);
+
+ *new_size = *size;
+
+ for (i = 0; i < *size; i++) {
+ new_s[i].count = s[i].count;
+ new_s[i].restart_count = s[i].restart_count;
+
+#ifndef FULL_TIMEKEEPING
+ new_s[i].first_time = s[i].first_time;
+#else
+ 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 );
+ }
+#endif
+ }
+ }
+
+ return new_size;
+}
+
+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);
+
+ DUMB_IT_ROW_TIME * s_loop_start = s + loop_start;
+ LONG_LONG loop_start_time;
+
+ if ( loop_start >= *size || s_loop_start->count < 1 ) return;
+
+#ifndef FULL_TIMEKEEPING
+ loop_start_time = s_loop_start->first_time;
+#else
+ loop_start_time = s_loop_start->times[0];
+#endif
+
+ for ( i = 0; i < *size; i++ ) {
+#ifndef FULL_TIMEKEEPING
+ if ( s[i].count && s[i].first_time >= loop_start_time ) {
+#else
+ if ( s[i].count && s[i].times[0] >= loop_start_time ) {
+#endif
+ s[i].restart_count = 0;
+ }
+ }
+}
+
+void timekeeping_array_push(void * array, size_t index, LONG_LONG time)
+{
+ size_t i;
+ size_t * size = (size_t *) array;
+ DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
+ size_t time_count;
+
+ if (index >= *size) return;
+
+#ifndef FULL_TIMEKEEPING
+ if ( !s[index].count++ )
+ s[index].first_time = time;
+#else
+ time_count = ( s[index].count + 16 ) & ~15;
+
+ s[index].times = (LONG_LONG *) realloc( s[index].times, sizeof(LONG_LONG) * time_count );
+
+ s[index].times[s[index].count++] = time;
+#endif
+}
+
+void timekeeping_array_bump(void * array, size_t index)
+{
+ size_t i;
+ size_t * size = (size_t *) array;
+ DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
+
+ if (index >= *size) return;
+
+ s[index].restart_count++;
+}
+
+unsigned int timekeeping_array_get_count(void * array, size_t index)
+{
+ size_t i;
+ size_t * size = (size_t *) array;
+ DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
+
+ if (index >= *size) return 0;
+
+ return s[index].count;
+}
+
+LONG_LONG timekeeping_array_get_item(void * array, size_t index)
+{
+ size_t i;
+ size_t * size = (size_t *) array;
+ DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
+
+ if (index >= *size || s[index].restart_count >= s[index].count) return 0;
+
+#ifndef FULL_TIMEKEEPING
+ return s[index].first_time;
+#else
+ return s[index].times[s[index].restart_count];
+#endif
+}
--- a/dumb/src/it/itrender.c
+++ b/dumb/src/it/itrender.c
@@ -379,6 +379,8 @@
#ifdef BIT_ARRAY_BULLSHIT
dst->played = bit_array_dup(src->played);
+
+ dst->row_timekeeper = timekeeping_array_dup(src->row_timekeeper);
#endif
dst->gvz_time = src->gvz_time;
@@ -2196,6 +2198,9 @@
bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row);
#endif
sigrenderer->speed = 0;
+#ifdef BIT_ARRAY_BULLSHIT
+ sigrenderer->looped = 1;
+#endif
if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data))
return 1;
}
@@ -4235,6 +4240,10 @@
*/
#endif
bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row);
+ if (sigrenderer->looped == 0) {
+ timekeeping_array_push(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row, sigrenderer->time_played);
+ }
+ timekeeping_array_bump(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row);
{
int n;
for (n = 0; n < DUMB_IT_N_CHANNELS; n++)
@@ -4349,6 +4358,9 @@
&& bit_array_test(sigrenderer->played, sigrenderer->processorder * 256 + sigrenderer->processrow)
#endif
) {
+#ifdef BIT_ARRAY_BULLSHIT
+ sigrenderer->looped = 1;
+#endif
if (sigrenderer->callbacks->loop) {
if ((*sigrenderer->callbacks->loop)(sigrenderer->callbacks->loop_data))
return 1;
@@ -4444,6 +4456,9 @@
sigrenderer->gvz_time += (int)(t >> 16);
sigrenderer->gvz_sub_time = (int)t & 65535;
if (sigrenderer->gvz_time >= 65536 * 12) {
+#ifdef BIT_ARRAY_BULLSHIT
+ sigrenderer->looped = 1;
+#endif
if ((*sigrenderer->callbacks->global_volume_zero)(sigrenderer->callbacks->global_volume_zero_data))
return 1;
}
@@ -5575,6 +5590,10 @@
#ifdef BIT_ARRAY_BULLSHIT
sigrenderer->played = bit_array_create(sigdata->n_orders * 256);
+
+ sigrenderer->looped = 0;
+ sigrenderer->time_played = 0;
+ sigrenderer->row_timekeeper = timekeeping_array_create(sigdata->n_orders * 256);
#endif
sigrenderer->gvz_time = 0;
@@ -5758,7 +5777,7 @@
long pos;
int dt;
long todo;
- LONG_LONG t;
+ LONG_LONG time_left, t;
if (sigrenderer->order < 0) return 0; // problematic
@@ -5771,7 +5790,8 @@
if (!samples) volume = 0;
for (;;) {
- todo = (long)((((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left) / dt);
+ time_left = ((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left;
+ todo = (long)(time_left / dt);
if (todo >= size)
break;
@@ -5785,11 +5805,25 @@
sigrenderer->sub_time_left = (long)t & 65535;
sigrenderer->time_left += (long)(t >> 16);
+#ifdef BIT_ARRAY_BULLSHIT
+ sigrenderer->time_played += time_left;
+#endif
+
if (process_tick(sigrenderer)) {
sigrenderer->order = -1;
sigrenderer->row = -1;
return pos;
}
+
+#ifdef BIT_ARRAY_BULLSHIT
+ if (sigrenderer->looped == 1) {
+ sigrenderer->looped = -1;
+ size = 0;
+ timekeeping_array_reset(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row);
+ sigrenderer->time_played = timekeeping_array_get_item(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row);
+ break;
+ }
+#endif
}
render(sigrenderer, volume, delta, pos, size, samples);
@@ -5800,6 +5834,10 @@
sigrenderer->sub_time_left = (long)t & 65535;
sigrenderer->time_left += (long)(t >> 16);
+#ifdef BIT_ARRAY_BULLSHIT
+ sigrenderer->time_played += (LONG_LONG)size * dt;
+#endif
+
if (samples)
dumb_remove_clicks_array(sigrenderer->n_channels, sigrenderer->click_remover, samples, pos, 512.0f / delta);
@@ -5843,6 +5881,8 @@
#ifdef BIT_ARRAY_BULLSHIT
bit_array_destroy(sigrenderer->played);
+
+ timekeeping_array_destroy(sigrenderer->row_timekeeper);
#endif
free(vsigrenderer);
@@ -5851,6 +5891,17 @@
+#ifdef BIT_ARRAY_BULLSHIT
+static long it_sigrenderer_get_position(sigrenderer_t *vsigrenderer)
+{
+ DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer;
+
+ return sigrenderer->time_played >> 16;
+}
+#endif
+
+
+
DUH_SIGTYPE_DESC _dumb_sigtype_it = {
SIGTYPE_IT,
NULL,
@@ -5858,6 +5909,11 @@
NULL,
&it_sigrenderer_get_samples,
&it_sigrenderer_get_current_sample,
+#ifdef BIT_ARRAY_BULLSHIT
+ &it_sigrenderer_get_position,
+#else
+ NULL,
+#endif
&_dumb_it_end_sigrenderer,
&_dumb_it_unload_sigdata
};
--- a/dumb/vc6/dumb/dumb.vcxproj
+++ b/dumb/vc6/dumb/dumb.vcxproj
@@ -116,6 +116,7 @@
<ClCompile Include="..\..\src\helpers\sampbuf.c" />
<ClCompile Include="..\..\src\helpers\silence.c" />
<ClCompile Include="..\..\src\helpers\stdfile.c" />
+ <ClCompile Include="..\..\src\helpers\tarray.c" />
<ClCompile Include="..\..\src\it\itmisc.c" />
<ClCompile Include="..\..\src\it\itorder.c" />
<ClCompile Include="..\..\src\it\itrender.c" />
@@ -207,6 +208,7 @@
<ClInclude Include="..\..\include\internal\lpc.h" />
<ClInclude Include="..\..\include\internal\riff.h" />
<ClInclude Include="..\..\include\internal\stack_alloc.h" />
+ <ClInclude Include="..\..\include\internal\tarray.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
--- a/dumb/vc6/dumb/dumb.vcxproj.filters
+++ b/dumb/vc6/dumb/dumb.vcxproj.filters
@@ -285,6 +285,9 @@
<ClCompile Include="..\..\src\helpers\lanczos_resampler.c">
<Filter>src\helpers</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\helpers\tarray.c">
+ <Filter>src\helpers</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\dumb.h">
@@ -315,6 +318,9 @@
<Filter>include\internal</Filter>
</ClInclude>
<ClInclude Include="..\..\include\internal\lanczos_resampler.h">
+ <Filter>include\internal</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\internal\tarray.h">
<Filter>include\internal</Filter>
</ClInclude>
</ItemGroup>