From 9e25b44e1ff5f6ce20d921d7d7d59dac15bc5358 Mon Sep 17 00:00:00 2001 From: LunaTheFoxgirl Date: Mon, 29 Nov 2021 01:15:05 +0100 Subject: [PATCH 1/3] Various tracker module features --- source/audioformats/pocketmod.d | 8 ++ source/audioformats/stream.d | 139 ++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) diff --git a/source/audioformats/pocketmod.d b/source/audioformats/pocketmod.d index cb696b8..18ced15 100644 --- a/source/audioformats/pocketmod.d +++ b/source/audioformats/pocketmod.d @@ -892,6 +892,14 @@ int pocketmod_render(pocketmod_context *c, void *buffer, int buffer_size) return samples_rendered * POCKETMOD_SAMPLE_SIZE; } +void pocketmod_seek(pocketmod_context* c, ubyte pattern, ubyte row, ushort tick) { + // NOTE: This is untested. + c.line = row; + c.pattern = pattern; + c.tick = tick; + c.sample = 0; +} + int pocketmod_loop_count(pocketmod_context *c) { return c.loop_count; diff --git a/source/audioformats/stream.d b/source/audioformats/stream.d index 74d2962..0e2cac1 100644 --- a/source/audioformats/stream.d +++ b/source/audioformats/stream.d @@ -609,6 +609,145 @@ public: // This is also part of the public API return writeSamplesFloat(inData.ptr, cast(int)(inData.length / _numChannels)); } + /// Length. Returns the amount of patterns in the module + /// Formats that support this: MOD, XM + int countModulePattern() { + assert(_io && (_io.read !is null) ); + final switch(_format) with (AudioFileFormat) + { + case mp3: + case flac: + case ogg: + case opus: + case wav: + case unknown: + assert(false); + case mod: + return _modDecoder.num_patterns; + case xm: + return xm_get_number_of_patterns(_xmDecoder); + } + } + + /// Tell. Returns amount of rows in a pattern. + /// Formats that support this: MOD, XM + int rowsInPattern(int pattern) { + assert(_io && (_io.read !is null) ); + final switch(_format) with (AudioFileFormat) + { + case mp3: + case flac: + case ogg: + case opus: + case wav: + case unknown: + assert(false); + case mod: + // According to http://lclevy.free.fr/mo3/mod.txt + // there's 64 lines (aka rows) per pattern. + // TODO: error checking, make sure no out of bounds happens. + return 64; + case xm: + // TODO: error checking, make sure no out of bounds happens. + return xm_get_number_of_rows(_xmDecoder, pattern); + } + } + + /// Tell. Returns the current playing pattern id + /// Formats that support this: MOD, XM + int tellModulePattern() { + assert(_io && (_io.read !is null) ); + final switch(_format) with (AudioFileFormat) + { + case mp3: + case flac: + case ogg: + case opus: + case wav: + case unknown: + assert(false); + case mod: + return _modDecoder.pattern; + case xm: + return _xmDecoder.current_table_index; + } + } + + /// Tell. Returns the current playing row id + /// Formats that support this: MOD, XM + int tellModuleRow() { + assert(_io && (_io.read !is null) ); + final switch(_format) with (AudioFileFormat) + { + case mp3: + case flac: + case ogg: + case opus: + case wav: + case unknown: + assert(false); + case mod: + return _modDecoder.line; + case xm: + return _xmDecoder.current_row; + } + } + + /// Playback info. Returns the amount of samples remaining in the current playing pattern + /// Formats that support this: MOD + long samplesRemainingInPattern() { + assert(_io && (_io.read !is null) ); + final switch(_format) with (AudioFileFormat) + { + case mp3: + case flac: + case ogg: + case opus: + case wav: + case unknown: + assert(false); + case mod: + + // According to http://lclevy.free.fr/mo3/mod.txt + // there's 64 lines (aka rows) per pattern. + int rows = 64; + + // NOTE: This is untested. + long samplesPerLine = cast(int)(cast(float)_modDecoder.ticks_per_line*_modDecoder.samples_per_tick); + return cast(long)(rows-_modDecoder.line)*samplesPerLine; + + case xm: + return 0; // NOT IMPLEMENTED + } + } + + /// Seeking. Subsequent reads start from pattern + row, 0 index + /// Only available for input streams. + /// Formats that support seeking per pattern/row: MOD, XM + bool seekPosition(int pattern, int row) { + assert(_io && (_io.read !is null) ); + final switch(_format) with (AudioFileFormat) + { + case mp3: + case flac: + case ogg: + case opus: + case wav: + case unknown: + assert(false); + case mod: + + // NOTE: This is untested. + pocketmod_seek(_modDecoder, pattern, row, 0); + return true; + case xm: + + xm_seek(_xmDecoder, cast(ubyte)pattern, cast(ubyte)row, 0); + return true; + + } + } + /// Seeking. Subsequent reads start from multi-channel frame index `frames`. /// Only available for input streams. /// Formats that support seeking: WAV, MP3, OGG, FLAC. From ec777be79d7b3e8c6fc4ab57b7d38f8de45de3aa Mon Sep 17 00:00:00 2001 From: LunaTheFoxgirl Date: Mon, 29 Nov 2021 01:21:19 +0100 Subject: [PATCH 2/3] Fix name of countModulePatterns --- source/audioformats/stream.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/audioformats/stream.d b/source/audioformats/stream.d index 0e2cac1..3e279a0 100644 --- a/source/audioformats/stream.d +++ b/source/audioformats/stream.d @@ -611,7 +611,7 @@ public: // This is also part of the public API /// Length. Returns the amount of patterns in the module /// Formats that support this: MOD, XM - int countModulePattern() { + int countModulePatterns() { assert(_io && (_io.read !is null) ); final switch(_format) with (AudioFileFormat) { @@ -741,7 +741,7 @@ public: // This is also part of the public API pocketmod_seek(_modDecoder, pattern, row, 0); return true; case xm: - + xm_seek(_xmDecoder, cast(ubyte)pattern, cast(ubyte)row, 0); return true; From af4bb2ac57974a79f34cfcc5e3d0c480f95af5ec Mon Sep 17 00:00:00 2001 From: LunaTheFoxgirl Date: Mon, 29 Nov 2021 01:26:05 +0100 Subject: [PATCH 3/3] Add getModuleLength --- source/audioformats/stream.d | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/source/audioformats/stream.d b/source/audioformats/stream.d index 3e279a0..452ea93 100644 --- a/source/audioformats/stream.d +++ b/source/audioformats/stream.d @@ -629,6 +629,26 @@ public: // This is also part of the public API } } + /// Length. Returns the amount of PLAYED patterns in the module + /// Formats that support this: MOD, XM + int getModuleLength() { + assert(_io && (_io.read !is null) ); + final switch(_format) with (AudioFileFormat) + { + case mp3: + case flac: + case ogg: + case opus: + case wav: + case unknown: + assert(false); + case mod: + return _modDecoder.length; + case xm: + return xm_get_module_length(_xmDecoder); + } + } + /// Tell. Returns amount of rows in a pattern. /// Formats that support this: MOD, XM int rowsInPattern(int pattern) {