diff --git a/addons/acodec/modaudio.c b/addons/acodec/modaudio.c index 358b5445a6..3d9a5c64b8 100644 --- a/addons/acodec/modaudio.c +++ b/addons/acodec/modaudio.c @@ -3,7 +3,6 @@ * author: Matthew Leverton */ - #define _FILE_OFFSET_BITS 64 #include "allegro5/allegro.h" #include "allegro5/allegro_acodec.h" @@ -176,10 +175,20 @@ static size_t modaudio_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data, } while (written < buf_size) { + long size_to_read = (buf_size - written) / sample_size; + long position = lib.duh_sigrenderer_get_position(df->sig); + bool loop = false; + if (stream->spl.loop != _ALLEGRO_PLAYMODE_STREAM_ONCE && df->loop_end != -1 && + position + 65536 * size_to_read / 44100 >= df->loop_end) { + size_to_read = (df->loop_end - position) * 44100 / 65536; + if (size_to_read < 0) + size_to_read = 0; + loop = true; + } written += lib.duh_render(df->sig, 16, 0, 1.0, 65536.0 / 44100.0, - (buf_size - written) / sample_size, &(((char *)data)[written])) * sample_size; - if (stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONCE) { - break; + size_to_read, &(((char *)data)[written])) * sample_size; + if (loop || (long)written < size_to_read * sample_size) { + break; } } @@ -213,6 +222,10 @@ static bool modaudio_stream_seek(ALLEGRO_AUDIO_STREAM *stream, double time) { MOD_FILE *const df = stream->extra; + if (df->loop_end != -1 && (long)(time * 65336) > df->loop_end) { + return false; + } + lib.duh_end_sigrenderer(df->sig); df->sig = lib.duh_start_sigrenderer(df->duh, 0, 2, time * 65536); @@ -306,10 +319,15 @@ static ALLEGRO_AUDIO_STREAM *modaudio_stream_init(ALLEGRO_FILE* f, mf->sig = sig; mf->fh = NULL; mf->length = lib.duh_get_length(duh) / 65536.0; - if (mf->length < 0) + if (mf->length < 0) { mf->length = 0; - mf->loop_start = -1; - mf->loop_end = -1; + mf->loop_start = -1; + mf->loop_end = -1; + } + else { + mf->loop_start = 0; + mf->loop_end = (int)(mf->length * 65536.0); + } stream->extra = mf; stream->feeder = modaudio_stream_update; @@ -471,6 +489,118 @@ static ALLEGRO_AUDIO_STREAM *load_dumb_audio_stream(const char *filename, return stream; } +static bool _al_identify_669(ALLEGRO_FILE *f) +{ + uint8_t x[2]; + if (al_fread(f, x, 2) < 2) + return false; + if (memcmp(x, "if", 2) == 0 || memcmp(x, "JN", 2) == 0) + return true; + return false; +} + +static bool _al_identify_amf(ALLEGRO_FILE *f) +{ + uint8_t x[3]; + if (al_fread(f, x, 3) < 3) + return false; + if (memcmp(x, "AMF", 3) == 0) + return true; + return false; +} + +static bool _al_identify_asy(ALLEGRO_FILE *f) +{ + uint8_t x[24]; + if (al_fread(f, x, 24) < 24) + return false; + if (memcmp(x, "ASYLUM Music Format V1.0", 24) == 0) + return true; + return false; +} + +static bool _al_identify_mtm(ALLEGRO_FILE *f) +{ + uint8_t x[3]; + if (al_fread(f, x, 3) < 3) + return false; + if (memcmp(x, "MTM", 3) == 0) + return true; + return false; +} + +static bool _al_identify_okt(ALLEGRO_FILE *f) +{ + uint8_t x[8]; + if (al_fread(f, x, 8) < 8) + return false; + if (memcmp(x, "OKTASONG", 8) == 0) + return true; + return false; +} + +static bool _al_identify_psm(ALLEGRO_FILE *f) +{ + uint8_t x[4]; + if (al_fread(f, x, 4) < 4) + return false; + if (memcmp(x, "PSM\x00", 4) == 0 || memcmp(x, "PSM\xFE", 4) == 0) + return true; + return false; +} + +static bool _al_identify_ptm(ALLEGRO_FILE *f) +{ + uint8_t x[4]; + if (!al_fseek(f, 0x2C, ALLEGRO_SEEK_CUR)) + return false; + if (al_fread(f, x, 4) < 4) + return false; + if (memcmp(x, "DSMF", 4) == 0) + return true; + return false; +} + +static bool _al_identify_riff(ALLEGRO_FILE *f) +{ + static const char riff_fmts[][4] = { + "AM ", "AMFF", "DSMF" + }; + uint8_t x[4]; + if (al_fread(f, x, 4) < 4) + return false; + if (memcmp(x, "RIFF", 4) != 0) + return false; + if (!al_fseek(f, 4, ALLEGRO_SEEK_CUR)) + return false; + if (al_fread(f, x, 4) < 4) + return false; + for (size_t i = 0; i < sizeof(riff_fmts) / 4; ++i) { + if (memcmp(x, riff_fmts[i], 4) == 0) + return true; + } + return false; +} + +static bool _al_identify_stm(ALLEGRO_FILE *f) +{ + static const char stm_fmts[][8] = { + "!Scream!", "BMOD2STM", "WUZAMOD!" + }; + uint8_t x[10]; + if (!al_fseek(f, 20, ALLEGRO_SEEK_CUR)) + return false; + if (al_fread(f, x, 10) < 8) + return false; + if (x[9] != 2) + return false; + for (size_t i = 0; i < sizeof(stm_fmts) / 8; ++i) { + if (memcmp(x, stm_fmts[i], 8) == 0) + return true; + } + return false; +} + #else /* * For DUMB 0.9.3: @@ -614,6 +744,64 @@ static ALLEGRO_AUDIO_STREAM *load_s3m_audio_stream(const char *filename, #endif // DUMB_MAJOR_VERSION +static bool _al_identify_it(ALLEGRO_FILE *f) +{ + uint8_t x[4]; + if (al_fread(f, x, 4) < 4) + return false; + if (memcmp(x, "IMPM", 4) == 0) + return true; + return false; +} + +static bool _al_identify_mod(ALLEGRO_FILE *f) +{ + static const char mod_sigs[][4] = { + "M.K.", "M!K!", "M&K!", "N.T.", + "NSMS", "FLT4", "M\0\0\0", "8\0\0\0", + "FEST", "FLT8", "CD81", "OCTA", + "OKTA", "16CN", "32CN" + }; + uint8_t x[4]; + if (!al_fseek(f, 0x438, ALLEGRO_SEEK_CUR)) + return false; + if (al_fread(f, x, 4) < 4) + return false; + for (size_t i = 0; i < sizeof(mod_sigs) / 4; ++i) { + if (memcmp(x, mod_sigs[i], 4) == 0) + return true; + } + if (memcmp(x + 2, "CH", 2) == 0 && isdigit(x[0]) && isdigit(x[1])) /* ##CH */ + return true; + if (memcmp(x + 1, "CHN", 3) == 0 && isdigit(x[0])) /* #CHN */ + return true; + if (memcmp(x, "TDZ", 3) == 0 && isdigit(x[3])) /* TDZ? */ + return true; + return false; +} + +static bool _al_identify_s3m(ALLEGRO_FILE *f) +{ + uint8_t x[4]; + if (!al_fseek(f, 0x2C, ALLEGRO_SEEK_CUR)) + return false; + if (al_fread(f, x, 4) < 4) + return false; + if (memcmp(x, "SCRM", 4) == 0) + return true; + return false; +} + +static bool _al_identify_xm(ALLEGRO_FILE *f) +{ + uint8_t x[16]; + if (al_fread(f, x, 16) < 16) + return false; + if (memcmp(x, "Extended Module:", 16) == 0) + return true; + return false; +} + bool _al_register_dumb_loaders(void) { bool ret = true; @@ -626,30 +814,43 @@ bool _al_register_dumb_loaders(void) */ ret &= al_register_audio_stream_loader(".669", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".669", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".669", _al_identify_669); ret &= al_register_audio_stream_loader(".amf", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".amf", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".amf", _al_identify_amf); ret &= al_register_audio_stream_loader(".asy", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".asy", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".asy", _al_identify_asy); ret &= al_register_audio_stream_loader(".it", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".it", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".it", _al_identify_it); ret &= al_register_audio_stream_loader(".mod", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".mod", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".mod", _al_identify_mod); ret &= al_register_audio_stream_loader(".mtm", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".mtm", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".mtm", _al_identify_mtm); ret &= al_register_audio_stream_loader(".okt", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".okt", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".okt", _al_identify_okt); ret &= al_register_audio_stream_loader(".psm", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".psm", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".psm", _al_identify_psm); ret &= al_register_audio_stream_loader(".ptm", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".ptm", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".ptm", _al_identify_ptm); ret &= al_register_audio_stream_loader(".riff", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".riff", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".riff", _al_identify_riff); ret &= al_register_audio_stream_loader(".s3m", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".s3m", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".s3m", _al_identify_s3m); ret &= al_register_audio_stream_loader(".stm", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".stm", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".stm", _al_identify_stm); ret &= al_register_audio_stream_loader(".xm", load_dumb_audio_stream); ret &= al_register_audio_stream_loader_f(".xm", load_dumb_audio_stream_f); + ret &= al_register_sample_identifier(".xm", _al_identify_xm); #else /* * DUMB 0.9.3 supported only these 4 formats and had no *_any loader. @@ -658,12 +859,16 @@ bool _al_register_dumb_loaders(void) */ ret &= al_register_audio_stream_loader(".xm", load_xm_audio_stream); ret &= al_register_audio_stream_loader_f(".xm", load_xm_audio_stream_f); + ret &= al_register_sample_identifier(".xm", _al_identify_xm); ret &= al_register_audio_stream_loader(".it", load_it_audio_stream); ret &= al_register_audio_stream_loader_f(".it", load_it_audio_stream_f); + ret &= al_register_sample_identifier(".it", _al_identify_it); ret &= al_register_audio_stream_loader(".mod", load_mod_audio_stream); ret &= al_register_audio_stream_loader_f(".mod", load_mod_audio_stream_f); + ret &= al_register_sample_identifier(".mod", _al_identify_mod); ret &= al_register_audio_stream_loader(".s3m", load_s3m_audio_stream); ret &= al_register_audio_stream_loader_f(".s3m", load_s3m_audio_stream_f); + ret &= al_register_sample_identifier(".s3m", _al_identify_s3m); #endif // DUMB_MAJOR_VERSION return ret; } diff --git a/docs/src/refman/utf8.txt b/docs/src/refman/utf8.txt index b600f024ee..1d3e120e0d 100644 --- a/docs/src/refman/utf8.txt +++ b/docs/src/refman/utf8.txt @@ -227,7 +227,7 @@ pointed to by the `info` parameter. The string will not have any other storage allocated of its own, so if you allocate the `info` structure on the stack then no explicit "free" operation is required. -The string is valid until the underlying C string disappears. +The result of string and info is valid until the underlying C string disappears. Example: @@ -245,7 +245,7 @@ Create a string that references the storage of an underlying buffer. The size of the buffer is given in bytes. You can use it to reference only part of a string or an arbitrary region of memory. -The string is valid while the underlying memory buffer is valid. +The result of string and info is valid while the underlying memory buffer is valid. See also: [al_ref_cstr], [al_ref_ustr] @@ -261,7 +261,7 @@ stack then no explicit "free" operation is required. The referenced interval is \[`start_pos`, `end_pos`). Both are byte offsets. -The string is valid until the underlying string is modified or destroyed. +The result of string and info is valid until the underlying string is modified or destroyed. If you need a range of code-points instead of bytes, use [al_ustr_offset] to find the byte offsets.