Skip to content

Commit

Permalink
DUMB 1.0 and DUMB 0.9.3 compat
Browse files Browse the repository at this point in the history
There are two versions of DUMB that Allegro should support as of
September 2017: DUMB 0.9.3 from Sourceforge, and DUMB 1.0.0 by kode54 on
github. kode54's fork is endorsed by the DUMB homepage.

These changes to modaudio.c should make A5 work with both DUMB versions.
1.0.0 requires two more fields for a complete DUMBFILE_SYSTEM, see
DUMB's include/dumb.h for the definition. A debugging version of DUMB
1.0.0 will fail asserts if we don't provide them. Some functions have
a different interface and we therefore call them differently from A5.

I differentiate by testing DUMB_MAJOR_VERSION as defined in dumb.h.
The DUMB version tagged in git as 1.0 reports 0.9.3 when my
code asks for its header constants (DUMB_MAJOR_VERSION == 0).
We should wait for the next tagged 1.y.z, or find a workaround in the
Allegro build system.
  • Loading branch information
SimonN committed Sep 17, 2017
1 parent 541e63a commit 34ba82f
Showing 1 changed file with 100 additions and 46 deletions.
146 changes: 100 additions & 46 deletions addons/acodec/modaudio.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,14 @@

ALLEGRO_DEBUG_CHANNEL("acodec")

/* In addition to DUMB 0.9.3 at http://dumb.sourceforge.net/,
* we support kode54's fork of DUMB at https://github.com/kode54/dumb.
* The newest version before kode54's fork was DUMB 0.9.3, and the first
* forked version that A5 supports is already 1.0.0.
*/

/* forward declarations */
static bool init_libdumb(void);
static size_t modaudio_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data,
size_t buf_size);
static bool modaudio_stream_rewind(ALLEGRO_AUDIO_STREAM *stream);
Expand Down Expand Up @@ -55,25 +61,39 @@ static void *dumb_dll = NULL;

static struct
{
long (*duh_render)(DUH_SIGRENDERER *, int, int, float, float, long, void *);
long (*duh_sigrenderer_get_position)(DUH_SIGRENDERER *);
void (*duh_end_sigrenderer)(DUH_SIGRENDERER *);
void (*unload_duh)(DUH *);
DUH_SIGRENDERER *(*duh_start_sigrenderer)(DUH *, int, int, long);
DUMBFILE *(*dumbfile_open_ex)(void *, DUMBFILE_SYSTEM *);
long (*duh_get_length)(DUH *);
void (*dumb_exit)(void);
void (*register_dumbfile_system)(DUMBFILE_SYSTEM *);
DUH *(*dumb_read_it)(DUMBFILE *);
DUH *(*dumb_read_xm)(DUMBFILE *);
DUH *(*dumb_read_s3m)(DUMBFILE *);
DUH *(*dumb_read_mod)(DUMBFILE *);
DUMB_IT_SIGRENDERER *(*duh_get_it_sigrenderer)(DUH_SIGRENDERER *);
void (*dumb_it_set_loop_callback)(DUMB_IT_SIGRENDERER *, int (*)(void *), void *);
void (*dumb_it_set_xm_speed_zero_callback)(DUMB_IT_SIGRENDERER *, int (*)(void *), void *);
int (*dumb_it_callback_terminate)(void *);
} lib;

#if ((DUMB_MAJOR_VERSION) >= 1)
/* DUMB 2.0 deprecates duh_render, and suggests instead duh_render_int
* and duh_render_float. I (Simon N.) have no idea how to use those.
* We should work on this once A5 works with DUMB 1.0 and once DUMB 2.0
* has been released (it hasn't yet in September 2017).
*/
long (*duh_render)(DUH_SIGRENDERER *,
int, int, float, float, long, void *);
void (*register_dumbfile_system)(const DUMBFILE_SYSTEM *);
DUMBFILE *(*dumbfile_open_ex)(void *, const DUMBFILE_SYSTEM *);
DUH *(*dumb_read_mod)(DUMBFILE *, int);
#else
long (*duh_render)(DUH_SIGRENDERER *,
int, int, float, float, long, void *);
void (*register_dumbfile_system)(DUMBFILE_SYSTEM *);
DUMBFILE *(*dumbfile_open_ex)(void *, DUMBFILE_SYSTEM *);
DUH *(*dumb_read_mod)(DUMBFILE *);
#endif
} lib;

/* Set up DUMB's file system */
static DUMBFILE_SYSTEM dfs, dfs_f;
Expand Down Expand Up @@ -104,14 +124,25 @@ static void dfs_close(void *f)
(void)f;
}

#if ((DUMB_MAJOR_VERSION) >= 1)
static int dfs_seek(void *f, long n)
{
return al_fseek(f, n, ALLEGRO_SEEK_SET) ? 0 : -1;
}

static long dfs_get_size(void *f)
{
return al_fsize(f);
}
#endif

/* Stream Functions */

static size_t modaudio_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data,
size_t buf_size)
{
MOD_FILE *const df = stream->extra;

/* the mod files are stereo and 16-bit */
const int sample_size = 4;
size_t written;
Expand All @@ -120,31 +151,31 @@ static size_t modaudio_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data,
DUMB_IT_SIGRENDERER *it_sig = lib.duh_get_it_sigrenderer(df->sig);
if (it_sig) {
lib.dumb_it_set_loop_callback(it_sig,
stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONCE
? lib.dumb_it_callback_terminate : NULL, NULL);
stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONCE
? lib.dumb_it_callback_terminate : NULL, NULL);
}

written = lib.duh_render(df->sig, 16, 0, 1.0, 65536.0 / 44100.0,
buf_size / sample_size, data) * sample_size;

/* Fill the remainder with silence */
for (i = written; i < buf_size; ++i)
((char *)data)[i] = 0;

/* Check to see if a loop is set */
if (df->loop_start != -1 &&
if (df->loop_start != -1 &&
df->loop_end < lib.duh_sigrenderer_get_position(df->sig)) {
modaudio_stream_seek(stream, df->loop_start / 65536.0);
}

return written;
}

static void modaudio_stream_close(ALLEGRO_AUDIO_STREAM *stream)
{
MOD_FILE *const df = stream->extra;
_al_acodec_stop_feed_thread(stream);

lib.duh_end_sigrenderer(df->sig);
lib.unload_duh(df->duh);
if (df->fh)
Expand All @@ -162,10 +193,10 @@ static bool modaudio_stream_rewind(ALLEGRO_AUDIO_STREAM *stream)
static bool modaudio_stream_seek(ALLEGRO_AUDIO_STREAM *stream, double time)
{
MOD_FILE *const df = stream->extra;

lib.duh_end_sigrenderer(df->sig);
df->sig = lib.duh_start_sigrenderer(df->duh, 0, 2, time * 65536);

return false;
}

Expand All @@ -185,32 +216,50 @@ static bool modaudio_stream_set_loop(ALLEGRO_AUDIO_STREAM *stream,
double start, double end)
{
MOD_FILE *const df = stream->extra;

df->loop_start = start * 65536;
df->loop_end = end * 65536;

return true;
}

/* Create the Allegro stream */

static ALLEGRO_AUDIO_STREAM *mod_stream_init(ALLEGRO_FILE* f,
size_t buffer_count, unsigned int samples, DUH *(loader)(DUMBFILE *))
/* Create the Allegro stream.
* This takes 2 function pointers in the final 2 arguments: One without int
* arg, one with an int arg. Exactly one of them should be != NULL:
* DUMB 0.9.3 and non-MOD files in DUMB >= 1.0 use the single-argument funcptr.
* The function pointer with the extra int arg is for MOD files in DUMB >= 1.0.
*/
static ALLEGRO_AUDIO_STREAM *stream_init(ALLEGRO_FILE* f,
size_t buffer_count,unsigned int samples,
DUH *(loader)(DUMBFILE *),
DUH *(loader2)(DUMBFILE *, int))
{
ALLEGRO_AUDIO_STREAM *stream;
DUMBFILE *df;
DUH_SIGRENDERER *sig = NULL;
DUH *duh = NULL;
DUMB_IT_SIGRENDERER *it_sig = NULL;
int64_t start_pos = -1;

df = lib.dumbfile_open_ex(f, &dfs_f);
if (!df)
return NULL;

start_pos = al_ftell(f);

duh = loader(df);
if (loader2) {
/* DUMB 1.0 introduces an int argument, restrict_, to configure how
* a MOD module is interpreted. It's considered a two-bit bitfield:
* (restrict_ & 1) and (restrict_ / 2). Since we have to hardcode
* something here, I (Simon N.) tested some modules with
* restrict_ = 0, 1, 2, 3, and found that 0 or 1 work best.
*/
duh = loader2(df, 0);
}
else if (loader) {
duh = loader(df);
}

if (!duh) {
goto Error;
}
Expand All @@ -227,7 +276,7 @@ static ALLEGRO_AUDIO_STREAM *mod_stream_init(ALLEGRO_FILE* f,
}

stream = al_create_audio_stream(buffer_count, samples, 44100,
ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2);
ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2);

if (stream) {
MOD_FILE *mf = al_malloc(sizeof(MOD_FILE));
Expand Down Expand Up @@ -318,7 +367,7 @@ static bool init_libdumb(void)

memset(&lib, 0, sizeof(lib));

INITSYM(duh_render);
INITSYM(duh_render); /* see comment on duh_render deprecation above */
INITSYM(duh_sigrenderer_get_position);
INITSYM(duh_end_sigrenderer);
INITSYM(unload_duh);
Expand All @@ -341,10 +390,14 @@ static bool init_libdumb(void)
dfs.getc = dfs_getc;
dfs.getnc = dfs_getnc;
dfs.close = dfs_close;

#if ((DUMB_MAJOR_VERSION) >= 1)
dfs.seek = dfs_seek;
dfs.get_size = dfs_get_size;
#endif

/* Set up DUMB's default I/O to go through Allegro... */
lib.register_dumbfile_system(&dfs);

/* But we'll actually use them through this version: */
dfs_f = dfs;
dfs_f.open = NULL;
Expand All @@ -360,7 +413,7 @@ ALLEGRO_AUDIO_STREAM *_al_load_mod_audio_stream(const char *filename,
ALLEGRO_FILE *f;
ALLEGRO_AUDIO_STREAM *stream;
ASSERT(filename);

f = al_fopen(filename, "rb");
if (!f)
return NULL;
Expand All @@ -373,7 +426,7 @@ ALLEGRO_AUDIO_STREAM *_al_load_mod_audio_stream(const char *filename,
}

((MOD_FILE *)stream->extra)->fh = f;

return stream;
}

Expand All @@ -383,20 +436,20 @@ ALLEGRO_AUDIO_STREAM *_al_load_it_audio_stream(const char *filename,
ALLEGRO_FILE *f;
ALLEGRO_AUDIO_STREAM *stream;
ASSERT(filename);

f = al_fopen(filename, "rb");
if (!f)
return NULL;

stream = _al_load_it_audio_stream_f(f, buffer_count, samples);

if (!stream) {
al_fclose(f);
return NULL;
}

((MOD_FILE *)stream->extra)->fh = f;

return stream;
}

Expand All @@ -406,7 +459,7 @@ ALLEGRO_AUDIO_STREAM *_al_load_xm_audio_stream(const char *filename,
ALLEGRO_FILE *f;
ALLEGRO_AUDIO_STREAM *stream;
ASSERT(filename);

f = al_fopen(filename, "rb");
if (!f)
return NULL;
Expand All @@ -419,7 +472,7 @@ ALLEGRO_AUDIO_STREAM *_al_load_xm_audio_stream(const char *filename,
}

((MOD_FILE *)stream->extra)->fh = f;

return stream;
}

Expand All @@ -429,20 +482,20 @@ ALLEGRO_AUDIO_STREAM *_al_load_s3m_audio_stream(const char *filename,
ALLEGRO_FILE *f;
ALLEGRO_AUDIO_STREAM *stream;
ASSERT(filename);

f = al_fopen(filename, "rb");
if (!f)
return NULL;

stream = _al_load_s3m_audio_stream_f(f, buffer_count, samples);

if (!stream) {
al_fclose(f);
return NULL;
}

((MOD_FILE *)stream->extra)->fh = f;

return stream;
}

Expand All @@ -452,34 +505,35 @@ ALLEGRO_AUDIO_STREAM *_al_load_mod_audio_stream_f(ALLEGRO_FILE *f,
if (!init_libdumb())
return NULL;

return mod_stream_init(f, buffer_count, samples, lib.dumb_read_mod);
#if ((DUMB_MAJOR_VERSION) >= 1)
return stream_init(f, buffer_count, samples, NULL, lib.dumb_read_mod);
#else
return stream_init(f, buffer_count, samples, lib.dumb_read_mod, NULL);
#endif
}

ALLEGRO_AUDIO_STREAM *_al_load_it_audio_stream_f(ALLEGRO_FILE *f,
size_t buffer_count, unsigned int samples)
{
if (!init_libdumb())
return NULL;

return mod_stream_init(f, buffer_count, samples, lib.dumb_read_it);
return stream_init(f, buffer_count, samples, lib.dumb_read_it, NULL);
}

ALLEGRO_AUDIO_STREAM *_al_load_xm_audio_stream_f(ALLEGRO_FILE *f,
size_t buffer_count, unsigned int samples)
{
if (!init_libdumb())
return NULL;

return mod_stream_init(f, buffer_count, samples, lib.dumb_read_xm);
return stream_init(f, buffer_count, samples, lib.dumb_read_xm, NULL);
}

ALLEGRO_AUDIO_STREAM *_al_load_s3m_audio_stream_f(ALLEGRO_FILE *f,
size_t buffer_count, unsigned int samples)
{
if (!init_libdumb())
return NULL;

return mod_stream_init(f, buffer_count, samples, lib.dumb_read_s3m);
return stream_init(f, buffer_count, samples, lib.dumb_read_s3m, NULL);
}

/* vim: set sts=3 sw=3 et: */

0 comments on commit 34ba82f

Please sign in to comment.