diff options
Diffstat (limited to 'plugins/dumb/dumb-kode54/src')
83 files changed, 17270 insertions, 17212 deletions
diff --git a/plugins/dumb/dumb-kode54/src/allegro/alplay.c b/plugins/dumb/dumb-kode54/src/allegro/alplay.c index 85e2079a..761ae36a 100644 --- a/plugins/dumb/dumb-kode54/src/allegro/alplay.c +++ b/plugins/dumb/dumb-kode54/src/allegro/alplay.c @@ -1,277 +1,284 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * alplay.c - Functions to play a DUH through / / \ \
- * an Allegro audio stream. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include <allegro.h>
-
-#include "aldumb.h"
-
-
-
-#define ADP_PLAYING 1
-
-struct AL_DUH_PLAYER
-{
- int flags;
- long bufsize;
- int freq;
- AUDIOSTREAM *stream;
- DUH_SIGRENDERER *sigrenderer; /* If this is NULL, stream is invalid. */
- float volume;
- int silentcount;
-};
-
-
-
-AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, float volume, long bufsize, int freq)
-{
- AL_DUH_PLAYER *dp;
-
- /* This restriction is imposed by Allegro. */
- ASSERT(n_channels > 0);
- ASSERT(n_channels <= 2);
-
- if (!duh)
- return NULL;
-
- dp = malloc(sizeof(*dp));
- if (!dp)
- return NULL;
-
- dp->flags = ADP_PLAYING;
- dp->bufsize = bufsize;
- dp->freq = freq;
-
- dp->stream = play_audio_stream(bufsize, 16, n_channels - 1, freq, 255, 128);
-
- if (!dp->stream) {
- free(dp);
- return NULL;
- }
-
- voice_set_priority(dp->stream->voice, 255);
-
- dp->sigrenderer = duh_start_sigrenderer(duh, 0, n_channels, pos);
-
- if (!dp->sigrenderer) {
- stop_audio_stream(dp->stream);
- free(dp);
- return NULL;
- }
-
- dp->volume = volume;
- dp->silentcount = 0;
-
- return dp;
-}
-
-
-
-void al_stop_duh(AL_DUH_PLAYER *dp)
-{
- if (dp) {
- if (dp->sigrenderer) {
- duh_end_sigrenderer(dp->sigrenderer);
- stop_audio_stream(dp->stream);
- }
- free(dp);
- }
-}
-
-
-
-void al_pause_duh(AL_DUH_PLAYER *dp)
-{
- if (dp && dp->sigrenderer && (dp->flags & ADP_PLAYING)) {
- voice_stop(dp->stream->voice);
- dp->flags &= ~ADP_PLAYING;
- }
-}
-
-
-
-void al_resume_duh(AL_DUH_PLAYER *dp)
-{
- if (dp && dp->sigrenderer && !(dp->flags & ADP_PLAYING)) {
- voice_start(dp->stream->voice);
- dp->flags |= ADP_PLAYING;
- }
-}
-
-
-
-void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority)
-{
- if (dp && dp->sigrenderer)
- voice_set_priority(dp->stream->voice, priority);
-}
-
-
-
-void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume)
-{
- if (dp)
- dp->volume = volume;
-}
-
-
-
-float al_duh_get_volume(AL_DUH_PLAYER *dp)
-{
- return dp ? dp->volume : 0;
-}
-
-
-
-int al_poll_duh(AL_DUH_PLAYER *dp)
-{
- unsigned short *sptr;
- long n;
- long size;
- int n_channels;
-
- if (!dp || !dp->sigrenderer)
- return 1;
-
- if (!(dp->flags & ADP_PLAYING))
- return 0;
-
- sptr = get_audio_stream_buffer(dp->stream);
-
- if (!sptr)
- return 0;
-
- n = duh_render(dp->sigrenderer, 16, 1, dp->volume, 65536.0 / dp->freq, dp->bufsize, sptr);
-
- if (n == 0) {
- if (++dp->silentcount >= 2) {
- duh_end_sigrenderer(dp->sigrenderer);
- free_audio_stream_buffer(dp->stream);
- stop_audio_stream(dp->stream);
- dp->sigrenderer = NULL;
- return 1;
- }
- }
-
- n_channels = duh_sigrenderer_get_n_channels(dp->sigrenderer);
- n *= n_channels;
- size = dp->bufsize * n_channels;
- for (; n < size; n++)
- sptr[n] = 0x8000;
-
- free_audio_stream_buffer(dp->stream);
-
- return 0;
-}
-
-
-
-long al_duh_get_position(AL_DUH_PLAYER *dp)
-{
- return dp ? duh_sigrenderer_get_position(dp->sigrenderer) : -1;
-}
-
-
-
-AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq)
-{
- AL_DUH_PLAYER *dp;
- int n_channels;
-
- if (!sigrenderer)
- return NULL;
-
- dp = malloc(sizeof(*dp));
- if (!dp)
- return NULL;
-
- n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
-
- /* This restriction is imposed by Allegro. */
- ASSERT(n_channels > 0);
- ASSERT(n_channels <= 2);
-
- dp->flags = ADP_PLAYING;
- dp->bufsize = bufsize;
- dp->freq = freq;
-
- dp->stream = play_audio_stream(bufsize, 16, n_channels - 1, freq, 255, 128);
-
- if (!dp->stream) {
- free(dp);
- return NULL;
- }
-
- voice_set_priority(dp->stream->voice, 255);
-
- dp->sigrenderer = sigrenderer;
-
- dp->volume = volume;
- dp->silentcount = 0;
-
- return dp;
-}
-
-
-
-DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp)
-{
- return dp ? dp->sigrenderer : NULL;
-}
-
-
-
-/* IMPORTANT: This function will return NULL if the music has ended. */
-// Should this be changed? User might want to hack the underlying SIGRENDERER
-// and resurrect it (e.g. change pattern number), before it gets destroyed...
-DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp)
-{
- if (dp) {
- DUH_SIGRENDERER *sigrenderer = dp->sigrenderer;
- if (sigrenderer) stop_audio_stream(dp->stream);
- free(dp);
- return sigrenderer;
- }
- return NULL;
-}
-
-
-
-/* DEPRECATED */
-AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_SIGRENDERER *dr, float volume, long bufsize, int freq)
-{
- return al_duh_encapsulate_sigrenderer(dr, volume, bufsize, freq);
-}
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp)
-{
- return al_duh_get_sigrenderer(dp);
-}
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp)
-{
- return al_duh_decompose_to_sigrenderer(dp);
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * alplay.c - Functions to play a DUH through / / \ \ + * an Allegro audio stream. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> + +#include <allegro.h> + +#include "aldumb.h" + + + +#define ADP_PLAYING 1 + +struct AL_DUH_PLAYER +{ + int flags; + long bufsize; + int freq; + AUDIOSTREAM *stream; + DUH_SIGRENDERER *sigrenderer; /* If this is NULL, stream is invalid. */ + float volume; + int silentcount; +}; + + + +AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, float volume, long bufsize, int freq) +{ + AL_DUH_PLAYER *dp; + + /* This restriction is imposed by Allegro. */ + ASSERT(n_channels > 0); + ASSERT(n_channels <= 2); + + if (!duh) + return NULL; + + dp = malloc(sizeof(*dp)); + if (!dp) + return NULL; + + dp->flags = ADP_PLAYING; + dp->bufsize = bufsize; + dp->freq = freq; + + dp->stream = play_audio_stream(bufsize, 16, n_channels - 1, freq, 255, 128); + + if (!dp->stream) { + free(dp); + return NULL; + } + + voice_set_priority(dp->stream->voice, 255); + + dp->sigrenderer = duh_start_sigrenderer(duh, 0, n_channels, pos); + + if (!dp->sigrenderer) { + stop_audio_stream(dp->stream); + free(dp); + return NULL; + } + + dp->volume = volume; + dp->silentcount = 0; + + return dp; +} + + + +void al_stop_duh(AL_DUH_PLAYER *dp) +{ + if (dp) { + if (dp->sigrenderer) { + duh_end_sigrenderer(dp->sigrenderer); + stop_audio_stream(dp->stream); + } + free(dp); + } +} + + + +void al_pause_duh(AL_DUH_PLAYER *dp) +{ + if (dp && dp->sigrenderer && (dp->flags & ADP_PLAYING)) { + voice_stop(dp->stream->voice); + dp->flags &= ~ADP_PLAYING; + } +} + + + +void al_resume_duh(AL_DUH_PLAYER *dp) +{ + if (dp && dp->sigrenderer && !(dp->flags & ADP_PLAYING)) { + voice_start(dp->stream->voice); + dp->flags |= ADP_PLAYING; + } +} + + + +void al_duh_set_priority(AL_DUH_PLAYER *dp, int priority) +{ + if (dp && dp->sigrenderer) + voice_set_priority(dp->stream->voice, priority); +} + + + +void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume) +{ + if (dp) + dp->volume = volume; +} + + + +float al_duh_get_volume(AL_DUH_PLAYER *dp) +{ + return dp ? dp->volume : 0; +} + + + +float al_duh_get_volume(AL_DUH_PLAYER *dp) +{ + return dp ? dp->volume : 0; +} + + + +int al_poll_duh(AL_DUH_PLAYER *dp) +{ + unsigned short *sptr; + long n; + long size; + int n_channels; + + if (!dp || !dp->sigrenderer) + return 1; + + if (!(dp->flags & ADP_PLAYING)) + return 0; + + sptr = get_audio_stream_buffer(dp->stream); + + if (!sptr) + return 0; + + n = duh_render(dp->sigrenderer, 16, 1, dp->volume, 65536.0 / dp->freq, dp->bufsize, sptr); + + if (n == 0) { + if (++dp->silentcount >= 2) { + duh_end_sigrenderer(dp->sigrenderer); + free_audio_stream_buffer(dp->stream); + stop_audio_stream(dp->stream); + dp->sigrenderer = NULL; + return 1; + } + } + + n_channels = duh_sigrenderer_get_n_channels(dp->sigrenderer); + n *= n_channels; + size = dp->bufsize * n_channels; + for (; n < size; n++) + sptr[n] = 0x8000; + + free_audio_stream_buffer(dp->stream); + + return 0; +} + + + +long al_duh_get_position(AL_DUH_PLAYER *dp) +{ + return dp ? duh_sigrenderer_get_position(dp->sigrenderer) : -1; +} + + + +AL_DUH_PLAYER *al_duh_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer, float volume, long bufsize, int freq) +{ + AL_DUH_PLAYER *dp; + int n_channels; + + if (!sigrenderer) + return NULL; + + dp = malloc(sizeof(*dp)); + if (!dp) + return NULL; + + n_channels = duh_sigrenderer_get_n_channels(sigrenderer); + + /* This restriction is imposed by Allegro. */ + ASSERT(n_channels > 0); + ASSERT(n_channels <= 2); + + dp->flags = ADP_PLAYING; + dp->bufsize = bufsize; + dp->freq = freq; + + dp->stream = play_audio_stream(bufsize, 16, n_channels - 1, freq, 255, 128); + + if (!dp->stream) { + free(dp); + return NULL; + } + + voice_set_priority(dp->stream->voice, 255); + + dp->sigrenderer = sigrenderer; + + dp->volume = volume; + dp->silentcount = 0; + + return dp; +} + + + +DUH_SIGRENDERER *al_duh_get_sigrenderer(AL_DUH_PLAYER *dp) +{ + return dp ? dp->sigrenderer : NULL; +} + + + +/* IMPORTANT: This function will return NULL if the music has ended. */ +// Should this be changed? User might want to hack the underlying SIGRENDERER +// and resurrect it (e.g. change pattern number), before it gets destroyed... +DUH_SIGRENDERER *al_duh_decompose_to_sigrenderer(AL_DUH_PLAYER *dp) +{ + if (dp) { + DUH_SIGRENDERER *sigrenderer = dp->sigrenderer; + if (sigrenderer) stop_audio_stream(dp->stream); + free(dp); + return sigrenderer; + } + return NULL; +} + + + +/* DEPRECATED */ +AL_DUH_PLAYER *al_duh_encapsulate_renderer(DUH_SIGRENDERER *dr, float volume, long bufsize, int freq) +{ + return al_duh_encapsulate_sigrenderer(dr, volume, bufsize, freq); +} + + + +/* DEPRECATED */ +DUH_SIGRENDERER *al_duh_get_renderer(AL_DUH_PLAYER *dp) +{ + return al_duh_get_sigrenderer(dp); +} + + + +/* DEPRECATED */ +DUH_SIGRENDERER *al_duh_decompose_to_renderer(AL_DUH_PLAYER *dp) +{ + return al_duh_decompose_to_sigrenderer(dp); +} diff --git a/plugins/dumb/dumb-kode54/src/allegro/datduh.c b/plugins/dumb/dumb-kode54/src/allegro/datduh.c index 5dec3975..672e3c82 100644 --- a/plugins/dumb/dumb-kode54/src/allegro/datduh.c +++ b/plugins/dumb/dumb-kode54/src/allegro/datduh.c @@ -1,60 +1,60 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * datduh.c - Integration with Allegro's / / \ \
- * datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-static void *dat_read_duh(PACKFILE *f, long size)
-{
- DUMBFILE *df;
- DUH *duh;
-
- (void)size;
-
- df = dumbfile_open_packfile(f);
-
- if (!df)
- return NULL;
-
- duh = read_duh(df);
-
- dumbfile_close(df);
-
- return duh;
-}
-
-
-
-/* dumb_register_dat_duh(): tells Allegro about the DUH datafile object. If
- * you intend to load a datafile containing a DUH object, you must call this
- * function first. It is recommended you pass DAT_DUH, but you may have a
- * reason to use a different type (apart from pride, that doesn't count).
- */
-void dumb_register_dat_duh(long type)
-{
- register_datafile_object(
- type,
- &dat_read_duh,
- &_dat_unload_duh
- );
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * datduh.c - Integration with Allegro's / / \ \ + * datafiles. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <allegro.h> + +#include "aldumb.h" +#include "internal/aldumb.h" + + + +static void *dat_read_duh(PACKFILE *f, long size) +{ + DUMBFILE *df; + DUH *duh; + + (void)size; + + df = dumbfile_open_packfile(f); + + if (!df) + return NULL; + + duh = read_duh(df); + + dumbfile_close(df); + + return duh; +} + + + +/* dumb_register_dat_duh(): tells Allegro about the DUH datafile object. If + * you intend to load a datafile containing a DUH object, you must call this + * function first. It is recommended you pass DAT_DUH, but you may have a + * reason to use a different type (apart from pride, that doesn't count). + */ +void dumb_register_dat_duh(long type) +{ + register_datafile_object( + type, + &dat_read_duh, + &_dat_unload_duh + ); +} diff --git a/plugins/dumb/dumb-kode54/src/allegro/datit.c b/plugins/dumb/dumb-kode54/src/allegro/datit.c index 1a6ce2f6..8f58f142 100644 --- a/plugins/dumb/dumb-kode54/src/allegro/datit.c +++ b/plugins/dumb/dumb-kode54/src/allegro/datit.c @@ -1,62 +1,62 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * datit.c - Integration of IT files with / / \ \
- * Allegro's datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-static void *dat_read_it(PACKFILE *f, long size)
-{
- DUMBFILE *df;
- DUH *duh;
-
- (void)size;
-
- df = dumbfile_open_packfile(f);
-
- if (!df)
- return NULL;
-
- duh = dumb_read_it(df);
-
- dumbfile_close(df);
-
- return duh;
-}
-
-
-
-/* dumb_register_dat_it(): tells Allegro about the IT datafile object. If you
- * intend to load a datafile containing an IT object, you must call this
- * function first. It is recommended you pass DUMB_DAT_IT, but you may have a
- * reason to use a different type (perhaps you already have a datafile with
- * IT files in and they use a different type).
- */
-void dumb_register_dat_it(long type)
-{
- register_datafile_object(
- type,
- &dat_read_it,
- &_dat_unload_duh
- );
-}
-
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * datit.c - Integration of IT files with / / \ \ + * Allegro's datafiles. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <allegro.h> + +#include "aldumb.h" +#include "internal/aldumb.h" + + + +static void *dat_read_it(PACKFILE *f, long size) +{ + DUMBFILE *df; + DUH *duh; + + (void)size; + + df = dumbfile_open_packfile(f); + + if (!df) + return NULL; + + duh = dumb_read_it(df); + + dumbfile_close(df); + + return duh; +} + + + +/* dumb_register_dat_it(): tells Allegro about the IT datafile object. If you + * intend to load a datafile containing an IT object, you must call this + * function first. It is recommended you pass DUMB_DAT_IT, but you may have a + * reason to use a different type (perhaps you already have a datafile with + * IT files in and they use a different type). + */ +void dumb_register_dat_it(long type) +{ + register_datafile_object( + type, + &dat_read_it, + &_dat_unload_duh + ); +} + diff --git a/plugins/dumb/dumb-kode54/src/allegro/datmod.c b/plugins/dumb/dumb-kode54/src/allegro/datmod.c index abbc1d9a..850b17b4 100644 --- a/plugins/dumb/dumb-kode54/src/allegro/datmod.c +++ b/plugins/dumb/dumb-kode54/src/allegro/datmod.c @@ -1,61 +1,61 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * datmod.c - Integration of MOD files with / / \ \
- * Allegro's datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-static void *dat_read_mod(PACKFILE *f, long size)
-{
- DUMBFILE *df;
- DUH *duh;
-
- (void)size;
-
- df = dumbfile_open_packfile(f);
-
- if (!df)
- return NULL;
-
- duh = dumb_read_mod(df);
-
- dumbfile_close(df);
-
- return duh;
-}
-
-
-
-/* dumb_register_dat_mod(): tells Allegro about the MOD datafile object. If
- * you intend to load a datafile containing a MOD object, you must call this
- * function first. It is recommended you pass DUMB_DAT_MOD, but you may have
- * a reason to use a different type (perhaps you already have a datafile with
- * MOD files in and they use a different type).
- */
-void dumb_register_dat_mod(long type)
-{
- register_datafile_object(
- type,
- &dat_read_mod,
- &_dat_unload_duh
- );
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * datmod.c - Integration of MOD files with / / \ \ + * Allegro's datafiles. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <allegro.h> + +#include "aldumb.h" +#include "internal/aldumb.h" + + + +static void *dat_read_mod(PACKFILE *f, long size) +{ + DUMBFILE *df; + DUH *duh; + + (void)size; + + df = dumbfile_open_packfile(f); + + if (!df) + return NULL; + + duh = dumb_read_mod(df); + + dumbfile_close(df); + + return duh; +} + + + +/* dumb_register_dat_mod(): tells Allegro about the MOD datafile object. If + * you intend to load a datafile containing a MOD object, you must call this + * function first. It is recommended you pass DUMB_DAT_MOD, but you may have + * a reason to use a different type (perhaps you already have a datafile with + * MOD files in and they use a different type). + */ +void dumb_register_dat_mod(long type) +{ + register_datafile_object( + type, + &dat_read_mod, + &_dat_unload_duh + ); +} diff --git a/plugins/dumb/dumb-kode54/src/allegro/dats3m.c b/plugins/dumb/dumb-kode54/src/allegro/dats3m.c index 8fe21666..a0fc7442 100644 --- a/plugins/dumb/dumb-kode54/src/allegro/dats3m.c +++ b/plugins/dumb/dumb-kode54/src/allegro/dats3m.c @@ -1,61 +1,61 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * dats3m.c - Integration of S3M files with / / \ \
- * Allegro's datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-static void *dat_read_s3m(PACKFILE *f, long size)
-{
- DUMBFILE *df;
- DUH *duh;
-
- (void)size;
-
- df = dumbfile_open_packfile(f);
-
- if (!df)
- return NULL;
-
- duh = dumb_read_s3m(df);
-
- dumbfile_close(df);
-
- return duh;
-}
-
-
-
-/* dumb_register_dat_s3m(): tells Allegro about the S3M datafile object. If
- * you intend to load a datafile containing an S3M object, you must call this
- * function first. It is recommended you pass DUMB_DAT_S3M, but you may have
- * a reason to use a different type (perhaps you already have a datafile with
- * S3M files in and they use a different type).
- */
-void dumb_register_dat_s3m(long type)
-{
- register_datafile_object(
- type,
- &dat_read_s3m,
- &_dat_unload_duh
- );
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * dats3m.c - Integration of S3M files with / / \ \ + * Allegro's datafiles. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <allegro.h> + +#include "aldumb.h" +#include "internal/aldumb.h" + + + +static void *dat_read_s3m(PACKFILE *f, long size) +{ + DUMBFILE *df; + DUH *duh; + + (void)size; + + df = dumbfile_open_packfile(f); + + if (!df) + return NULL; + + duh = dumb_read_s3m(df); + + dumbfile_close(df); + + return duh; +} + + + +/* dumb_register_dat_s3m(): tells Allegro about the S3M datafile object. If + * you intend to load a datafile containing an S3M object, you must call this + * function first. It is recommended you pass DUMB_DAT_S3M, but you may have + * a reason to use a different type (perhaps you already have a datafile with + * S3M files in and they use a different type). + */ +void dumb_register_dat_s3m(long type) +{ + register_datafile_object( + type, + &dat_read_s3m, + &_dat_unload_duh + ); +} diff --git a/plugins/dumb/dumb-kode54/src/allegro/datunld.c b/plugins/dumb/dumb-kode54/src/allegro/datunld.c index 68d359fb..71906445 100644 --- a/plugins/dumb/dumb-kode54/src/allegro/datunld.c +++ b/plugins/dumb/dumb-kode54/src/allegro/datunld.c @@ -1,31 +1,31 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * datunld.c - Unload function for integration / / \ \
- * with Allegro's datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-void _dat_unload_duh(void *duh)
-{
- unload_duh(duh);
-}
-
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * datunld.c - Unload function for integration / / \ \ + * with Allegro's datafiles. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <allegro.h> + +#include "aldumb.h" +#include "internal/aldumb.h" + + + +void _dat_unload_duh(void *duh) +{ + unload_duh(duh); +} + diff --git a/plugins/dumb/dumb-kode54/src/allegro/datxm.c b/plugins/dumb/dumb-kode54/src/allegro/datxm.c index ff3ff25a..6cb98d87 100644 --- a/plugins/dumb/dumb-kode54/src/allegro/datxm.c +++ b/plugins/dumb/dumb-kode54/src/allegro/datxm.c @@ -1,62 +1,62 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * datxm.c - Integration of XM files with / / \ \
- * Allegro's datafiles. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-#include "internal/aldumb.h"
-
-
-
-static void *dat_read_xm(PACKFILE *f, long size)
-{
- DUMBFILE *df;
- DUH *duh;
-
- (void)size;
-
- df = dumbfile_open_packfile(f);
-
- if (!df)
- return NULL;
-
- duh = dumb_read_xm(df);
-
- dumbfile_close(df);
-
- return duh;
-}
-
-
-
-/* dumb_register_dat_xm(): tells Allegro about the XM datafile object. If you
- * intend to load a datafile containing an XM object, you must call this
- * function first. It is recommended you pass DUMB_DAT_XM, but you may have a
- * reason to use a different type (perhaps you already have a datafile with
- * XM files in and they use a different type).
- */
-void dumb_register_dat_xm(long type)
-{
- register_datafile_object(
- type,
- &dat_read_xm,
- &_dat_unload_duh
- );
-}
-
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * datxm.c - Integration of XM files with / / \ \ + * Allegro's datafiles. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <allegro.h> + +#include "aldumb.h" +#include "internal/aldumb.h" + + + +static void *dat_read_xm(PACKFILE *f, long size) +{ + DUMBFILE *df; + DUH *duh; + + (void)size; + + df = dumbfile_open_packfile(f); + + if (!df) + return NULL; + + duh = dumb_read_xm(df); + + dumbfile_close(df); + + return duh; +} + + + +/* dumb_register_dat_xm(): tells Allegro about the XM datafile object. If you + * intend to load a datafile containing an XM object, you must call this + * function first. It is recommended you pass DUMB_DAT_XM, but you may have a + * reason to use a different type (perhaps you already have a datafile with + * XM files in and they use a different type). + */ +void dumb_register_dat_xm(long type) +{ + register_datafile_object( + type, + &dat_read_xm, + &_dat_unload_duh + ); +} + diff --git a/plugins/dumb/dumb-kode54/src/allegro/packfile.c b/plugins/dumb/dumb-kode54/src/allegro/packfile.c index 5a07bdb5..525baebd 100644 --- a/plugins/dumb/dumb-kode54/src/allegro/packfile.c +++ b/plugins/dumb/dumb-kode54/src/allegro/packfile.c @@ -1,98 +1,98 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * packfile.c - Packfile input module. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * Note that this does not use file compression; | \ / /
- * for that you must open the file yourself and | ' /
- * then use dumbfile_open_packfile(). \__/
- */
-
-#include <allegro.h>
-
-#include "aldumb.h"
-
-
-
-static void *dumb_packfile_open(const char *filename)
-{
- return pack_fopen(filename, F_READ);
-}
-
-
-
-static int dumb_packfile_skip(void *f, long n)
-{
- return pack_fseek(f, n);
-}
-
-
-
-static int dumb_packfile_getc(void *f)
-{
- return pack_getc(f);
-}
-
-
-
-static long dumb_packfile_getnc(char *ptr, long n, void *f)
-{
- return pack_fread(ptr, n, f);
-}
-
-
-
-static void dumb_packfile_close(void *f)
-{
- pack_fclose(f);
-}
-
-
-
-static DUMBFILE_SYSTEM packfile_dfs = {
- &dumb_packfile_open,
- &dumb_packfile_skip,
- &dumb_packfile_getc,
- &dumb_packfile_getnc,
- &dumb_packfile_close
-};
-
-
-
-void dumb_register_packfiles(void)
-{
- register_dumbfile_system(&packfile_dfs);
-}
-
-
-
-static DUMBFILE_SYSTEM packfile_dfs_leave_open = {
- NULL,
- &dumb_packfile_skip,
- &dumb_packfile_getc,
- &dumb_packfile_getnc,
- NULL
-};
-
-
-
-DUMBFILE *dumbfile_open_packfile(PACKFILE *p)
-{
- return dumbfile_open_ex(p, &packfile_dfs_leave_open);
-}
-
-
-
-DUMBFILE *dumbfile_from_packfile(PACKFILE *p)
-{
- return p ? dumbfile_open_ex(p, &packfile_dfs) : NULL;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * packfile.c - Packfile input module. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * Note that this does not use file compression; | \ / / + * for that you must open the file yourself and | ' / + * then use dumbfile_open_packfile(). \__/ + */ + +#include <allegro.h> + +#include "aldumb.h" + + + +static void *dumb_packfile_open(const char *filename) +{ + return pack_fopen(filename, F_READ); +} + + + +static int dumb_packfile_skip(void *f, long n) +{ + return pack_fseek(f, n); +} + + + +static int dumb_packfile_getc(void *f) +{ + return pack_getc(f); +} + + + +static long dumb_packfile_getnc(char *ptr, long n, void *f) +{ + return pack_fread(ptr, n, f); +} + + + +static void dumb_packfile_close(void *f) +{ + pack_fclose(f); +} + + + +static DUMBFILE_SYSTEM packfile_dfs = { + &dumb_packfile_open, + &dumb_packfile_skip, + &dumb_packfile_getc, + &dumb_packfile_getnc, + &dumb_packfile_close +}; + + + +void dumb_register_packfiles(void) +{ + register_dumbfile_system(&packfile_dfs); +} + + + +static DUMBFILE_SYSTEM packfile_dfs_leave_open = { + NULL, + &dumb_packfile_skip, + &dumb_packfile_getc, + &dumb_packfile_getnc, + NULL +}; + + + +DUMBFILE *dumbfile_open_packfile(PACKFILE *p) +{ + return dumbfile_open_ex(p, &packfile_dfs_leave_open); +} + + + +DUMBFILE *dumbfile_from_packfile(PACKFILE *p) +{ + return p ? dumbfile_open_ex(p, &packfile_dfs) : NULL; +} diff --git a/plugins/dumb/dumb-kode54/src/core/atexit.c b/plugins/dumb/dumb-kode54/src/core/atexit.c index 64814efd..16c6abdb 100644 --- a/plugins/dumb/dumb-kode54/src/core/atexit.c +++ b/plugins/dumb/dumb-kode54/src/core/atexit.c @@ -1,71 +1,71 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * atexit.c - Library Clean-up Management. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-typedef struct DUMB_ATEXIT_PROC
-{
- struct DUMB_ATEXIT_PROC *next;
- void (*proc)(void);
-}
-DUMB_ATEXIT_PROC;
-
-
-
-static DUMB_ATEXIT_PROC *dumb_atexit_proc = NULL;
-
-
-
-int dumb_atexit(void (*proc)(void))
-{
- DUMB_ATEXIT_PROC *dap = dumb_atexit_proc;
-
- while (dap) {
- if (dap->proc == proc) return 0;
- dap = dap->next;
- }
-
- dap = malloc(sizeof(*dap));
-
- if (!dap)
- return -1;
-
- dap->next = dumb_atexit_proc;
- dap->proc = proc;
- dumb_atexit_proc = dap;
-
- return 0;
-}
-
-
-
-void dumb_exit(void)
-{
- while (dumb_atexit_proc) {
- DUMB_ATEXIT_PROC *next = dumb_atexit_proc->next;
- (*dumb_atexit_proc->proc)();
- free(dumb_atexit_proc);
- dumb_atexit_proc = next;
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * atexit.c - Library Clean-up Management. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> + +#include "dumb.h" +#include "internal/dumb.h" + + + +typedef struct DUMB_ATEXIT_PROC +{ + struct DUMB_ATEXIT_PROC *next; + void (*proc)(void); +} +DUMB_ATEXIT_PROC; + + + +static DUMB_ATEXIT_PROC *dumb_atexit_proc = NULL; + + + +int dumb_atexit(void (*proc)(void)) +{ + DUMB_ATEXIT_PROC *dap = dumb_atexit_proc; + + while (dap) { + if (dap->proc == proc) return 0; + dap = dap->next; + } + + dap = malloc(sizeof(*dap)); + + if (!dap) + return -1; + + dap->next = dumb_atexit_proc; + dap->proc = proc; + dumb_atexit_proc = dap; + + return 0; +} + + + +void dumb_exit(void) +{ + while (dumb_atexit_proc) { + DUMB_ATEXIT_PROC *next = dumb_atexit_proc->next; + (*dumb_atexit_proc->proc)(); + free(dumb_atexit_proc); + dumb_atexit_proc = next; + } +} diff --git a/plugins/dumb/dumb-kode54/src/core/duhlen.c b/plugins/dumb/dumb-kode54/src/core/duhlen.c index 2c3a3576..3cfa8d88 100644 --- a/plugins/dumb/dumb-kode54/src/core/duhlen.c +++ b/plugins/dumb/dumb-kode54/src/core/duhlen.c @@ -1,42 +1,45 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * duhlen.c - Functions to set and return the / / \ \
- * length of a DUH. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * Note that the length of a DUH is a constant | ' /
- * stored in the DUH struct and in the DUH disk \__/
- * format. It will be calculated on loading for
- * other formats in which the length is not explicitly stored. Also note that
- * it does not necessarily correspond to the length of time for which the DUH
- * will generate samples. Rather it represents a suitable point for a player
- * such as Winamp to stop, and in any good DUH it will allow for any final
- * flourish to fade out and be appreciated.
- */
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-long duh_get_length(DUH *duh)
-{
- return duh ? duh->length : 0;
-}
-
-
-
-void duh_set_length(DUH *duh, long length)
-{
- if (duh)
- duh->length = length;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * duhlen.c - Functions to set and return the / / \ \ + * length of a DUH. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * Note that the length of a DUH is a constant | ' / + * stored in the DUH struct and in the DUH disk \__/ + * format. It will be calculated on loading for + * other formats in which the length is not explicitly stored. Also note that + * it does not necessarily correspond to the length of time for which the DUH + * will generate samples. Rather it represents a suitable point for a player + * such as Winamp to stop, and in any good DUH it will allow for any final + * flourish to fade out and be appreciated. + */ + +#include "dumb.h" +#include "internal/dumb.h" + + + +long duh_get_length(DUH *duh) +{ + return duh ? duh->length : 0; +} + + + +void duh_set_length(DUH *duh, long length) +{ + if (duh) + duh->length = length; +} + + + diff --git a/plugins/dumb/dumb-kode54/src/core/duhtag.c b/plugins/dumb/dumb-kode54/src/core/duhtag.c index 77061094..b150467d 100644 --- a/plugins/dumb/dumb-kode54/src/core/duhtag.c +++ b/plugins/dumb/dumb-kode54/src/core/duhtag.c @@ -1,38 +1,38 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * duhtag.c - Function to return the tags stored / / \ \
- * in a DUH struct (typically author | < / \_
- * information). | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-const char *duh_get_tag(DUH *duh, const char *key)
-{
- int i;
- ASSERT(key);
- if (!duh || !duh->tag) return NULL;
-
- for (i = 0; i < duh->n_tags; i++)
- if (strcmp(key, duh->tag[i][0]) == 0)
- return duh->tag[i][1];
-
- return NULL;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * duhtag.c - Function to return the tags stored / / \ \ + * in a DUH struct (typically author | < / \_ + * information). | \/ /\ / + * \_ / > / + * By entheh. | \ / / + * | ' / + * \__/ + */ + +#include <string.h> + +#include "dumb.h" +#include "internal/dumb.h" + + + +const char *duh_get_tag(DUH *duh, const char *key) +{ + int i; + ASSERT(key); + if (!duh || !duh->tag) return NULL; + + for (i = 0; i < duh->n_tags; i++) + if (strcmp(key, duh->tag[i][0]) == 0) + return duh->tag[i][1]; + + return NULL; +} diff --git a/plugins/dumb/dumb-kode54/src/core/dumbfile.c b/plugins/dumb/dumb-kode54/src/core/dumbfile.c index ae738bf7..71108c0c 100644 --- a/plugins/dumb/dumb-kode54/src/core/dumbfile.c +++ b/plugins/dumb/dumb-kode54/src/core/dumbfile.c @@ -1,401 +1,401 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * dumbfile.c - Hookable, strictly sequential / / \ \
- * file input functions. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-
-
-
-static DUMBFILE_SYSTEM *the_dfs = NULL;
-
-
-
-void register_dumbfile_system(DUMBFILE_SYSTEM *dfs)
-{
- ASSERT(dfs);
- ASSERT(dfs->open);
- ASSERT(dfs->getc);
- ASSERT(dfs->close);
- the_dfs = dfs;
-}
-
-
-
-struct DUMBFILE
-{
- DUMBFILE_SYSTEM *dfs;
- void *file;
- long pos;
-};
-
-
-
-DUMBFILE *dumbfile_open(const char *filename)
-{
- DUMBFILE *f;
-
- ASSERT(the_dfs);
-
- f = malloc(sizeof(*f));
-
- if (!f)
- return NULL;
-
- f->dfs = the_dfs;
-
- f->file = (*the_dfs->open)(filename);
-
- if (!f->file) {
- free(f);
- return NULL;
- }
-
- f->pos = 0;
-
- return f;
-}
-
-
-
-DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs)
-{
- DUMBFILE *f;
-
- ASSERT(dfs);
- ASSERT(dfs->getc);
- ASSERT(file);
-
- f = malloc(sizeof(*f));
-
- if (!f) {
- if (dfs->close)
- (*dfs->close)(file);
- return NULL;
- }
-
- f->dfs = dfs;
- f->file = file;
-
- f->pos = 0;
-
- return f;
-}
-
-
-
-long dumbfile_pos(DUMBFILE *f)
-{
- ASSERT(f);
-
- return f->pos;
-}
-
-
-
-int dumbfile_skip(DUMBFILE *f, long n)
-{
- int rv;
-
- ASSERT(f);
- ASSERT(n >= 0);
-
- if (f->pos < 0)
- return -1;
-
- f->pos += n;
-
- if (f->dfs->skip) {
- rv = (*f->dfs->skip)(f->file, n);
- if (rv) {
- f->pos = -1;
- return rv;
- }
- } else {
- while (n) {
- rv = (*f->dfs->getc)(f->file);
- if (rv < 0) {
- f->pos = -1;
- return rv;
- }
- n--;
- }
- }
-
- return 0;
-}
-
-
-
-int dumbfile_getc(DUMBFILE *f)
-{
- int rv;
-
- ASSERT(f);
-
- if (f->pos < 0)
- return -1;
-
- rv = (*f->dfs->getc)(f->file);
-
- if (rv < 0) {
- f->pos = -1;
- return rv;
- }
-
- f->pos++;
-
- return rv;
-}
-
-
-
-int dumbfile_igetw(DUMBFILE *f)
-{
- int l, h;
-
- ASSERT(f);
-
- if (f->pos < 0)
- return -1;
-
- l = (*f->dfs->getc)(f->file);
- if (l < 0) {
- f->pos = -1;
- return l;
- }
-
- h = (*f->dfs->getc)(f->file);
- if (h < 0) {
- f->pos = -1;
- return h;
- }
-
- f->pos += 2;
-
- return l | (h << 8);
-}
-
-
-
-int dumbfile_mgetw(DUMBFILE *f)
-{
- int l, h;
-
- ASSERT(f);
-
- if (f->pos < 0)
- return -1;
-
- h = (*f->dfs->getc)(f->file);
- if (h < 0) {
- f->pos = -1;
- return h;
- }
-
- l = (*f->dfs->getc)(f->file);
- if (l < 0) {
- f->pos = -1;
- return l;
- }
-
- f->pos += 2;
-
- return l | (h << 8);
-}
-
-
-
-long dumbfile_igetl(DUMBFILE *f)
-{
- unsigned long rv, b;
-
- ASSERT(f);
-
- if (f->pos < 0)
- return -1;
-
- rv = (*f->dfs->getc)(f->file);
- if ((signed long)rv < 0) {
- f->pos = -1;
- return rv;
- }
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b << 8;
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b << 16;
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b << 24;
-
- f->pos += 4;
-
- return rv;
-}
-
-
-
-long dumbfile_mgetl(DUMBFILE *f)
-{
- unsigned long rv, b;
-
- ASSERT(f);
-
- if (f->pos < 0)
- return -1;
-
- rv = (*f->dfs->getc)(f->file);
- if ((signed long)rv < 0) {
- f->pos = -1;
- return rv;
- }
- rv <<= 24;
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b << 16;
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b << 8;
-
- b = (*f->dfs->getc)(f->file);
- if ((signed long)b < 0) {
- f->pos = -1;
- return b;
- }
- rv |= b;
-
- f->pos += 4;
-
- return rv;
-}
-
-
-
-unsigned long dumbfile_cgetul(DUMBFILE *f)
-{
- unsigned long rv = 0;
- int v;
-
- do {
- v = dumbfile_getc(f);
-
- if (v < 0)
- return v;
-
- rv <<= 7;
- rv |= v & 0x7F;
- } while (v & 0x80);
-
- return rv;
-}
-
-
-
-signed long dumbfile_cgetsl(DUMBFILE *f)
-{
- unsigned long rv = dumbfile_cgetul(f);
-
- if (f->pos < 0)
- return rv;
-
- return (rv >> 1) | (rv << 31);
-}
-
-
-
-long dumbfile_getnc(char *ptr, long n, DUMBFILE *f)
-{
- long rv;
-
- ASSERT(f);
- ASSERT(n >= 0);
-
- if (f->pos < 0)
- return -1;
-
- if (f->dfs->getnc) {
- rv = (*f->dfs->getnc)(ptr, n, f->file);
- if (rv < n) {
- f->pos = -1;
- return MAX(rv, 0);
- }
- } else {
- for (rv = 0; rv < n; rv++) {
- int c = (*f->dfs->getc)(f->file);
- if (c < 0) {
- f->pos = -1;
- return rv;
- }
- *ptr++ = c;
- }
- }
-
- f->pos += rv;
-
- return rv;
-}
-
-
-
-int dumbfile_error(DUMBFILE *f)
-{
- ASSERT(f);
-
- return f->pos < 0;
-}
-
-
-
-int dumbfile_close(DUMBFILE *f)
-{
- int rv;
-
- ASSERT(f);
-
- rv = f->pos < 0;
-
- if (f->dfs->close)
- (*f->dfs->close)(f->file);
-
- free(f);
-
- return rv;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * dumbfile.c - Hookable, strictly sequential / / \ \ + * file input functions. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> + +#include "dumb.h" + + + +static DUMBFILE_SYSTEM *the_dfs = NULL; + + + +void register_dumbfile_system(DUMBFILE_SYSTEM *dfs) +{ + ASSERT(dfs); + ASSERT(dfs->open); + ASSERT(dfs->getc); + ASSERT(dfs->close); + the_dfs = dfs; +} + + + +struct DUMBFILE +{ + DUMBFILE_SYSTEM *dfs; + void *file; + long pos; +}; + + + +DUMBFILE *dumbfile_open(const char *filename) +{ + DUMBFILE *f; + + ASSERT(the_dfs); + + f = malloc(sizeof(*f)); + + if (!f) + return NULL; + + f->dfs = the_dfs; + + f->file = (*the_dfs->open)(filename); + + if (!f->file) { + free(f); + return NULL; + } + + f->pos = 0; + + return f; +} + + + +DUMBFILE *dumbfile_open_ex(void *file, DUMBFILE_SYSTEM *dfs) +{ + DUMBFILE *f; + + ASSERT(dfs); + ASSERT(dfs->getc); + ASSERT(file); + + f = malloc(sizeof(*f)); + + if (!f) { + if (dfs->close) + (*dfs->close)(file); + return NULL; + } + + f->dfs = dfs; + f->file = file; + + f->pos = 0; + + return f; +} + + + +long dumbfile_pos(DUMBFILE *f) +{ + ASSERT(f); + + return f->pos; +} + + + +int dumbfile_skip(DUMBFILE *f, long n) +{ + int rv; + + ASSERT(f); + ASSERT(n >= 0); + + if (f->pos < 0) + return -1; + + f->pos += n; + + if (f->dfs->skip) { + rv = (*f->dfs->skip)(f->file, n); + if (rv) { + f->pos = -1; + return rv; + } + } else { + while (n) { + rv = (*f->dfs->getc)(f->file); + if (rv < 0) { + f->pos = -1; + return rv; + } + n--; + } + } + + return 0; +} + + + +int dumbfile_getc(DUMBFILE *f) +{ + int rv; + + ASSERT(f); + + if (f->pos < 0) + return -1; + + rv = (*f->dfs->getc)(f->file); + + if (rv < 0) { + f->pos = -1; + return rv; + } + + f->pos++; + + return rv; +} + + + +int dumbfile_igetw(DUMBFILE *f) +{ + int l, h; + + ASSERT(f); + + if (f->pos < 0) + return -1; + + l = (*f->dfs->getc)(f->file); + if (l < 0) { + f->pos = -1; + return l; + } + + h = (*f->dfs->getc)(f->file); + if (h < 0) { + f->pos = -1; + return h; + } + + f->pos += 2; + + return l | (h << 8); +} + + + +int dumbfile_mgetw(DUMBFILE *f) +{ + int l, h; + + ASSERT(f); + + if (f->pos < 0) + return -1; + + h = (*f->dfs->getc)(f->file); + if (h < 0) { + f->pos = -1; + return h; + } + + l = (*f->dfs->getc)(f->file); + if (l < 0) { + f->pos = -1; + return l; + } + + f->pos += 2; + + return l | (h << 8); +} + + + +long dumbfile_igetl(DUMBFILE *f) +{ + unsigned long rv, b; + + ASSERT(f); + + if (f->pos < 0) + return -1; + + rv = (*f->dfs->getc)(f->file); + if ((signed long)rv < 0) { + f->pos = -1; + return rv; + } + + b = (*f->dfs->getc)(f->file); + if ((signed long)b < 0) { + f->pos = -1; + return b; + } + rv |= b << 8; + + b = (*f->dfs->getc)(f->file); + if ((signed long)b < 0) { + f->pos = -1; + return b; + } + rv |= b << 16; + + b = (*f->dfs->getc)(f->file); + if ((signed long)b < 0) { + f->pos = -1; + return b; + } + rv |= b << 24; + + f->pos += 4; + + return rv; +} + + + +long dumbfile_mgetl(DUMBFILE *f) +{ + unsigned long rv, b; + + ASSERT(f); + + if (f->pos < 0) + return -1; + + rv = (*f->dfs->getc)(f->file); + if ((signed long)rv < 0) { + f->pos = -1; + return rv; + } + rv <<= 24; + + b = (*f->dfs->getc)(f->file); + if ((signed long)b < 0) { + f->pos = -1; + return b; + } + rv |= b << 16; + + b = (*f->dfs->getc)(f->file); + if ((signed long)b < 0) { + f->pos = -1; + return b; + } + rv |= b << 8; + + b = (*f->dfs->getc)(f->file); + if ((signed long)b < 0) { + f->pos = -1; + return b; + } + rv |= b; + + f->pos += 4; + + return rv; +} + + + +unsigned long dumbfile_cgetul(DUMBFILE *f) +{ + unsigned long rv = 0; + int v; + + do { + v = dumbfile_getc(f); + + if (v < 0) + return v; + + rv <<= 7; + rv |= v & 0x7F; + } while (v & 0x80); + + return rv; +} + + + +signed long dumbfile_cgetsl(DUMBFILE *f) +{ + unsigned long rv = dumbfile_cgetul(f); + + if (f->pos < 0) + return rv; + + return (rv >> 1) | (rv << 31); +} + + + +long dumbfile_getnc(char *ptr, long n, DUMBFILE *f) +{ + long rv; + + ASSERT(f); + ASSERT(n >= 0); + + if (f->pos < 0) + return -1; + + if (f->dfs->getnc) { + rv = (*f->dfs->getnc)(ptr, n, f->file); + if (rv < n) { + f->pos = -1; + return MAX(rv, 0); + } + } else { + for (rv = 0; rv < n; rv++) { + int c = (*f->dfs->getc)(f->file); + if (c < 0) { + f->pos = -1; + return rv; + } + *ptr++ = c; + } + } + + f->pos += rv; + + return rv; +} + + + +int dumbfile_error(DUMBFILE *f) +{ + ASSERT(f); + + return f->pos < 0; +} + + + +int dumbfile_close(DUMBFILE *f) +{ + int rv; + + ASSERT(f); + + rv = f->pos < 0; + + if (f->dfs->close) + (*f->dfs->close)(f->file); + + free(f); + + return rv; +} diff --git a/plugins/dumb/dumb-kode54/src/core/loadduh.c b/plugins/dumb/dumb-kode54/src/core/loadduh.c index e954fe24..7dfe5cc1 100644 --- a/plugins/dumb/dumb-kode54/src/core/loadduh.c +++ b/plugins/dumb/dumb-kode54/src/core/loadduh.c @@ -1,42 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadduh.c - Code to read a DUH from a file, / / \ \
- * opening and closing the file for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-/* load_duh(): loads a .duh file, returning a pointer to a DUH struct.
- * When you have finished with it, you must pass the pointer to unload_duh()
- * so that the memory can be freed.
- */
-DUH *load_duh(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = read_duh(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadduh.c - Code to read a DUH from a file, / / \ \ + * opening and closing the file for | < / \_ + * you. | \/ /\ / + * \_ / > / + * By entheh. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/dumb.h" + + + +/* load_duh(): loads a .duh file, returning a pointer to a DUH struct. + * When you have finished with it, you must pass the pointer to unload_duh() + * so that the memory can be freed. + */ +DUH *load_duh(const char *filename) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = read_duh(f); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/core/makeduh.c b/plugins/dumb/dumb-kode54/src/core/makeduh.c index 1edf2b1f..e52b86bc 100644 --- a/plugins/dumb/dumb-kode54/src/core/makeduh.c +++ b/plugins/dumb/dumb-kode54/src/core/makeduh.c @@ -1,132 +1,135 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * makeduh.c - Function to construct a DUH from / / \ \
- * its components. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-static DUH_SIGNAL *make_signal(DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata)
-{
- DUH_SIGNAL *signal;
-
- ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
- ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample);
-
- signal = malloc(sizeof(*signal));
-
- if (!signal) {
- if (desc->unload_sigdata)
- if (sigdata)
- (*desc->unload_sigdata)(sigdata);
- return NULL;
- }
-
- signal->desc = desc;
- signal->sigdata = sigdata;
-
- return signal;
-}
-
-
-
-DUH *make_duh(
- long length,
- int n_tags,
- const char *const tags[][2],
- int n_signals,
- DUH_SIGTYPE_DESC *desc[],
- sigdata_t *sigdata[]
-)
-{
- DUH *duh = malloc(sizeof(*duh));
- int i;
- int fail;
-
- if (duh) {
- duh->n_signals = n_signals;
-
- duh->signal = malloc(n_signals * sizeof(*duh->signal));
-
- if (!duh->signal) {
- free(duh);
- duh = NULL;
- }
- }
-
- if (!duh) {
- for (i = 0; i < n_signals; i++)
- if (desc[i]->unload_sigdata)
- if (sigdata[i])
- (*desc[i]->unload_sigdata)(sigdata[i]);
- return NULL;
- }
-
- duh->n_tags = 0;
- duh->tag = NULL;
-
- fail = 0;
-
- for (i = 0; i < n_signals; i++) {
- duh->signal[i] = make_signal(desc[i], sigdata[i]);
- if (!duh->signal[i])
- fail = 1;
- }
-
- if (fail) {
- unload_duh(duh);
- return NULL;
- }
-
- duh->length = length;
-
- {
- int mem = n_tags * 2; /* account for NUL terminators here */
- char *ptr;
-
- for (i = 0; i < n_tags; i++)
- mem += strlen(tags[i][0]) + strlen(tags[i][1]);
-
- if (mem <= 0) return duh;
-
- duh->tag = malloc(n_tags * sizeof(*duh->tag));
- if (!duh->tag) return duh;
- duh->tag[0][0] = malloc(mem);
- if (!duh->tag[0][0]) {
- free(duh->tag);
- duh->tag = NULL;
- return duh;
- }
- duh->n_tags = n_tags;
- ptr = duh->tag[0][0];
- for (i = 0; i < n_tags; i++) {
- duh->tag[i][0] = ptr;
- strcpy(ptr, tags[i][0]);
- ptr += strlen(tags[i][0]) + 1;
- duh->tag[i][1] = ptr;
- strcpy(ptr, tags[i][1]);
- ptr += strlen(tags[i][1]) + 1;
- }
- }
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * makeduh.c - Function to construct a DUH from / / \ \ + * its components. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" +#include "internal/dumb.h" + + + +static DUH_SIGNAL *make_signal(DUH_SIGTYPE_DESC *desc, sigdata_t *sigdata) +{ + DUH_SIGNAL *signal; + + ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer)); + ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample); + + signal = malloc(sizeof(*signal)); + + if (!signal) { + if (desc->unload_sigdata) + if (sigdata) + (*desc->unload_sigdata)(sigdata); + return NULL; + } + + signal->desc = desc; + signal->sigdata = sigdata; + + return signal; +} + + + +DUH *make_duh( + long length, + int n_tags, + const char *const tags[][2], + int n_signals, + DUH_SIGTYPE_DESC *desc[], + sigdata_t *sigdata[] +) +{ + DUH *duh = malloc(sizeof(*duh)); + int i; + int fail; + + if (duh) { + duh->n_signals = n_signals; + + duh->signal = malloc(n_signals * sizeof(*duh->signal)); + + if (!duh->signal) { + free(duh); + duh = NULL; + } + } + + if (!duh) { + for (i = 0; i < n_signals; i++) + if (desc[i]->unload_sigdata) + if (sigdata[i]) + (*desc[i]->unload_sigdata)(sigdata[i]); + return NULL; + } + + duh->n_tags = 0; + duh->tag = NULL; + + duh->n_tags = 0; + duh->tag = NULL; + + fail = 0; + + for (i = 0; i < n_signals; i++) { + duh->signal[i] = make_signal(desc[i], sigdata[i]); + if (!duh->signal[i]) + fail = 1; + } + + if (fail) { + unload_duh(duh); + return NULL; + } + + duh->length = length; + + { + int mem = n_tags * 2; /* account for NUL terminators here */ + char *ptr; + + for (i = 0; i < n_tags; i++) + mem += strlen(tags[i][0]) + strlen(tags[i][1]); + + if (mem <= 0) return duh; + + duh->tag = malloc(n_tags * sizeof(*duh->tag)); + if (!duh->tag) return duh; + duh->tag[0][0] = malloc(mem); + if (!duh->tag[0][0]) { + free(duh->tag); + duh->tag = NULL; + return duh; + } + duh->n_tags = n_tags; + ptr = duh->tag[0][0]; + for (i = 0; i < n_tags; i++) { + duh->tag[i][0] = ptr; + strcpy(ptr, tags[i][0]); + ptr += strlen(tags[i][0]) + 1; + duh->tag[i][1] = ptr; + strcpy(ptr, tags[i][1]); + ptr += strlen(tags[i][1]) + 1; + } + } + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/core/rawsig.c b/plugins/dumb/dumb-kode54/src/core/rawsig.c index 75c41eb0..926c9906 100644 --- a/plugins/dumb/dumb-kode54/src/core/rawsig.c +++ b/plugins/dumb/dumb-kode54/src/core/rawsig.c @@ -1,44 +1,44 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * rawsig.c - Function to retrieve raw signal / / \ \
- * data from a DUH provided you know | < / \_
- * what type of signal it is. | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-/* You have to specify the type of sigdata, proving you know what to do with
- * the pointer. If you get it wrong, you can expect NULL back.
- */
-sigdata_t *duh_get_raw_sigdata(DUH *duh, int sig, long type)
-{
- DUH_SIGNAL *signal;
-
- if (!duh) return NULL;
-
- if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL;
-
- signal = duh->signal[sig];
-
- if (signal && signal->desc->type == type)
- return signal->sigdata;
-
- return NULL;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * rawsig.c - Function to retrieve raw signal / / \ \ + * data from a DUH provided you know | < / \_ + * what type of signal it is. | \/ /\ / + * \_ / > / + * By entheh. | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> + +#include "dumb.h" +#include "internal/dumb.h" + + + +/* You have to specify the type of sigdata, proving you know what to do with + * the pointer. If you get it wrong, you can expect NULL back. + */ +sigdata_t *duh_get_raw_sigdata(DUH *duh, int sig, long type) +{ + DUH_SIGNAL *signal; + + if (!duh) return NULL; + + if ((unsigned int)sig >= (unsigned int)duh->n_signals) return NULL; + + signal = duh->signal[sig]; + + if (signal && signal->desc->type == type) + return signal->sigdata; + + return NULL; +} diff --git a/plugins/dumb/dumb-kode54/src/core/readduh.c b/plugins/dumb/dumb-kode54/src/core/readduh.c index 0fb775b2..514b04a0 100644 --- a/plugins/dumb/dumb-kode54/src/core/readduh.c +++ b/plugins/dumb/dumb-kode54/src/core/readduh.c @@ -1,107 +1,107 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readduh.c - Code to read a DUH from an open / / \ \
- * file. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-static DUH_SIGNAL *read_signal(DUH *duh, DUMBFILE *f)
-{
- DUH_SIGNAL *signal;
- long type;
-
- signal = malloc(sizeof(*signal));
-
- if (!signal)
- return NULL;
-
- type = dumbfile_mgetl(f);
- if (dumbfile_error(f)) {
- free(signal);
- return NULL;
- }
-
- signal->desc = _dumb_get_sigtype_desc(type);
- if (!signal->desc) {
- free(signal);
- return NULL;
- }
-
- if (signal->desc->load_sigdata) {
- signal->sigdata = (*signal->desc->load_sigdata)(duh, f);
- if (!signal->sigdata) {
- free(signal);
- return NULL;
- }
- } else
- signal->sigdata = NULL;
-
- return signal;
-}
-
-
-
-/* read_duh(): reads a DUH from an already open DUMBFILE, and returns its
- * pointer, or null on error. The file is not closed.
- */
-DUH *read_duh(DUMBFILE *f)
-{
- DUH *duh;
- int i;
-
- if (dumbfile_mgetl(f) != DUH_SIGNATURE)
- return NULL;
-
- duh = malloc(sizeof(*duh));
- if (!duh)
- return NULL;
-
- duh->length = dumbfile_igetl(f);
- if (dumbfile_error(f) || duh->length <= 0) {
- free(duh);
- return NULL;
- }
-
- duh->n_signals = dumbfile_igetl(f);
- if (dumbfile_error(f) || duh->n_signals <= 0) {
- free(duh);
- return NULL;
- }
-
- duh->signal = malloc(sizeof(*duh->signal) * duh->n_signals);
- if (!duh->signal) {
- free(duh);
- return NULL;
- }
-
- for (i = 0; i < duh->n_signals; i++)
- duh->signal[i] = NULL;
-
- for (i = 0; i < duh->n_signals; i++) {
- if (!(duh->signal[i] = read_signal(duh, f))) {
- unload_duh(duh);
- return NULL;
- }
- }
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readduh.c - Code to read a DUH from an open / / \ \ + * file. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> + +#include "dumb.h" +#include "internal/dumb.h" + + + +static DUH_SIGNAL *read_signal(DUH *duh, DUMBFILE *f) +{ + DUH_SIGNAL *signal; + long type; + + signal = malloc(sizeof(*signal)); + + if (!signal) + return NULL; + + type = dumbfile_mgetl(f); + if (dumbfile_error(f)) { + free(signal); + return NULL; + } + + signal->desc = _dumb_get_sigtype_desc(type); + if (!signal->desc) { + free(signal); + return NULL; + } + + if (signal->desc->load_sigdata) { + signal->sigdata = (*signal->desc->load_sigdata)(duh, f); + if (!signal->sigdata) { + free(signal); + return NULL; + } + } else + signal->sigdata = NULL; + + return signal; +} + + + +/* read_duh(): reads a DUH from an already open DUMBFILE, and returns its + * pointer, or null on error. The file is not closed. + */ +DUH *read_duh(DUMBFILE *f) +{ + DUH *duh; + int i; + + if (dumbfile_mgetl(f) != DUH_SIGNATURE) + return NULL; + + duh = malloc(sizeof(*duh)); + if (!duh) + return NULL; + + duh->length = dumbfile_igetl(f); + if (dumbfile_error(f) || duh->length <= 0) { + free(duh); + return NULL; + } + + duh->n_signals = dumbfile_igetl(f); + if (dumbfile_error(f) || duh->n_signals <= 0) { + free(duh); + return NULL; + } + + duh->signal = malloc(sizeof(*duh->signal) * duh->n_signals); + if (!duh->signal) { + free(duh); + return NULL; + } + + for (i = 0; i < duh->n_signals; i++) + duh->signal[i] = NULL; + + for (i = 0; i < duh->n_signals; i++) { + if (!(duh->signal[i] = read_signal(duh, f))) { + unload_duh(duh); + return NULL; + } + } + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/core/register.c b/plugins/dumb/dumb-kode54/src/core/register.c index 2e16c9a7..66dd4524 100644 --- a/plugins/dumb/dumb-kode54/src/core/register.c +++ b/plugins/dumb/dumb-kode54/src/core/register.c @@ -1,104 +1,104 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * register.c - Signal type registration. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-static DUH_SIGTYPE_DESC_LINK *sigtype_desc = NULL;
-static DUH_SIGTYPE_DESC_LINK **sigtype_desc_tail = &sigtype_desc;
-
-
-
-/* destroy_sigtypes(): frees all memory allocated while registering signal
- * types. This function is set up to be called by dumb_exit().
- */
-static void destroy_sigtypes(void)
-{
- DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc, *next;
- sigtype_desc = NULL;
- sigtype_desc_tail = &sigtype_desc;
-
- while (desc_link) {
- next = desc_link->next;
- free(desc_link);
- desc_link = next;
- }
-}
-
-
-
-/* dumb_register_sigtype(): registers a new signal type with DUMB. The signal
- * type is identified by a four-character string (e.g. "WAVE"), which you can
- * encode using the the DUMB_ID() macro (e.g. DUMB_ID('W','A','V','E')). The
- * signal's behaviour is defined by four functions, whose pointers you pass
- * here. See the documentation for details.
- *
- * If a DUH tries to use a signal that has not been registered using this
- * function, then the library will fail to load the DUH.
- */
-void dumb_register_sigtype(DUH_SIGTYPE_DESC *desc)
-{
- DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
-
- ASSERT((desc->load_sigdata && desc->unload_sigdata) || (!desc->load_sigdata && !desc->unload_sigdata));
- ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer));
- ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample);
-
- if (desc_link) {
- do {
- if (desc_link->desc->type == desc->type) {
- desc_link->desc = desc;
- return;
- }
- desc_link = desc_link->next;
- } while (desc_link);
- } else
- dumb_atexit(&destroy_sigtypes);
-
- desc_link = *sigtype_desc_tail = malloc(sizeof(DUH_SIGTYPE_DESC_LINK));
-
- if (!desc_link)
- return;
-
- desc_link->next = NULL;
- sigtype_desc_tail = &desc_link->next;
-
- desc_link->desc = desc;
-}
-
-
-
-/* _dumb_get_sigtype_desc(): searches the registered functions for a signal
- * type matching the parameter. If such a sigtype is found, it returns a
- * pointer to a sigtype descriptor containing the necessary functions to
- * manage the signal. If none is found, it returns NULL.
- */
-DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type)
-{
- DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc;
-
- while (desc_link && desc_link->desc->type != type)
- desc_link = desc_link->next;
-
- return desc_link ? desc_link->desc : NULL;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * register.c - Signal type registration. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> + +#include "dumb.h" +#include "internal/dumb.h" + + + +static DUH_SIGTYPE_DESC_LINK *sigtype_desc = NULL; +static DUH_SIGTYPE_DESC_LINK **sigtype_desc_tail = &sigtype_desc; + + + +/* destroy_sigtypes(): frees all memory allocated while registering signal + * types. This function is set up to be called by dumb_exit(). + */ +static void destroy_sigtypes(void) +{ + DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc, *next; + sigtype_desc = NULL; + sigtype_desc_tail = &sigtype_desc; + + while (desc_link) { + next = desc_link->next; + free(desc_link); + desc_link = next; + } +} + + + +/* dumb_register_sigtype(): registers a new signal type with DUMB. The signal + * type is identified by a four-character string (e.g. "WAVE"), which you can + * encode using the the DUMB_ID() macro (e.g. DUMB_ID('W','A','V','E')). The + * signal's behaviour is defined by four functions, whose pointers you pass + * here. See the documentation for details. + * + * If a DUH tries to use a signal that has not been registered using this + * function, then the library will fail to load the DUH. + */ +void dumb_register_sigtype(DUH_SIGTYPE_DESC *desc) +{ + DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc; + + ASSERT((desc->load_sigdata && desc->unload_sigdata) || (!desc->load_sigdata && !desc->unload_sigdata)); + ASSERT((desc->start_sigrenderer && desc->end_sigrenderer) || (!desc->start_sigrenderer && !desc->end_sigrenderer)); + ASSERT(desc->sigrenderer_generate_samples && desc->sigrenderer_get_current_sample); + + if (desc_link) { + do { + if (desc_link->desc->type == desc->type) { + desc_link->desc = desc; + return; + } + desc_link = desc_link->next; + } while (desc_link); + } else + dumb_atexit(&destroy_sigtypes); + + desc_link = *sigtype_desc_tail = malloc(sizeof(DUH_SIGTYPE_DESC_LINK)); + + if (!desc_link) + return; + + desc_link->next = NULL; + sigtype_desc_tail = &desc_link->next; + + desc_link->desc = desc; +} + + + +/* _dumb_get_sigtype_desc(): searches the registered functions for a signal + * type matching the parameter. If such a sigtype is found, it returns a + * pointer to a sigtype descriptor containing the necessary functions to + * manage the signal. If none is found, it returns NULL. + */ +DUH_SIGTYPE_DESC *_dumb_get_sigtype_desc(long type) +{ + DUH_SIGTYPE_DESC_LINK *desc_link = sigtype_desc; + + while (desc_link && desc_link->desc->type != type) + desc_link = desc_link->next; + + return desc_link ? desc_link->desc : NULL; +} diff --git a/plugins/dumb/dumb-kode54/src/core/rendduh.c b/plugins/dumb/dumb-kode54/src/core/rendduh.c index 1effa3eb..1639b938 100644 --- a/plugins/dumb/dumb-kode54/src/core/rendduh.c +++ b/plugins/dumb/dumb-kode54/src/core/rendduh.c @@ -1,184 +1,184 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * rendduh.c - Functions for rendering a DUH into / / \ \
- * an end-user sample format. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <limits.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-/* On the x86, we can use some tricks to speed stuff up */
-#if (defined _MSC_VER) || (defined __DJGPP__) || (defined __MINGW__)
-// Can't we detect Linux and other x86 platforms here? :/
-
-#define FAST_MID(var, min, max) { \
- var -= (min); \
- var &= (~var) >> (sizeof(var) * CHAR_BIT - 1); \
- var += (min); \
- var -= (max); \
- var &= var >> (sizeof(var) * CHAR_BIT - 1); \
- var += (max); \
-}
-
-#define CONVERT8(src, pos, signconv) { \
- signed int f = (src + 0x8000) >> 16; \
- FAST_MID(f, -128, 127); \
- ((char*)sptr)[pos] = (char)f ^ signconv; \
-}
-
-#define CONVERT16(src, pos, signconv) { \
- signed int f = (src + 0x80) >> 8; \
- FAST_MID(f, -32768, 32767); \
- ((short*)sptr)[pos] = (short)(f ^ signconv); \
-}
-
-#else
-
-#define CONVERT8(src, pos, signconv) \
-{ \
- signed int f = (src + 0x8000) >> 16; \
- f = MID(-128, f, 127); \
- ((char *)sptr)[pos] = (char)f ^ signconv; \
-}
-
-
-
-#define CONVERT16(src, pos, signconv) \
-{ \
- signed int f = (src + 0x80) >> 8; \
- f = MID(-32768, f, 32767); \
- ((short *)sptr)[pos] = (short)(f ^ signconv); \
-}
-
-#endif
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos)
-{
- return duh_start_sigrenderer(duh, 0, n_channels, pos);
-}
-
-
-
-long duh_render(
- DUH_SIGRENDERER *sigrenderer,
- int bits, int unsign,
- float volume, float delta,
- long size, void *sptr
-)
-{
- long n;
-
- sample_t **sampptr;
-
- int n_channels;
-
- ASSERT(bits == 8 || bits == 16);
- ASSERT(sptr);
-
- if (!sigrenderer)
- return 0;
-
- n_channels = duh_sigrenderer_get_n_channels(sigrenderer);
-
- ASSERT(n_channels > 0);
- /* This restriction will be removed when need be. At the moment, tightly
- * optimised loops exist for exactly one or two channels.
- */
- ASSERT(n_channels <= 2);
-
- sampptr = allocate_sample_buffer(n_channels, size);
-
- if (!sampptr)
- return 0;
-
- dumb_silence(sampptr[0], n_channels * size);
-
- size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr);
-
- if (bits == 16) {
- int signconv = unsign ? 0x8000 : 0x0000;
-
- for (n = 0; n < size * n_channels; n++) {
- CONVERT16(sampptr[0][n], n, signconv);
- }
- } else {
- char signconv = unsign ? 0x80 : 0x00;
-
- for (n = 0; n < size * n_channels; n++) {
- CONVERT8(sampptr[0][n], n, signconv);
- }
- }
-
- destroy_sample_buffer(sampptr);
-
- return size;
-}
-
-
-
-/* DEPRECATED */
-int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr)
-{
- return duh_sigrenderer_get_n_channels(dr);
-}
-
-
-
-/* DEPRECATED */
-long duh_renderer_get_position(DUH_SIGRENDERER *dr)
-{
- return duh_sigrenderer_get_position(dr);
-}
-
-
-
-/* DEPRECATED */
-void duh_end_renderer(DUH_SIGRENDERER *dr)
-{
- duh_end_sigrenderer(dr);
-}
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer)
-{
- return sigrenderer;
-}
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr)
-{
- return dr;
-}
-
-
-
-/* DEPRECATED */
-DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr)
-{
- return dr;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * rendduh.c - Functions for rendering a DUH into / / \ \ + * an end-user sample format. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <limits.h> + +#include "dumb.h" +#include "internal/dumb.h" + + + +/* On the x86, we can use some tricks to speed stuff up */ +#if (defined _MSC_VER) || (defined __DJGPP__) || (defined __MINGW__) +// Can't we detect Linux and other x86 platforms here? :/ + +#define FAST_MID(var, min, max) { \ + var -= (min); \ + var &= (~var) >> (sizeof(var) * CHAR_BIT - 1); \ + var += (min); \ + var -= (max); \ + var &= var >> (sizeof(var) * CHAR_BIT - 1); \ + var += (max); \ +} + +#define CONVERT8(src, pos, signconv) { \ + signed int f = (src + 0x8000) >> 16; \ + FAST_MID(f, -128, 127); \ + ((char*)sptr)[pos] = (char)f ^ signconv; \ +} + +#define CONVERT16(src, pos, signconv) { \ + signed int f = (src + 0x80) >> 8; \ + FAST_MID(f, -32768, 32767); \ + ((short*)sptr)[pos] = (short)(f ^ signconv); \ +} + +#else + +#define CONVERT8(src, pos, signconv) \ +{ \ + signed int f = (src + 0x8000) >> 16; \ + f = MID(-128, f, 127); \ + ((char *)sptr)[pos] = (char)f ^ signconv; \ +} + + + +#define CONVERT16(src, pos, signconv) \ +{ \ + signed int f = (src + 0x80) >> 8; \ + f = MID(-32768, f, 32767); \ + ((short *)sptr)[pos] = (short)(f ^ signconv); \ +} + +#endif + + + +/* DEPRECATED */ +DUH_SIGRENDERER *duh_start_renderer(DUH *duh, int n_channels, long pos) +{ + return duh_start_sigrenderer(duh, 0, n_channels, pos); +} + + + +long duh_render( + DUH_SIGRENDERER *sigrenderer, + int bits, int unsign, + float volume, float delta, + long size, void *sptr +) +{ + long n; + + sample_t **sampptr; + + int n_channels; + + ASSERT(bits == 8 || bits == 16); + ASSERT(sptr); + + if (!sigrenderer) + return 0; + + n_channels = duh_sigrenderer_get_n_channels(sigrenderer); + + ASSERT(n_channels > 0); + /* This restriction will be removed when need be. At the moment, tightly + * optimised loops exist for exactly one or two channels. + */ + ASSERT(n_channels <= 2); + + sampptr = allocate_sample_buffer(n_channels, size); + + if (!sampptr) + return 0; + + dumb_silence(sampptr[0], n_channels * size); + + size = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, sampptr); + + if (bits == 16) { + int signconv = unsign ? 0x8000 : 0x0000; + + for (n = 0; n < size * n_channels; n++) { + CONVERT16(sampptr[0][n], n, signconv); + } + } else { + char signconv = unsign ? 0x80 : 0x00; + + for (n = 0; n < size * n_channels; n++) { + CONVERT8(sampptr[0][n], n, signconv); + } + } + + destroy_sample_buffer(sampptr); + + return size; +} + + + +/* DEPRECATED */ +int duh_renderer_get_n_channels(DUH_SIGRENDERER *dr) +{ + return duh_sigrenderer_get_n_channels(dr); +} + + + +/* DEPRECATED */ +long duh_renderer_get_position(DUH_SIGRENDERER *dr) +{ + return duh_sigrenderer_get_position(dr); +} + + + +/* DEPRECATED */ +void duh_end_renderer(DUH_SIGRENDERER *dr) +{ + duh_end_sigrenderer(dr); +} + + + +/* DEPRECATED */ +DUH_SIGRENDERER *duh_renderer_encapsulate_sigrenderer(DUH_SIGRENDERER *sigrenderer) +{ + return sigrenderer; +} + + + +/* DEPRECATED */ +DUH_SIGRENDERER *duh_renderer_get_sigrenderer(DUH_SIGRENDERER *dr) +{ + return dr; +} + + + +/* DEPRECATED */ +DUH_SIGRENDERER *duh_renderer_decompose_to_sigrenderer(DUH_SIGRENDERER *dr) +{ + return dr; +} diff --git a/plugins/dumb/dumb-kode54/src/core/rendsig.c b/plugins/dumb/dumb-kode54/src/core/rendsig.c index b8f866c5..4181d1cd 100644 --- a/plugins/dumb/dumb-kode54/src/core/rendsig.c +++ b/plugins/dumb/dumb-kode54/src/core/rendsig.c @@ -1,344 +1,346 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * rendsig.c - Wrappers to render samples from / / \ \
- * the signals in a DUH. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-struct DUH_SIGRENDERER
-{
- DUH_SIGTYPE_DESC *desc;
-
- sigrenderer_t *sigrenderer;
-
- int n_channels;
-
- long pos;
- int subpos;
-
- DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback;
- void *callback_data;
-};
-
-
-
-DUH_SIGRENDERER *duh_start_sigrenderer(DUH *duh, int sig, int n_channels, long pos)
-{
- DUH_SIGRENDERER *sigrenderer;
-
- DUH_SIGNAL *signal;
- DUH_START_SIGRENDERER proc;
-
- if (!duh)
- return NULL;
-
- if ((unsigned int)sig >= (unsigned int)duh->n_signals)
- return NULL;
-
- signal = duh->signal[sig];
- if (!signal)
- return NULL;
-
- sigrenderer = malloc(sizeof(*sigrenderer));
- if (!sigrenderer)
- return NULL;
-
- sigrenderer->desc = signal->desc;
-
- proc = sigrenderer->desc->start_sigrenderer;
-
- if (proc) {
- duh->signal[sig] = NULL;
- sigrenderer->sigrenderer = (*proc)(duh, signal->sigdata, n_channels, pos);
- duh->signal[sig] = signal;
-
- if (!sigrenderer->sigrenderer) {
- free(sigrenderer);
- return NULL;
- }
- } else
- sigrenderer->sigrenderer = NULL;
-
- sigrenderer->n_channels = n_channels;
-
- sigrenderer->pos = pos;
- sigrenderer->subpos = 0;
-
- sigrenderer->callback = NULL;
-
- return sigrenderer;
-}
-
-
-
-#include <stdio.h>
-void duh_sigrenderer_set_callback(
- DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_CALLBACK callback, void *data
-)
-{
- (void)sigrenderer;
- (void)callback;
- (void)data;
- /*fprintf(stderr,
- "Call to deprecated function duh_sigrenderer_set_callback(). The callback\n"
- "was not installed. See dumb/docs/deprec.txt for how to fix this.\n");*/
-}
-
-
-
-void duh_sigrenderer_set_analyser_callback(
- DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data
-)
-{
- (void)sigrenderer;
- (void)callback;
- (void)data;
- fprintf(stderr,
- "Call to deprecated function duh_sigrenderer_set_analyser_callback(). The\n"
- "callback was not installed. See dumb/docs/deprec.txt for how to fix this.\n");
-}
-
-
-
-void duh_sigrenderer_set_sample_analyser_callback(
- DUH_SIGRENDERER *sigrenderer,
- DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data
-)
-{
- if (sigrenderer) {
- sigrenderer->callback = callback;
- sigrenderer->callback_data = data;
- }
-}
-
-
-
-int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer)
-{
- return sigrenderer ? sigrenderer->n_channels : 0;
-}
-
-
-
-long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer)
-{
- return sigrenderer ? sigrenderer->pos : -1;
-}
-
-
-
-void duh_sigrenderer_set_sigparam(
- DUH_SIGRENDERER *sigrenderer,
- unsigned char id, long value
-)
-{
- DUH_SIGRENDERER_SET_SIGPARAM proc;
-
- if (!sigrenderer) return;
-
- proc = sigrenderer->desc->sigrenderer_set_sigparam;
- if (proc)
- (*proc)(sigrenderer->sigrenderer, id, value);
- else
- TRACE("Parameter #%d = %ld for signal %c%c%c%c, which does not take parameters.\n",
- (int)id,
- value,
- (int)(sigrenderer->desc->type >> 24),
- (int)(sigrenderer->desc->type >> 16),
- (int)(sigrenderer->desc->type >> 8),
- (int)(sigrenderer->desc->type));
-}
-
-
-
-long duh_sigrenderer_generate_samples(
- DUH_SIGRENDERER *sigrenderer,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
- long rendered;
- LONG_LONG t;
-
- if (!sigrenderer) return 0;
-
- rendered = (*sigrenderer->desc->sigrenderer_generate_samples)
- (sigrenderer->sigrenderer, volume, delta, size, samples);
-
- if (rendered) {
- if (sigrenderer->callback)
- (*sigrenderer->callback)(sigrenderer->callback_data,
- (const sample_t *const *)samples, sigrenderer->n_channels, rendered);
-
- t = sigrenderer->subpos + (LONG_LONG)(delta * 65536.0 + 0.5) * rendered;
-
- sigrenderer->pos += (long)(t >> 16);
- sigrenderer->subpos = (int)t & 65535;
- }
-
- return rendered;
-}
-
-
-
-/* DEPRECATED */
-long duh_sigrenderer_get_samples(
- DUH_SIGRENDERER *sigrenderer,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
- sample_t **s;
- long rendered;
- long i;
- int j;
- if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL);
- s = allocate_sample_buffer(sigrenderer->n_channels, size);
- if (!s) return 0;
- dumb_silence(s[0], sigrenderer->n_channels * size);
- rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s);
- for (j = 0; j < sigrenderer->n_channels; j++)
- for (i = 0; i < rendered; i++)
- samples[j][i] += s[0][i*sigrenderer->n_channels+j];
- destroy_sample_buffer(s);
- return rendered;
-}
-
-
-
-/* DEPRECATED */
-long duh_render_signal(
- DUH_SIGRENDERER *sigrenderer,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
- sample_t **s;
- long rendered;
- long i;
- int j;
- if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL);
- s = allocate_sample_buffer(sigrenderer->n_channels, size);
- if (!s) return 0;
- dumb_silence(s[0], sigrenderer->n_channels * size);
- rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s);
- for (j = 0; j < sigrenderer->n_channels; j++)
- for (i = 0; i < rendered; i++)
- samples[j][i] += s[0][i*sigrenderer->n_channels+j] >> 8;
- destroy_sample_buffer(s);
- return rendered;
-}
-
-
-
-void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples)
-{
- if (sigrenderer)
- (*sigrenderer->desc->sigrenderer_get_current_sample)(sigrenderer->sigrenderer, volume, samples);
-}
-
-
-
-void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer)
-{
- if (sigrenderer) {
- if (sigrenderer->desc->end_sigrenderer)
- if (sigrenderer->sigrenderer)
- (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
-
- free(sigrenderer);
- }
-}
-
-
-
-DUH_SIGRENDERER *duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, long pos)
-{
- DUH_SIGRENDERER *sigrenderer;
-
- if (desc->start_sigrenderer && !vsigrenderer) return NULL;
-
- sigrenderer = malloc(sizeof(*sigrenderer));
- if (!sigrenderer) {
- if (desc->end_sigrenderer)
- if (vsigrenderer)
- (*desc->end_sigrenderer)(vsigrenderer);
- return NULL;
- }
-
- sigrenderer->desc = desc;
- sigrenderer->sigrenderer = vsigrenderer;
-
- sigrenderer->n_channels = n_channels;
-
- sigrenderer->pos = pos;
- sigrenderer->subpos = 0;
-
- sigrenderer->callback = NULL;
-
- return sigrenderer;
-}
-
-
-
-sigrenderer_t *duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type)
-{
- if (sigrenderer && sigrenderer->desc->type == type)
- return sigrenderer->sigrenderer;
-
- return NULL;
-}
-
-
-
-#if 0
-// This function is disabled because we don't know whether we want to destroy
-// the sigrenderer if the type doesn't match. We don't even know if we need
-// the function at all. Who would want to keep an IT_SIGRENDERER (for
-// instance) without keeping the DUH_SIGRENDERER?
-sigrenderer_t *duh_decompose_to_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type)
-{
- if (sigrenderer && sigrenderer->desc->type == type) {
-
-
-
- if (sigrenderer) {
- if (sigrenderer->desc->end_sigrenderer)
- if (sigrenderer->sigrenderer)
- (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer);
-
- free(sigrenderer);
- }
-
-
-
-
-
-
- return sigrenderer->sigrenderer;
- }
-
- return NULL;
-}
-#endif
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * rendsig.c - Wrappers to render samples from / / \ \ + * the signals in a DUH. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> + +#include "dumb.h" +#include "internal/dumb.h" + + + +struct DUH_SIGRENDERER +{ + DUH_SIGTYPE_DESC *desc; + + sigrenderer_t *sigrenderer; + + int n_channels; + + long pos; + int subpos; + + DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback; + void *callback_data; +}; + + + +DUH_SIGRENDERER *duh_start_sigrenderer(DUH *duh, int sig, int n_channels, long pos) +{ + DUH_SIGRENDERER *sigrenderer; + + DUH_SIGNAL *signal; + DUH_START_SIGRENDERER proc; + + if (!duh) + return NULL; + + if ((unsigned int)sig >= (unsigned int)duh->n_signals) + return NULL; + + signal = duh->signal[sig]; + if (!signal) + return NULL; + + sigrenderer = malloc(sizeof(*sigrenderer)); + if (!sigrenderer) + return NULL; + + sigrenderer->desc = signal->desc; + + proc = sigrenderer->desc->start_sigrenderer; + + if (proc) { + duh->signal[sig] = NULL; + sigrenderer->sigrenderer = (*proc)(duh, signal->sigdata, n_channels, pos); + duh->signal[sig] = signal; + + if (!sigrenderer->sigrenderer) { + free(sigrenderer); + return NULL; + } + } else + sigrenderer->sigrenderer = NULL; + + sigrenderer->n_channels = n_channels; + + sigrenderer->pos = pos; + sigrenderer->subpos = 0; + + sigrenderer->callback = NULL; + + return sigrenderer; +} + + + +#include <stdio.h> +void duh_sigrenderer_set_callback( + DUH_SIGRENDERER *sigrenderer, + DUH_SIGRENDERER_CALLBACK callback, void *data +) +{ + (void)sigrenderer; + (void)callback; + (void)data; + /*fprintf(stderr, + "Call to deprecated function duh_sigrenderer_set_callback(). The callback\n" + "was not installed. See dumb/docs/deprec.txt for how to fix this.\n");*/ +} + + + +void duh_sigrenderer_set_analyser_callback( + DUH_SIGRENDERER *sigrenderer, + DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data +) +{ + (void)sigrenderer; + (void)callback; + (void)data; + fprintf(stderr, + "Call to deprecated function duh_sigrenderer_set_analyser_callback(). The\n" + "callback was not installed. See dumb/docs/deprec.txt for how to fix this.\n"); +} + + + +void duh_sigrenderer_set_sample_analyser_callback( + DUH_SIGRENDERER *sigrenderer, + DUH_SIGRENDERER_SAMPLE_ANALYSER_CALLBACK callback, void *data +) +{ + (void)sigrenderer; + (void)callback; + (void)data; + fprintf(stderr, + "Call to deprecated function duh_sigrenderer_set_analyser_callback(). The\n" + "callback was not installed. See dumb/docs/deprec.txt for how to fix this.\n"); +} + + + +int duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer) +{ + return sigrenderer ? sigrenderer->n_channels : 0; +} + + + +long duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer) +{ + return sigrenderer ? sigrenderer->pos : -1; +} + + + +void duh_sigrenderer_set_sigparam( + DUH_SIGRENDERER *sigrenderer, + unsigned char id, long value +) +{ + DUH_SIGRENDERER_SET_SIGPARAM proc; + + if (!sigrenderer) return; + + proc = sigrenderer->desc->sigrenderer_set_sigparam; + if (proc) + (*proc)(sigrenderer->sigrenderer, id, value); + else + TRACE("Parameter #%d = %ld for signal %c%c%c%c, which does not take parameters.\n", + (int)id, + value, + (int)(sigrenderer->desc->type >> 24), + (int)(sigrenderer->desc->type >> 16), + (int)(sigrenderer->desc->type >> 8), + (int)(sigrenderer->desc->type)); +} + + + +long duh_sigrenderer_generate_samples( + DUH_SIGRENDERER *sigrenderer, + float volume, float delta, + long size, sample_t **samples +) +{ + long rendered; + LONG_LONG t; + + if (!sigrenderer) return 0; + + rendered = (*sigrenderer->desc->sigrenderer_generate_samples) + (sigrenderer->sigrenderer, volume, delta, size, samples); + + if (rendered) { + if (sigrenderer->callback) + (*sigrenderer->callback)(sigrenderer->callback_data, + (const sample_t *const *)samples, sigrenderer->n_channels, rendered); + + t = sigrenderer->subpos + (LONG_LONG)(delta * 65536.0 + 0.5) * rendered; + + sigrenderer->pos += (long)(t >> 16); + sigrenderer->subpos = (int)t & 65535; + } + + return rendered; +} + + + +/* DEPRECATED */ +long duh_sigrenderer_get_samples( + DUH_SIGRENDERER *sigrenderer, + float volume, float delta, + long size, sample_t **samples +) +{ + sample_t **s; + long rendered; + long i; + int j; + if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL); + s = allocate_sample_buffer(sigrenderer->n_channels, size); + if (!s) return 0; + dumb_silence(s[0], sigrenderer->n_channels * size); + rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s); + for (j = 0; j < sigrenderer->n_channels; j++) + for (i = 0; i < rendered; i++) + samples[j][i] += s[0][i*sigrenderer->n_channels+j]; + destroy_sample_buffer(s); + return rendered; +} + + + +/* DEPRECATED */ +long duh_render_signal( + DUH_SIGRENDERER *sigrenderer, + float volume, float delta, + long size, sample_t **samples +) +{ + sample_t **s; + long rendered; + long i; + int j; + if (!samples) return duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, NULL); + s = allocate_sample_buffer(sigrenderer->n_channels, size); + if (!s) return 0; + dumb_silence(s[0], sigrenderer->n_channels * size); + rendered = duh_sigrenderer_generate_samples(sigrenderer, volume, delta, size, s); + for (j = 0; j < sigrenderer->n_channels; j++) + for (i = 0; i < rendered; i++) + samples[j][i] += s[0][i*sigrenderer->n_channels+j] >> 8; + destroy_sample_buffer(s); + return rendered; +} + + + +void duh_sigrenderer_get_current_sample(DUH_SIGRENDERER *sigrenderer, float volume, sample_t *samples) +{ + if (sigrenderer) + (*sigrenderer->desc->sigrenderer_get_current_sample)(sigrenderer->sigrenderer, volume, samples); +} + + + +void duh_end_sigrenderer(DUH_SIGRENDERER *sigrenderer) +{ + if (sigrenderer) { + if (sigrenderer->desc->end_sigrenderer) + if (sigrenderer->sigrenderer) + (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer); + + free(sigrenderer); + } +} + + + +DUH_SIGRENDERER *duh_encapsulate_raw_sigrenderer(sigrenderer_t *vsigrenderer, DUH_SIGTYPE_DESC *desc, int n_channels, long pos) +{ + DUH_SIGRENDERER *sigrenderer; + + if (desc->start_sigrenderer && !vsigrenderer) return NULL; + + sigrenderer = malloc(sizeof(*sigrenderer)); + if (!sigrenderer) { + if (desc->end_sigrenderer) + if (vsigrenderer) + (*desc->end_sigrenderer)(vsigrenderer); + return NULL; + } + + sigrenderer->desc = desc; + sigrenderer->sigrenderer = vsigrenderer; + + sigrenderer->n_channels = n_channels; + + sigrenderer->pos = pos; + sigrenderer->subpos = 0; + + sigrenderer->callback = NULL; + + return sigrenderer; +} + + + +sigrenderer_t *duh_get_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type) +{ + if (sigrenderer && sigrenderer->desc->type == type) + return sigrenderer->sigrenderer; + + return NULL; +} + + + +#if 0 +// This function is disabled because we don't know whether we want to destroy +// the sigrenderer if the type doesn't match. We don't even know if we need +// the function at all. Who would want to keep an IT_SIGRENDERER (for +// instance) without keeping the DUH_SIGRENDERER? +sigrenderer_t *duh_decompose_to_raw_sigrenderer(DUH_SIGRENDERER *sigrenderer, long type) +{ + if (sigrenderer && sigrenderer->desc->type == type) { + + + + if (sigrenderer) { + if (sigrenderer->desc->end_sigrenderer) + if (sigrenderer->sigrenderer) + (*sigrenderer->desc->end_sigrenderer)(sigrenderer->sigrenderer); + + free(sigrenderer); + } + + + + + + + return sigrenderer->sigrenderer; + } + + return NULL; +} +#endif diff --git a/plugins/dumb/dumb-kode54/src/core/unload.c b/plugins/dumb/dumb-kode54/src/core/unload.c index f241f718..11d81e26 100644 --- a/plugins/dumb/dumb-kode54/src/core/unload.c +++ b/plugins/dumb/dumb-kode54/src/core/unload.c @@ -1,64 +1,64 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * unload.c - Code to free a DUH from memory. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/dumb.h"
-
-
-
-static void destroy_signal(DUH_SIGNAL *signal)
-{
- if (signal) {
- if (signal->desc)
- if (signal->desc->unload_sigdata)
- if (signal->sigdata)
- (*signal->desc->unload_sigdata)(signal->sigdata);
-
- free(signal);
- }
-}
-
-
-
-/* unload_duh(): destroys a DUH struct. You must call this for every DUH
- * struct created, when you've finished with it.
- */
-void unload_duh(DUH *duh)
-{
- int i;
-
- if (duh) {
- if (duh->signal) {
- for (i = 0; i < duh->n_signals; i++)
- destroy_signal(duh->signal[i]);
-
- free(duh->signal);
- }
-
- if (duh->tag) {
- if (duh->tag[0][0])
- free(duh->tag[0][0]);
- free(duh->tag);
- }
-
- free(duh);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * unload.c - Code to free a DUH from memory. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> + +#include "dumb.h" +#include "internal/dumb.h" + + + +static void destroy_signal(DUH_SIGNAL *signal) +{ + if (signal) { + if (signal->desc) + if (signal->desc->unload_sigdata) + if (signal->sigdata) + (*signal->desc->unload_sigdata)(signal->sigdata); + + free(signal); + } +} + + + +/* unload_duh(): destroys a DUH struct. You must call this for every DUH + * struct created, when you've finished with it. + */ +void unload_duh(DUH *duh) +{ + int i; + + if (duh) { + if (duh->signal) { + for (i = 0; i < duh->n_signals; i++) + destroy_signal(duh->signal[i]); + + free(duh->signal); + } + + if (duh->tag) { + if (duh->tag[0][0]) + free(duh->tag[0][0]); + free(duh->tag); + } + + free(duh); + } +} diff --git a/plugins/dumb/dumb-kode54/src/helpers/barray.c b/plugins/dumb/dumb-kode54/src/helpers/barray.c index 95fe7af1..5877725c 100644 --- a/plugins/dumb/dumb-kode54/src/helpers/barray.c +++ b/plugins/dumb/dumb-kode54/src/helpers/barray.c @@ -1,159 +1,159 @@ -#include "internal/barray.h"
-
-#include <string.h>
-
-
-void * bit_array_create(size_t size)
-{
- size_t bsize = ((size + 7) >> 3) + sizeof(size_t);
- void * ret = calloc(1, bsize);
- if (ret) *(size_t *)ret = size;
- return ret;
-}
-
-void bit_array_destroy(void * array)
-{
- if (array) free(array);
-}
-
-void * bit_array_dup(void * array)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- size_t bsize = ((*size + 7) >> 3) + sizeof(*size);
- void * ret = malloc(bsize);
- if (ret) memcpy(ret, array, bsize);
- return ret;
- }
- return NULL;
-}
-
-void bit_array_reset(void * array)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- size_t bsize = (*size + 7) >> 3;
- memset(size + 1, 0, bsize);
- }
-}
-
-
-void bit_array_set(void * array, size_t bit)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- if (bit < *size)
- {
- unsigned char * ptr = (unsigned char *)(size + 1);
- ptr[bit >> 3] |= (1U << (bit & 7));
- }
- }
-}
-
-int bit_array_test(void * array, size_t bit)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- if (bit < *size)
- {
- unsigned char * ptr = (unsigned char *)(size + 1);
- if (ptr[bit >> 3] & (1U << (bit & 7)))
- {
- return 1;
- }
- }
- }
- return 0;
-}
-
-int bit_array_test_range(void * array, size_t bit, size_t count)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- if (bit < *size)
- {
- unsigned char * ptr = (unsigned char *)(size + 1);
- if ((bit & 7) && (count > 8))
- {
- while ((bit < *size) && count && (bit & 7))
- {
- if (ptr[bit >> 3] & (1U << (bit & 7))) return 1;
- bit++;
- count--;
- }
- }
- if (!(bit & 7))
- {
- while (((*size - bit) >= 8) && (count >= 8))
- {
- if (ptr[bit >> 3]) return 1;
- bit += 8;
- count -= 8;
- }
- }
- while ((bit < *size) && count)
- {
- if (ptr[bit >> 3] & (1U << (bit & 7))) return 1;
- bit++;
- count--;
- }
- }
- }
- return 0;
-}
-
-void bit_array_clear(void * array, size_t bit)
-{
- if (array)
- {
- size_t * size = (size_t *) array;
- if (bit < *size)
- {
- unsigned char * ptr = (unsigned char *)(size + 1);
- ptr[bit >> 3] &= ~(1U << (bit & 7));
- }
- }
-}
-
-void bit_array_merge(void * dest, void * source, size_t offset)
-{
- if (dest && source)
- {
- size_t * dsize = (size_t *) dest;
- size_t * ssize = (size_t *) source;
- size_t soffset = 0;
- while (offset < *dsize && soffset < *ssize)
- {
- if (bit_array_test(source, soffset))
- {
- bit_array_set(dest, offset);
- }
- soffset++;
- offset++;
- }
- }
-}
-
-void bit_array_mask(void * dest, void * source, size_t offset)
-{
- if (dest && source)
- {
- size_t * dsize = (size_t *) dest;
- size_t * ssize = (size_t *) source;
- size_t soffset = 0;
- while (offset < *dsize && soffset < *ssize)
- {
- if (bit_array_test(source, soffset))
- {
- bit_array_clear(dest, offset);
- }
- soffset++;
- offset++;
- }
- }
-}
+#include "internal/barray.h" + +#include <string.h> + + +void * bit_array_create(size_t size) +{ + size_t bsize = ((size + 7) >> 3) + sizeof(size_t); + void * ret = calloc(1, bsize); + if (ret) *(size_t *)ret = size; + return ret; +} + +void bit_array_destroy(void * array) +{ + if (array) free(array); +} + +void * bit_array_dup(void * array) +{ + if (array) + { + size_t * size = (size_t *) array; + size_t bsize = ((*size + 7) >> 3) + sizeof(*size); + void * ret = malloc(bsize); + if (ret) memcpy(ret, array, bsize); + return ret; + } + return NULL; +} + +void bit_array_reset(void * array) +{ + if (array) + { + size_t * size = (size_t *) array; + size_t bsize = (*size + 7) >> 3; + memset(size + 1, 0, bsize); + } +} + + +void bit_array_set(void * array, size_t bit) +{ + if (array) + { + size_t * size = (size_t *) array; + if (bit < *size) + { + unsigned char * ptr = (unsigned char *)(size + 1); + ptr[bit >> 3] |= (1U << (bit & 7)); + } + } +} + +int bit_array_test(void * array, size_t bit) +{ + if (array) + { + size_t * size = (size_t *) array; + if (bit < *size) + { + unsigned char * ptr = (unsigned char *)(size + 1); + if (ptr[bit >> 3] & (1U << (bit & 7))) + { + return 1; + } + } + } + return 0; +} + +int bit_array_test_range(void * array, size_t bit, size_t count) +{ + if (array) + { + size_t * size = (size_t *) array; + if (bit < *size) + { + unsigned char * ptr = (unsigned char *)(size + 1); + if ((bit & 7) && (count > 8)) + { + while ((bit < *size) && count && (bit & 7)) + { + if (ptr[bit >> 3] & (1U << (bit & 7))) return 1; + bit++; + count--; + } + } + if (!(bit & 7)) + { + while (((*size - bit) >= 8) && (count >= 8)) + { + if (ptr[bit >> 3]) return 1; + bit += 8; + count -= 8; + } + } + while ((bit < *size) && count) + { + if (ptr[bit >> 3] & (1U << (bit & 7))) return 1; + bit++; + count--; + } + } + } + return 0; +} + +void bit_array_clear(void * array, size_t bit) +{ + if (array) + { + size_t * size = (size_t *) array; + if (bit < *size) + { + unsigned char * ptr = (unsigned char *)(size + 1); + ptr[bit >> 3] &= ~(1U << (bit & 7)); + } + } +} + +void bit_array_merge(void * dest, void * source, size_t offset) +{ + if (dest && source) + { + size_t * dsize = (size_t *) dest; + size_t * ssize = (size_t *) source; + size_t soffset = 0; + while (offset < *dsize && soffset < *ssize) + { + if (bit_array_test(source, soffset)) + { + bit_array_set(dest, offset); + } + soffset++; + offset++; + } + } +} + +void bit_array_mask(void * dest, void * source, size_t offset) +{ + if (dest && source) + { + size_t * dsize = (size_t *) dest; + size_t * ssize = (size_t *) source; + size_t soffset = 0; + while (offset < *dsize && soffset < *ssize) + { + if (bit_array_test(source, soffset)) + { + bit_array_clear(dest, offset); + } + soffset++; + offset++; + } + } +} diff --git a/plugins/dumb/dumb-kode54/src/helpers/clickrem.c b/plugins/dumb/dumb-kode54/src/helpers/clickrem.c index 336b492d..62885e6a 100644 --- a/plugins/dumb/dumb-kode54/src/helpers/clickrem.c +++ b/plugins/dumb/dumb-kode54/src/helpers/clickrem.c @@ -1,281 +1,281 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * clickrem.c - Click removal helpers. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <math.h>
-#include "dumb.h"
-
-
-
-typedef struct DUMB_CLICK DUMB_CLICK;
-
-
-struct DUMB_CLICK_REMOVER
-{
- DUMB_CLICK *click;
- int n_clicks;
-
- int offset;
-};
-
-
-struct DUMB_CLICK
-{
- DUMB_CLICK *next;
- long pos;
- sample_t step;
-};
-
-
-
-DUMB_CLICK_REMOVER *dumb_create_click_remover(void)
-{
- DUMB_CLICK_REMOVER *cr = malloc(sizeof(*cr));
- if (!cr) return NULL;
-
- cr->click = NULL;
- cr->n_clicks = 0;
-
- cr->offset = 0;
-
- return cr;
-}
-
-
-
-void dumb_record_click(DUMB_CLICK_REMOVER *cr, long pos, sample_t step)
-{
- DUMB_CLICK *click;
-
- ASSERT(pos >= 0);
-
- if (!cr || !step) return;
-
- if (pos == 0) {
- cr->offset -= step;
- return;
- }
-
- click = malloc(sizeof(*click));
- if (!click) return;
-
- click->pos = pos;
- click->step = step;
-
- click->next = cr->click;
- cr->click = click;
- cr->n_clicks++;
-}
-
-
-
-static DUMB_CLICK *dumb_click_mergesort(DUMB_CLICK *click, int n_clicks)
-{
- int i;
- DUMB_CLICK *c1, *c2, **cp;
-
- if (n_clicks <= 1) return click;
-
- /* Split the list into two */
- c1 = click;
- cp = &c1;
- for (i = 0; i < n_clicks; i += 2) cp = &(*cp)->next;
- c2 = *cp;
- *cp = NULL;
-
- /* Sort the sublists */
- c1 = dumb_click_mergesort(c1, (n_clicks + 1) >> 1);
- c2 = dumb_click_mergesort(c2, n_clicks >> 1);
-
- /* Merge them */
- cp = &click;
- while (c1 && c2) {
- if (c1->pos > c2->pos) {
- *cp = c2;
- c2 = c2->next;
- } else {
- *cp = c1;
- c1 = c1->next;
- }
- cp = &(*cp)->next;
- }
- if (c2)
- *cp = c2;
- else
- *cp = c1;
-
- return click;
-}
-
-
-
-void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, int step, float halflife)
-{
- DUMB_CLICK *click;
- long pos = 0;
- int offset;
- int factor;
-
- if (!cr) return;
-
- factor = (int)floor(pow(0.5, 1.0/halflife) * (1U << 31));
-
- click = dumb_click_mergesort(cr->click, cr->n_clicks);
- cr->click = NULL;
- cr->n_clicks = 0;
-
- length *= step;
-
- while (click) {
- DUMB_CLICK *next = click->next;
- int end = click->pos * step;
- ASSERT(end <= length);
- offset = cr->offset;
- if (offset < 0) {
- offset = -offset;
- while (pos < end) {
- samples[pos] -= offset;
- offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
- pos += step;
- }
- offset = -offset;
- } else {
- while (pos < end) {
- samples[pos] += offset;
- offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32);
- pos += step;
- }
- }
- cr->offset = offset - click->step;
- free(click);
- click = next;
- }
-
- offset = cr->offset;
- if (offset < 0) {
- offset = -offset;
- while (pos < length) {
- samples[pos] -= offset;
- offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
- pos += step;
- }
- offset = -offset;
- } else {
- while (pos < length) {
- samples[pos] += offset;
- offset = (int)((LONG_LONG)(offset << 1) * factor >> 32);
- pos += step;
- }
- }
- cr->offset = offset;
-}
-
-
-
-sample_t dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr)
-{
- return cr ? cr->offset : 0;
-}
-
-
-
-void dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr)
-{
- if (cr) {
- DUMB_CLICK *click = cr->click;
- while (click) {
- DUMB_CLICK *next = click->next;
- free(click);
- click = next;
- }
- free(cr);
- }
-}
-
-
-
-DUMB_CLICK_REMOVER **dumb_create_click_remover_array(int n)
-{
- int i;
- DUMB_CLICK_REMOVER **cr;
- if (n <= 0) return NULL;
- cr = malloc(n * sizeof(*cr));
- if (!cr) return NULL;
- for (i = 0; i < n; i++) cr[i] = dumb_create_click_remover();
- return cr;
-}
-
-
-
-void dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step)
-{
- if (cr) {
- int i;
- for (i = 0; i < n; i++)
- dumb_record_click(cr[i], pos, step[i]);
- }
-}
-
-
-
-void dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step)
-{
- if (cr) {
- int i;
- for (i = 0; i < n; i++)
- dumb_record_click(cr[i], pos, -step[i]);
- }
-}
-
-
-
-void dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, long length, float halflife)
-{
- if (cr) {
- int i;
- for (i = 0; i < n >> 1; i++) {
- dumb_remove_clicks(cr[i << 1], samples[i], length, 2, halflife);
- dumb_remove_clicks(cr[(i << 1) + 1], samples[i] + 1, length, 2, halflife);
- }
- if (n & 1)
- dumb_remove_clicks(cr[i << 1], samples[i], length, 1, halflife);
- }
-}
-
-
-
-void dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset)
-{
- if (cr) {
- int i;
- for (i = 0; i < n; i++)
- if (cr[i]) offset[i] += cr[i]->offset;
- }
-}
-
-
-
-void dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr)
-{
- if (cr) {
- int i;
- for (i = 0; i < n; i++) dumb_destroy_click_remover(cr[i]);
- free(cr);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * clickrem.c - Click removal helpers. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <math.h> +#include "dumb.h" + + + +typedef struct DUMB_CLICK DUMB_CLICK; + + +struct DUMB_CLICK_REMOVER +{ + DUMB_CLICK *click; + int n_clicks; + + int offset; +}; + + +struct DUMB_CLICK +{ + DUMB_CLICK *next; + long pos; + sample_t step; +}; + + + +DUMB_CLICK_REMOVER *dumb_create_click_remover(void) +{ + DUMB_CLICK_REMOVER *cr = malloc(sizeof(*cr)); + if (!cr) return NULL; + + cr->click = NULL; + cr->n_clicks = 0; + + cr->offset = 0; + + return cr; +} + + + +void dumb_record_click(DUMB_CLICK_REMOVER *cr, long pos, sample_t step) +{ + DUMB_CLICK *click; + + ASSERT(pos >= 0); + + if (!cr || !step) return; + + if (pos == 0) { + cr->offset -= step; + return; + } + + click = malloc(sizeof(*click)); + if (!click) return; + + click->pos = pos; + click->step = step; + + click->next = cr->click; + cr->click = click; + cr->n_clicks++; +} + + + +static DUMB_CLICK *dumb_click_mergesort(DUMB_CLICK *click, int n_clicks) +{ + int i; + DUMB_CLICK *c1, *c2, **cp; + + if (n_clicks <= 1) return click; + + /* Split the list into two */ + c1 = click; + cp = &c1; + for (i = 0; i < n_clicks; i += 2) cp = &(*cp)->next; + c2 = *cp; + *cp = NULL; + + /* Sort the sublists */ + c1 = dumb_click_mergesort(c1, (n_clicks + 1) >> 1); + c2 = dumb_click_mergesort(c2, n_clicks >> 1); + + /* Merge them */ + cp = &click; + while (c1 && c2) { + if (c1->pos > c2->pos) { + *cp = c2; + c2 = c2->next; + } else { + *cp = c1; + c1 = c1->next; + } + cp = &(*cp)->next; + } + if (c2) + *cp = c2; + else + *cp = c1; + + return click; +} + + + +void dumb_remove_clicks(DUMB_CLICK_REMOVER *cr, sample_t *samples, long length, int step, float halflife) +{ + DUMB_CLICK *click; + long pos = 0; + int offset; + int factor; + + if (!cr) return; + + factor = (int)floor(pow(0.5, 1.0/halflife) * (1U << 31)); + + click = dumb_click_mergesort(cr->click, cr->n_clicks); + cr->click = NULL; + cr->n_clicks = 0; + + length *= step; + + while (click) { + DUMB_CLICK *next = click->next; + int end = click->pos * step; + ASSERT(end <= length); + offset = cr->offset; + if (offset < 0) { + offset = -offset; + while (pos < end) { + samples[pos] -= offset; + offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32); + pos += step; + } + offset = -offset; + } else { + while (pos < end) { + samples[pos] += offset; + offset = (int)(((LONG_LONG)(offset << 1) * factor) >> 32); + pos += step; + } + } + cr->offset = offset - click->step; + free(click); + click = next; + } + + offset = cr->offset; + if (offset < 0) { + offset = -offset; + while (pos < length) { + samples[pos] -= offset; + offset = (int)((LONG_LONG)(offset << 1) * factor >> 32); + pos += step; + } + offset = -offset; + } else { + while (pos < length) { + samples[pos] += offset; + offset = (int)((LONG_LONG)(offset << 1) * factor >> 32); + pos += step; + } + } + cr->offset = offset; +} + + + +sample_t dumb_click_remover_get_offset(DUMB_CLICK_REMOVER *cr) +{ + return cr ? cr->offset : 0; +} + + + +void dumb_destroy_click_remover(DUMB_CLICK_REMOVER *cr) +{ + if (cr) { + DUMB_CLICK *click = cr->click; + while (click) { + DUMB_CLICK *next = click->next; + free(click); + click = next; + } + free(cr); + } +} + + + +DUMB_CLICK_REMOVER **dumb_create_click_remover_array(int n) +{ + int i; + DUMB_CLICK_REMOVER **cr; + if (n <= 0) return NULL; + cr = malloc(n * sizeof(*cr)); + if (!cr) return NULL; + for (i = 0; i < n; i++) cr[i] = dumb_create_click_remover(); + return cr; +} + + + +void dumb_record_click_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step) +{ + if (cr) { + int i; + for (i = 0; i < n; i++) + dumb_record_click(cr[i], pos, step[i]); + } +} + + + +void dumb_record_click_negative_array(int n, DUMB_CLICK_REMOVER **cr, long pos, sample_t *step) +{ + if (cr) { + int i; + for (i = 0; i < n; i++) + dumb_record_click(cr[i], pos, -step[i]); + } +} + + + +void dumb_remove_clicks_array(int n, DUMB_CLICK_REMOVER **cr, sample_t **samples, long length, float halflife) +{ + if (cr) { + int i; + for (i = 0; i < n >> 1; i++) { + dumb_remove_clicks(cr[i << 1], samples[i], length, 2, halflife); + dumb_remove_clicks(cr[(i << 1) + 1], samples[i] + 1, length, 2, halflife); + } + if (n & 1) + dumb_remove_clicks(cr[i << 1], samples[i], length, 1, halflife); + } +} + + + +void dumb_click_remover_get_offset_array(int n, DUMB_CLICK_REMOVER **cr, sample_t *offset) +{ + if (cr) { + int i; + for (i = 0; i < n; i++) + if (cr[i]) offset[i] += cr[i]->offset; + } +} + + + +void dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr) +{ + if (cr) { + int i; + for (i = 0; i < n; i++) dumb_destroy_click_remover(cr[i]); + free(cr); + } +} diff --git a/plugins/dumb/dumb-kode54/src/helpers/memfile.c b/plugins/dumb/dumb-kode54/src/helpers/memfile.c index 6fcbbc7c..bf6d510f 100644 --- a/plugins/dumb/dumb-kode54/src/helpers/memfile.c +++ b/plugins/dumb/dumb-kode54/src/helpers/memfile.c @@ -1,96 +1,96 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * memfile.c - Module for reading data from / / \ \
- * memory using a DUMBFILE. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-
-
-
-typedef struct MEMFILE MEMFILE;
-
-struct MEMFILE
-{
- const char *ptr;
- long left;
-};
-
-
-
-static int dumb_memfile_skip(void *f, long n)
-{
- MEMFILE *m = f;
- if (n > m->left) return -1;
- m->ptr += n;
- m->left -= n;
- return 0;
-}
-
-
-
-static int dumb_memfile_getc(void *f)
-{
- MEMFILE *m = f;
- if (m->left <= 0) return -1;
- m->left--;
- return *(const unsigned char *)m->ptr++;
-}
-
-
-
-static long dumb_memfile_getnc(char *ptr, long n, void *f)
-{
- MEMFILE *m = f;
- if (n > m->left) n = m->left;
- memcpy(ptr, m->ptr, n);
- m->ptr += n;
- m->left -= n;
- return n;
-}
-
-
-
-static void dumb_memfile_close(void *f)
-{
- free(f);
-}
-
-
-
-static const DUMBFILE_SYSTEM memfile_dfs = {
- NULL,
- &dumb_memfile_skip,
- &dumb_memfile_getc,
- &dumb_memfile_getnc,
- &dumb_memfile_close
-};
-
-
-
-DUMBFILE *dumbfile_open_memory(const char *data, long size)
-{
- MEMFILE *m = malloc(sizeof(*m));
- if (!m) return NULL;
-
- m->ptr = data;
- m->left = size;
-
- return dumbfile_open_ex(m, &memfile_dfs);
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * memfile.c - Module for reading data from / / \ \ + * memory using a DUMBFILE. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" + + + +typedef struct MEMFILE MEMFILE; + +struct MEMFILE +{ + const char *ptr; + long left; +}; + + + +static int dumb_memfile_skip(void *f, long n) +{ + MEMFILE *m = f; + if (n > m->left) return -1; + m->ptr += n; + m->left -= n; + return 0; +} + + + +static int dumb_memfile_getc(void *f) +{ + MEMFILE *m = f; + if (m->left <= 0) return -1; + m->left--; + return *(const unsigned char *)m->ptr++; +} + + + +static long dumb_memfile_getnc(char *ptr, long n, void *f) +{ + MEMFILE *m = f; + if (n > m->left) n = m->left; + memcpy(ptr, m->ptr, n); + m->ptr += n; + m->left -= n; + return n; +} + + + +static void dumb_memfile_close(void *f) +{ + free(f); +} + + + +static const DUMBFILE_SYSTEM memfile_dfs = { + NULL, + &dumb_memfile_skip, + &dumb_memfile_getc, + &dumb_memfile_getnc, + &dumb_memfile_close +}; + + + +DUMBFILE *dumbfile_open_memory(const char *data, long size) +{ + MEMFILE *m = malloc(sizeof(*m)); + if (!m) return NULL; + + m->ptr = data; + m->left = size; + + return dumbfile_open_ex(m, &memfile_dfs); +} diff --git a/plugins/dumb/dumb-kode54/src/helpers/resample.c b/plugins/dumb/dumb-kode54/src/helpers/resample.c index 033538c5..54b98d08 100644 --- a/plugins/dumb/dumb-kode54/src/helpers/resample.c +++ b/plugins/dumb/dumb-kode54/src/helpers/resample.c @@ -1,393 +1,393 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * resample.c - Resampling helpers. / / \ \
- * | < / \_
- * By Bob and entheh. | \/ /\ /
- * \_ / > /
- * In order to find a good trade-off between | \ / /
- * speed and accuracy in this code, some tests | ' /
- * were carried out regarding the behaviour of \__/
- * long long ints with gcc. The following code
- * was tested:
- *
- * int a, b, c;
- * c = ((long long)a * b) >> 16;
- *
- * DJGPP GCC Version 3.0.3 generated the following assembly language code for
- * the multiplication and scaling, leaving the 32-bit result in EAX.
- *
- * movl -8(%ebp), %eax ; read one int into EAX
- * imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX
- * shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX
- *
- * Note that a 32*32->64 multiplication is performed, allowing for high
- * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally),
- * so it is a minor concern when four multiplications are being performed
- * (the cubic resampler). On the Pentium MMX and earlier, it takes four or
- * more cycles, so this method is unsuitable for use in the low-quality
- * resamplers.
- *
- * Since "long long" is a gcc-specific extension, we use LONG_LONG instead,
- * defined in dumb.h. We may investigate later what code MSVC generates, but
- * if it seems too slow then we suggest you use a good compiler.
- *
- * FIXME: these comments are somewhat out of date now.
- */
-
-#include <math.h>
-#include "dumb.h"
-
-
-
-/* Compile with -DHEAVYDEBUG if you want to make sure the pick-up function is
- * called when it should be. There will be a considerable performance hit,
- * since at least one condition has to be tested for every sample generated.
- */
-#ifdef HEAVYDEBUG
-#define HEAVYASSERT(cond) ASSERT(cond)
-#else
-#define HEAVYASSERT(cond)
-#endif
-
-
-
-/* Make MSVC shut the hell up about if ( upd ) UPDATE_VOLUME() conditions being constant */
-#ifdef _MSC_VER
-#pragma warning(disable:4127 4701)
-#endif
-
-
-
-/* A global variable for controlling resampling quality wherever a local
- * specification doesn't override it. The following values are valid:
- *
- * 0 - DUMB_RQ_ALIASING - fastest
- * 1 - DUMB_RQ_LINEAR
- * 2 - DUMB_RQ_CUBIC - nicest
- *
- * Values outside the range 0-2 will behave the same as the nearest
- * value within the range.
- */
-int dumb_resampling_quality = DUMB_RQ_CUBIC;
-
-
-
-//#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16))
-//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14)
-#define MULSCV(a, b) ((int)((LONG_LONG)(a) * (b) >> 32))
-#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32))
-#define MULSC16(a, b) ((int)((LONG_LONG)((a) << 12) * ((b) << 12) >> 32))
-
-
-
-/* Executes the content 'iterator' times.
- * Clobbers the 'iterator' variable.
- * The loop is unrolled by four.
- */
-#define LOOP4(iterator, CONTENT) \
-{ \
- if ((iterator) & 2) { \
- CONTENT; \
- CONTENT; \
- } \
- if ((iterator) & 1) { \
- CONTENT; \
- } \
- (iterator) >>= 2; \
- while (iterator) { \
- CONTENT; \
- CONTENT; \
- CONTENT; \
- CONTENT; \
- (iterator)--; \
- } \
-}
-
-
-
-#define PASTERAW(a, b) a ## b /* This does not expand macros in b ... */
-#define PASTE(a, b) PASTERAW(a, b) /* ... but b is expanded during this substitution. */
-
-#define X PASTE(x.x, SRCBITS)
-
-
-
-/* Cubic resampler: look-up tables
- *
- * a = 1.5*x1 - 1.5*x2 + 0.5*x3 - 0.5*x0
- * b = 2*x2 + x0 - 2.5*x1 - 0.5*x3
- * c = 0.5*x2 - 0.5*x0
- * d = x1
- *
- * x = a*t*t*t + b*t*t + c*t + d
- * = (-0.5*x0 + 1.5*x1 - 1.5*x2 + 0.5*x3) * t*t*t +
- * ( 1*x0 - 2.5*x1 + 2 *x2 - 0.5*x3) * t*t +
- * (-0.5*x0 + 0.5*x2 ) * t +
- * ( 1*x1 )
- * = (-0.5*t*t*t + 1 *t*t - 0.5*t ) * x0 +
- * ( 1.5*t*t*t - 2.5*t*t + 1) * x1 +
- * (-1.5*t*t*t + 2 *t*t + 0.5*t ) * x2 +
- * ( 0.5*t*t*t - 0.5*t*t ) * x3
- * = A0(t) * x0 + A1(t) * x1 + A2(t) * x2 + A3(t) * x3
- *
- * A0, A1, A2 and A3 stay within the range [-1,1].
- * In the tables, they are scaled with 14 fractional bits.
- *
- * Turns out we don't need to store A2 and A3; they are symmetrical to A1 and A0.
- *
- * TODO: A0 and A3 stay very small indeed. Consider different scale/resolution?
- */
-
-static short cubicA0[1025], cubicA1[1025];
-
-/*static*/ void init_cubic(void)
-{
- unsigned int t; /* 3*1024*1024*1024 is within range if it's unsigned */
- static int done = 0;
- if (done) return;
- done = 1;
- for (t = 0; t < 1025; t++) {
- /* int casts to pacify warnings about negating unsigned values */
- cubicA0[t] = -(int)( t*t*t >> 17) + (int)( t*t >> 6) - (int)(t << 3);
- cubicA1[t] = (int)(3*t*t*t >> 17) - (int)(5*t*t >> 7) + (int)(1 << 14);
- }
-}
-
-
-
-/* Create resamplers for 24-in-32-bit source samples. */
-
-/* #define SUFFIX
- * MSVC warns if we try to paste a null SUFFIX, so instead we define
- * special macros for the function names that don't bother doing the
- * corresponding paste. The more generic definitions are further down.
- */
-#define process_pickup PASTE(process_pickup, SUFFIX2)
-#define dumb_resample PASTE(PASTE(dumb_resample, SUFFIX2), SUFFIX3)
-#define dumb_resample_get_current_sample PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX2), SUFFIX3)
-
-#define SRCTYPE sample_t
-#define SRCBITS 24
-#define ALIAS(x, vol) MULSC(x, vol)
-#define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos))
-/*
-#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
- a = (3 * (x1 - x2) + (x3 - x0)) >> 1; \
- b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) >> 1; \
- c = (x2 - x0) >> 1; \
-}
-#define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + d, vol)
-*/
-#define CUBIC(x0, x1, x2, x3) ( \
- MULSC(x0, cubicA0[subpos >> 6] << 2) + \
- MULSC(x1, cubicA1[subpos >> 6] << 2) + \
- MULSC(x2, cubicA1[1 + (subpos >> 6 ^ 1023)] << 2) + \
- MULSC(x3, cubicA0[1 + (subpos >> 6 ^ 1023)] << 2))
-#define CUBICVOL(x, vol) MULSC(x, vol)
-#include "resample.inc"
-
-/* Undefine the simplified macros. */
-#undef dumb_resample_get_current_sample
-#undef dumb_resample
-#undef process_pickup
-
-
-/* Now define the proper ones that use SUFFIX. */
-#define dumb_reset_resampler PASTE(dumb_reset_resampler, SUFFIX)
-#define dumb_start_resampler PASTE(dumb_start_resampler, SUFFIX)
-#define process_pickup PASTE(PASTE(process_pickup, SUFFIX), SUFFIX2)
-#define dumb_resample PASTE(PASTE(PASTE(dumb_resample, SUFFIX), SUFFIX2), SUFFIX3)
-#define dumb_resample_get_current_sample PASTE(PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX), SUFFIX2), SUFFIX3)
-#define dumb_end_resampler PASTE(dumb_end_resampler, SUFFIX)
-
-/* Create resamplers for 16-bit source samples. */
-#define SUFFIX _16
-#define SRCTYPE short
-#define SRCBITS 16
-#define ALIAS(x, vol) (x * vol >> 8)
-#define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos))
-/*
-#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
- a = (3 * (x1 - x2) + (x3 - x0)) << 7; \
- b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) << 7; \
- c = (x2 - x0) << 7; \
-}
-#define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + (d << 8), vol)
-*/
-#define CUBIC(x0, x1, x2, x3) ( \
- x0 * cubicA0[subpos >> 6] + \
- x1 * cubicA1[subpos >> 6] + \
- x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \
- x3 * cubicA0[1 + (subpos >> 6 ^ 1023)])
-#define CUBICVOL(x, vol) (int)((LONG_LONG)(x) * (vol << 10) >> 32)
-#include "resample.inc"
-
-/* Create resamplers for 8-bit source samples. */
-#define SUFFIX _8
-#define SRCTYPE signed char
-#define SRCBITS 8
-#define ALIAS(x, vol) (x * vol)
-#define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos)
-/*
-#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \
- a = 3 * (x1 - x2) + (x3 - x0); \
- b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) << 15; \
- c = (x2 - x0) << 15; \
-}
-#define CUBIC(d) MULSC(MULSC(MULSC((a * subpos >> 1) + b, subpos) + c, subpos) + (d << 16), vol)
-*/
-#define CUBIC(x0, x1, x2, x3) (( \
- x0 * cubicA0[subpos >> 6] + \
- x1 * cubicA1[subpos >> 6] + \
- x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \
- x3 * cubicA0[1 + (subpos >> 6 ^ 1023)]) << 6)
-#define CUBICVOL(x, vol) (int)((LONG_LONG)(x) * (vol << 12) >> 32)
-#include "resample.inc"
-
-
-#undef dumb_reset_resampler
-#undef dumb_start_resampler
-#undef process_pickup
-#undef dumb_resample
-#undef dumb_resample_get_current_sample
-#undef dumb_end_resampler
-
-
-
-void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, long pos, long start, long end, int quality)
-{
- if (n == 8)
- dumb_reset_resampler_8(resampler, src, src_channels, pos, start, end, quality);
- else if (n == 16)
- dumb_reset_resampler_16(resampler, src, src_channels, pos, start, end, quality);
- else
- dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality);
-}
-
-
-
-DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, long pos, long start, long end, int quality)
-{
- if (n == 8)
- return dumb_start_resampler_8(src, src_channels, pos, start, end, quality);
- else if (n == 16)
- return dumb_start_resampler_16(src, src_channels, pos, start, end, quality);
- else
- return dumb_start_resampler(src, src_channels, pos, start, end, quality);
-}
-
-
-
-long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta)
-{
- if (n == 8)
- return dumb_resample_8_1_1(resampler, dst, dst_size, volume, delta);
- else if (n == 16)
- return dumb_resample_16_1_1(resampler, dst, dst_size, volume, delta);
- else
- return dumb_resample_1_1(resampler, dst, dst_size, volume, delta);
-}
-
-
-
-long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
-{
- if (n == 8)
- return dumb_resample_8_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
- else if (n == 16)
- return dumb_resample_16_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
- else
- return dumb_resample_1_2(resampler, dst, dst_size, volume_left, volume_right, delta);
-}
-
-
-
-long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
-{
- if (n == 8)
- return dumb_resample_8_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
- else if (n == 16)
- return dumb_resample_16_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
- else
- return dumb_resample_2_1(resampler, dst, dst_size, volume_left, volume_right, delta);
-}
-
-
-
-long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta)
-{
- if (n == 8)
- return dumb_resample_8_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
- else if (n == 16)
- return dumb_resample_16_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
- else
- return dumb_resample_2_2(resampler, dst, dst_size, volume_left, volume_right, delta);
-}
-
-
-
-void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst)
-{
- if (n == 8)
- dumb_resample_get_current_sample_8_1_1(resampler, volume, dst);
- else if (n == 16)
- dumb_resample_get_current_sample_16_1_1(resampler, volume, dst);
- else
- dumb_resample_get_current_sample_1_1(resampler, volume, dst);
-}
-
-
-
-void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
-{
- if (n == 8)
- dumb_resample_get_current_sample_8_1_2(resampler, volume_left, volume_right, dst);
- else if (n == 16)
- dumb_resample_get_current_sample_16_1_2(resampler, volume_left, volume_right, dst);
- else
- dumb_resample_get_current_sample_1_2(resampler, volume_left, volume_right, dst);
-}
-
-
-
-void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
-{
- if (n == 8)
- dumb_resample_get_current_sample_8_2_1(resampler, volume_left, volume_right, dst);
- else if (n == 16)
- dumb_resample_get_current_sample_16_2_1(resampler, volume_left, volume_right, dst);
- else
- dumb_resample_get_current_sample_2_1(resampler, volume_left, volume_right, dst);
-}
-
-
-
-void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst)
-{
- if (n == 8)
- dumb_resample_get_current_sample_8_2_2(resampler, volume_left, volume_right, dst);
- else if (n == 16)
- dumb_resample_get_current_sample_16_2_2(resampler, volume_left, volume_right, dst);
- else
- dumb_resample_get_current_sample_2_2(resampler, volume_left, volume_right, dst);
-}
-
-
-
-void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler)
-{
- if (n == 8)
- dumb_end_resampler_8(resampler);
- else if (n == 16)
- dumb_end_resampler_16(resampler);
- else
- dumb_end_resampler(resampler);
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * resample.c - Resampling helpers. / / \ \ + * | < / \_ + * By Bob and entheh. | \/ /\ / + * \_ / > / + * In order to find a good trade-off between | \ / / + * speed and accuracy in this code, some tests | ' / + * were carried out regarding the behaviour of \__/ + * long long ints with gcc. The following code + * was tested: + * + * int a, b, c; + * c = ((long long)a * b) >> 16; + * + * DJGPP GCC Version 3.0.3 generated the following assembly language code for + * the multiplication and scaling, leaving the 32-bit result in EAX. + * + * movl -8(%ebp), %eax ; read one int into EAX + * imull -4(%ebp) ; multiply by the other; result goes in EDX:EAX + * shrdl $16, %edx, %eax ; shift EAX right 16, shifting bits in from EDX + * + * Note that a 32*32->64 multiplication is performed, allowing for high + * accuracy. On the Pentium 2 and above, shrdl takes two cycles (generally), + * so it is a minor concern when four multiplications are being performed + * (the cubic resampler). On the Pentium MMX and earlier, it takes four or + * more cycles, so this method is unsuitable for use in the low-quality + * resamplers. + * + * Since "long long" is a gcc-specific extension, we use LONG_LONG instead, + * defined in dumb.h. We may investigate later what code MSVC generates, but + * if it seems too slow then we suggest you use a good compiler. + * + * FIXME: these comments are somewhat out of date now. + */ + +#include <math.h> +#include "dumb.h" + + + +/* Compile with -DHEAVYDEBUG if you want to make sure the pick-up function is + * called when it should be. There will be a considerable performance hit, + * since at least one condition has to be tested for every sample generated. + */ +#ifdef HEAVYDEBUG +#define HEAVYASSERT(cond) ASSERT(cond) +#else +#define HEAVYASSERT(cond) +#endif + + + +/* Make MSVC shut the hell up about if ( upd ) UPDATE_VOLUME() conditions being constant */ +#ifdef _MSC_VER +#pragma warning(disable:4127 4701) +#endif + + + +/* A global variable for controlling resampling quality wherever a local + * specification doesn't override it. The following values are valid: + * + * 0 - DUMB_RQ_ALIASING - fastest + * 1 - DUMB_RQ_LINEAR + * 2 - DUMB_RQ_CUBIC - nicest + * + * Values outside the range 0-2 will behave the same as the nearest + * value within the range. + */ +int dumb_resampling_quality = DUMB_RQ_CUBIC; + + + +//#define MULSC(a, b) ((int)((LONG_LONG)(a) * (b) >> 16)) +//#define MULSC(a, b) ((a) * ((b) >> 2) >> 14) +#define MULSCV(a, b) ((int)((LONG_LONG)(a) * (b) >> 32)) +#define MULSC(a, b) ((int)((LONG_LONG)((a) << 4) * ((b) << 12) >> 32)) +#define MULSC16(a, b) ((int)((LONG_LONG)((a) << 12) * ((b) << 12) >> 32)) + + + +/* Executes the content 'iterator' times. + * Clobbers the 'iterator' variable. + * The loop is unrolled by four. + */ +#define LOOP4(iterator, CONTENT) \ +{ \ + if ((iterator) & 2) { \ + CONTENT; \ + CONTENT; \ + } \ + if ((iterator) & 1) { \ + CONTENT; \ + } \ + (iterator) >>= 2; \ + while (iterator) { \ + CONTENT; \ + CONTENT; \ + CONTENT; \ + CONTENT; \ + (iterator)--; \ + } \ +} + + + +#define PASTERAW(a, b) a ## b /* This does not expand macros in b ... */ +#define PASTE(a, b) PASTERAW(a, b) /* ... but b is expanded during this substitution. */ + +#define X PASTE(x.x, SRCBITS) + + + +/* Cubic resampler: look-up tables + * + * a = 1.5*x1 - 1.5*x2 + 0.5*x3 - 0.5*x0 + * b = 2*x2 + x0 - 2.5*x1 - 0.5*x3 + * c = 0.5*x2 - 0.5*x0 + * d = x1 + * + * x = a*t*t*t + b*t*t + c*t + d + * = (-0.5*x0 + 1.5*x1 - 1.5*x2 + 0.5*x3) * t*t*t + + * ( 1*x0 - 2.5*x1 + 2 *x2 - 0.5*x3) * t*t + + * (-0.5*x0 + 0.5*x2 ) * t + + * ( 1*x1 ) + * = (-0.5*t*t*t + 1 *t*t - 0.5*t ) * x0 + + * ( 1.5*t*t*t - 2.5*t*t + 1) * x1 + + * (-1.5*t*t*t + 2 *t*t + 0.5*t ) * x2 + + * ( 0.5*t*t*t - 0.5*t*t ) * x3 + * = A0(t) * x0 + A1(t) * x1 + A2(t) * x2 + A3(t) * x3 + * + * A0, A1, A2 and A3 stay within the range [-1,1]. + * In the tables, they are scaled with 14 fractional bits. + * + * Turns out we don't need to store A2 and A3; they are symmetrical to A1 and A0. + * + * TODO: A0 and A3 stay very small indeed. Consider different scale/resolution? + */ + +static short cubicA0[1025], cubicA1[1025]; + +/*static*/ void init_cubic(void) +{ + unsigned int t; /* 3*1024*1024*1024 is within range if it's unsigned */ + static int done = 0; + if (done) return; + done = 1; + for (t = 0; t < 1025; t++) { + /* int casts to pacify warnings about negating unsigned values */ + cubicA0[t] = -(int)( t*t*t >> 17) + (int)( t*t >> 6) - (int)(t << 3); + cubicA1[t] = (int)(3*t*t*t >> 17) - (int)(5*t*t >> 7) + (int)(1 << 14); + } +} + + + +/* Create resamplers for 24-in-32-bit source samples. */ + +/* #define SUFFIX + * MSVC warns if we try to paste a null SUFFIX, so instead we define + * special macros for the function names that don't bother doing the + * corresponding paste. The more generic definitions are further down. + */ +#define process_pickup PASTE(process_pickup, SUFFIX2) +#define dumb_resample PASTE(PASTE(dumb_resample, SUFFIX2), SUFFIX3) +#define dumb_resample_get_current_sample PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX2), SUFFIX3) + +#define SRCTYPE sample_t +#define SRCBITS 24 +#define ALIAS(x, vol) MULSC(x, vol) +#define LINEAR(x0, x1) (x0 + MULSC(x1 - x0, subpos)) +/* +#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \ + a = (3 * (x1 - x2) + (x3 - x0)) >> 1; \ + b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) >> 1; \ + c = (x2 - x0) >> 1; \ +} +#define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + d, vol) +*/ +#define CUBIC(x0, x1, x2, x3) ( \ + MULSC(x0, cubicA0[subpos >> 6] << 2) + \ + MULSC(x1, cubicA1[subpos >> 6] << 2) + \ + MULSC(x2, cubicA1[1 + (subpos >> 6 ^ 1023)] << 2) + \ + MULSC(x3, cubicA0[1 + (subpos >> 6 ^ 1023)] << 2)) +#define CUBICVOL(x, vol) MULSC(x, vol) +#include "resample.inc" + +/* Undefine the simplified macros. */ +#undef dumb_resample_get_current_sample +#undef dumb_resample +#undef process_pickup + + +/* Now define the proper ones that use SUFFIX. */ +#define dumb_reset_resampler PASTE(dumb_reset_resampler, SUFFIX) +#define dumb_start_resampler PASTE(dumb_start_resampler, SUFFIX) +#define process_pickup PASTE(PASTE(process_pickup, SUFFIX), SUFFIX2) +#define dumb_resample PASTE(PASTE(PASTE(dumb_resample, SUFFIX), SUFFIX2), SUFFIX3) +#define dumb_resample_get_current_sample PASTE(PASTE(PASTE(dumb_resample_get_current_sample, SUFFIX), SUFFIX2), SUFFIX3) +#define dumb_end_resampler PASTE(dumb_end_resampler, SUFFIX) + +/* Create resamplers for 16-bit source samples. */ +#define SUFFIX _16 +#define SRCTYPE short +#define SRCBITS 16 +#define ALIAS(x, vol) (x * vol >> 8) +#define LINEAR(x0, x1) ((x0 << 8) + MULSC16(x1 - x0, subpos)) +/* +#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \ + a = (3 * (x1 - x2) + (x3 - x0)) << 7; \ + b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) << 7; \ + c = (x2 - x0) << 7; \ +} +#define CUBIC(d) MULSC(MULSC(MULSC(MULSC(a, subpos) + b, subpos) + c, subpos) + (d << 8), vol) +*/ +#define CUBIC(x0, x1, x2, x3) ( \ + x0 * cubicA0[subpos >> 6] + \ + x1 * cubicA1[subpos >> 6] + \ + x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \ + x3 * cubicA0[1 + (subpos >> 6 ^ 1023)]) +#define CUBICVOL(x, vol) (int)((LONG_LONG)(x) * (vol << 10) >> 32) +#include "resample.inc" + +/* Create resamplers for 8-bit source samples. */ +#define SUFFIX _8 +#define SRCTYPE signed char +#define SRCBITS 8 +#define ALIAS(x, vol) (x * vol) +#define LINEAR(x0, x1) ((x0 << 16) + (x1 - x0) * subpos) +/* +#define SET_CUBIC_COEFFICIENTS(x0, x1, x2, x3) { \ + a = 3 * (x1 - x2) + (x3 - x0); \ + b = ((x2 << 2) + (x0 << 1) - (5 * x1 + x3)) << 15; \ + c = (x2 - x0) << 15; \ +} +#define CUBIC(d) MULSC(MULSC(MULSC((a * subpos >> 1) + b, subpos) + c, subpos) + (d << 16), vol) +*/ +#define CUBIC(x0, x1, x2, x3) (( \ + x0 * cubicA0[subpos >> 6] + \ + x1 * cubicA1[subpos >> 6] + \ + x2 * cubicA1[1 + (subpos >> 6 ^ 1023)] + \ + x3 * cubicA0[1 + (subpos >> 6 ^ 1023)]) << 6) +#define CUBICVOL(x, vol) (int)((LONG_LONG)(x) * (vol << 12) >> 32) +#include "resample.inc" + + +#undef dumb_reset_resampler +#undef dumb_start_resampler +#undef process_pickup +#undef dumb_resample +#undef dumb_resample_get_current_sample +#undef dumb_end_resampler + + + +void dumb_reset_resampler_n(int n, DUMB_RESAMPLER *resampler, void *src, int src_channels, long pos, long start, long end, int quality) +{ + if (n == 8) + dumb_reset_resampler_8(resampler, src, src_channels, pos, start, end, quality); + else if (n == 16) + dumb_reset_resampler_16(resampler, src, src_channels, pos, start, end, quality); + else + dumb_reset_resampler(resampler, src, src_channels, pos, start, end, quality); +} + + + +DUMB_RESAMPLER *dumb_start_resampler_n(int n, void *src, int src_channels, long pos, long start, long end, int quality) +{ + if (n == 8) + return dumb_start_resampler_8(src, src_channels, pos, start, end, quality); + else if (n == 16) + return dumb_start_resampler_16(src, src_channels, pos, start, end, quality); + else + return dumb_start_resampler(src, src_channels, pos, start, end, quality); +} + + + +long dumb_resample_n_1_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume, float delta) +{ + if (n == 8) + return dumb_resample_8_1_1(resampler, dst, dst_size, volume, delta); + else if (n == 16) + return dumb_resample_16_1_1(resampler, dst, dst_size, volume, delta); + else + return dumb_resample_1_1(resampler, dst, dst_size, volume, delta); +} + + + +long dumb_resample_n_1_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta) +{ + if (n == 8) + return dumb_resample_8_1_2(resampler, dst, dst_size, volume_left, volume_right, delta); + else if (n == 16) + return dumb_resample_16_1_2(resampler, dst, dst_size, volume_left, volume_right, delta); + else + return dumb_resample_1_2(resampler, dst, dst_size, volume_left, volume_right, delta); +} + + + +long dumb_resample_n_2_1(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta) +{ + if (n == 8) + return dumb_resample_8_2_1(resampler, dst, dst_size, volume_left, volume_right, delta); + else if (n == 16) + return dumb_resample_16_2_1(resampler, dst, dst_size, volume_left, volume_right, delta); + else + return dumb_resample_2_1(resampler, dst, dst_size, volume_left, volume_right, delta); +} + + + +long dumb_resample_n_2_2(int n, DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, float delta) +{ + if (n == 8) + return dumb_resample_8_2_2(resampler, dst, dst_size, volume_left, volume_right, delta); + else if (n == 16) + return dumb_resample_16_2_2(resampler, dst, dst_size, volume_left, volume_right, delta); + else + return dumb_resample_2_2(resampler, dst, dst_size, volume_left, volume_right, delta); +} + + + +void dumb_resample_get_current_sample_n_1_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume, sample_t *dst) +{ + if (n == 8) + dumb_resample_get_current_sample_8_1_1(resampler, volume, dst); + else if (n == 16) + dumb_resample_get_current_sample_16_1_1(resampler, volume, dst); + else + dumb_resample_get_current_sample_1_1(resampler, volume, dst); +} + + + +void dumb_resample_get_current_sample_n_1_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst) +{ + if (n == 8) + dumb_resample_get_current_sample_8_1_2(resampler, volume_left, volume_right, dst); + else if (n == 16) + dumb_resample_get_current_sample_16_1_2(resampler, volume_left, volume_right, dst); + else + dumb_resample_get_current_sample_1_2(resampler, volume_left, volume_right, dst); +} + + + +void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst) +{ + if (n == 8) + dumb_resample_get_current_sample_8_2_1(resampler, volume_left, volume_right, dst); + else if (n == 16) + dumb_resample_get_current_sample_16_2_1(resampler, volume_left, volume_right, dst); + else + dumb_resample_get_current_sample_2_1(resampler, volume_left, volume_right, dst); +} + + + +void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst) +{ + if (n == 8) + dumb_resample_get_current_sample_8_2_2(resampler, volume_left, volume_right, dst); + else if (n == 16) + dumb_resample_get_current_sample_16_2_2(resampler, volume_left, volume_right, dst); + else + dumb_resample_get_current_sample_2_2(resampler, volume_left, volume_right, dst); +} + + + +void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler) +{ + if (n == 8) + dumb_end_resampler_8(resampler); + else if (n == 16) + dumb_end_resampler_16(resampler); + else + dumb_end_resampler(resampler); +} diff --git a/plugins/dumb/dumb-kode54/src/helpers/riff.c b/plugins/dumb/dumb-kode54/src/helpers/riff.c index 62a7eccc..7a7ef065 100644 --- a/plugins/dumb/dumb-kode54/src/helpers/riff.c +++ b/plugins/dumb/dumb-kode54/src/helpers/riff.c @@ -1,88 +1,88 @@ -#include "internal/riff.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-struct riff * riff_parse( unsigned char * ptr, unsigned size, unsigned proper )
-{
- unsigned stream_size;
- struct riff * stream;
-
- if ( size < 8 ) return 0;
-
- if ( ptr[0] != 'R' || ptr[1] != 'I' || ptr[2] != 'F' || ptr[3] != 'F' ) return 0;
-
- stream_size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 );
- if ( stream_size + 8 > size ) return 0;
- if ( stream_size < 4 ) return 0;
-
- stream = malloc( sizeof( struct riff ) );
- if ( ! stream ) return 0;
-
- stream->type = ( ptr[8] << 24 ) | ( ptr[9] << 16 ) | ( ptr[10] << 8 ) | ptr[11];
- stream->chunk_count = 0;
- stream->chunks = 0;
-
- ptr += 12;
- stream_size -= 4;
-
- while ( stream_size )
- {
- struct riff_chunk * chunk;
- if ( stream_size < 8 ) break;
- stream->chunks = realloc( stream->chunks, ( stream->chunk_count + 1 ) * sizeof( struct riff_chunk ) );
- if ( ! stream->chunks ) break;
- chunk = stream->chunks + stream->chunk_count;
- chunk->type = ( ptr[0] << 24 ) | ( ptr[1] << 16 ) | ( ptr[2] << 8 ) | ptr[3];
- chunk->size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 );
- ptr += 8;
- stream_size -= 8;
- if ( stream_size < chunk->size ) break;
- if ( chunk->type == 'RIFF' )
- {
- chunk->data = riff_parse( ptr - 8, chunk->size + 8, proper );
- if ( ! chunk->data ) break;
- }
- else
- {
- chunk->data = malloc( chunk->size );
- if ( ! chunk->data ) break;
- memcpy( chunk->data, ptr, chunk->size );
- }
- ptr += chunk->size;
- stream_size -= chunk->size;
- if ( proper && ( chunk->size & 1 ) )
- {
- ++ ptr;
- -- stream_size;
- }
- ++stream->chunk_count;
- }
-
- if ( stream_size )
- {
- riff_free( stream );
- stream = 0;
- }
-
- return stream;
-}
-
-void riff_free( struct riff * stream )
-{
- if ( stream )
- {
- if ( stream->chunks )
- {
- unsigned i;
- for ( i = 0; i < stream->chunk_count; ++i )
- {
- struct riff_chunk * chunk = stream->chunks + i;
- if ( chunk->type == 'RIFF' ) riff_free( ( struct riff * ) chunk->data );
- else free( chunk->data );
- }
- free( stream->chunks );
- }
- free( stream );
- }
-}
+#include "internal/riff.h" + +#include <stdlib.h> +#include <string.h> + +struct riff * riff_parse( unsigned char * ptr, unsigned size, unsigned proper ) +{ + unsigned stream_size; + struct riff * stream; + + if ( size < 8 ) return 0; + + if ( ptr[0] != 'R' || ptr[1] != 'I' || ptr[2] != 'F' || ptr[3] != 'F' ) return 0; + + stream_size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 ); + if ( stream_size + 8 > size ) return 0; + if ( stream_size < 4 ) return 0; + + stream = malloc( sizeof( struct riff ) ); + if ( ! stream ) return 0; + + stream->type = ( ptr[8] << 24 ) | ( ptr[9] << 16 ) | ( ptr[10] << 8 ) | ptr[11]; + stream->chunk_count = 0; + stream->chunks = 0; + + ptr += 12; + stream_size -= 4; + + while ( stream_size ) + { + struct riff_chunk * chunk; + if ( stream_size < 8 ) break; + stream->chunks = realloc( stream->chunks, ( stream->chunk_count + 1 ) * sizeof( struct riff_chunk ) ); + if ( ! stream->chunks ) break; + chunk = stream->chunks + stream->chunk_count; + chunk->type = ( ptr[0] << 24 ) | ( ptr[1] << 16 ) | ( ptr[2] << 8 ) | ptr[3]; + chunk->size = ptr[4] | ( ptr[5] << 8 ) | ( ptr[6] << 16 ) | ( ptr[7] << 24 ); + ptr += 8; + stream_size -= 8; + if ( stream_size < chunk->size ) break; + if ( chunk->type == 'RIFF' ) + { + chunk->data = riff_parse( ptr - 8, chunk->size + 8, proper ); + if ( ! chunk->data ) break; + } + else + { + chunk->data = malloc( chunk->size ); + if ( ! chunk->data ) break; + memcpy( chunk->data, ptr, chunk->size ); + } + ptr += chunk->size; + stream_size -= chunk->size; + if ( proper && ( chunk->size & 1 ) ) + { + ++ ptr; + -- stream_size; + } + ++stream->chunk_count; + } + + if ( stream_size ) + { + riff_free( stream ); + stream = 0; + } + + return stream; +} + +void riff_free( struct riff * stream ) +{ + if ( stream ) + { + if ( stream->chunks ) + { + unsigned i; + for ( i = 0; i < stream->chunk_count; ++i ) + { + struct riff_chunk * chunk = stream->chunks + i; + if ( chunk->type == 'RIFF' ) riff_free( ( struct riff * ) chunk->data ); + else free( chunk->data ); + } + free( stream->chunks ); + } + free( stream ); + } +} diff --git a/plugins/dumb/dumb-kode54/src/helpers/sampbuf.c b/plugins/dumb/dumb-kode54/src/helpers/sampbuf.c index 488db449..6a80f1fa 100644 --- a/plugins/dumb/dumb-kode54/src/helpers/sampbuf.c +++ b/plugins/dumb/dumb-kode54/src/helpers/sampbuf.c @@ -1,64 +1,64 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * sampbuf.c - Helper for allocating sample / / \ \
- * buffers. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include "dumb.h"
-
-
-
-/* DEPRECATED */
-sample_t **create_sample_buffer(int n_channels, long length)
-{
- int i;
- sample_t **samples = malloc(n_channels * sizeof(*samples));
- if (!samples) return NULL;
- samples[0] = malloc(n_channels * length * sizeof(*samples[0]));
- if (!samples[0]) {
- free(samples);
- return NULL;
- }
- for (i = 1; i < n_channels; i++) samples[i] = samples[i-1] + length;
- return samples;
-}
-
-
-
-sample_t **allocate_sample_buffer(int n_channels, long length)
-{
- int i;
- sample_t **samples = malloc(((n_channels + 1) >> 1) * sizeof(*samples));
- if (!samples) return NULL;
- samples[0] = malloc(n_channels * length * sizeof(*samples[0]));
- if (!samples[0]) {
- free(samples);
- return NULL;
- }
- for (i = 1; i < (n_channels + 1) >> 1; i++) samples[i] = samples[i-1] + length*2;
- return samples;
-}
-
-
-
-void destroy_sample_buffer(sample_t **samples)
-{
- if (samples) {
- free(samples[0]);
- free(samples);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * sampbuf.c - Helper for allocating sample / / \ \ + * buffers. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include "dumb.h" + + + +/* DEPRECATED */ +sample_t **create_sample_buffer(int n_channels, long length) +{ + int i; + sample_t **samples = malloc(n_channels * sizeof(*samples)); + if (!samples) return NULL; + samples[0] = malloc(n_channels * length * sizeof(*samples[0])); + if (!samples[0]) { + free(samples); + return NULL; + } + for (i = 1; i < n_channels; i++) samples[i] = samples[i-1] + length; + return samples; +} + + + +sample_t **allocate_sample_buffer(int n_channels, long length) +{ + int i; + sample_t **samples = malloc(((n_channels + 1) >> 1) * sizeof(*samples)); + if (!samples) return NULL; + samples[0] = malloc(n_channels * length * sizeof(*samples[0])); + if (!samples[0]) { + free(samples); + return NULL; + } + for (i = 1; i < (n_channels + 1) >> 1; i++) samples[i] = samples[i-1] + length*2; + return samples; +} + + + +void destroy_sample_buffer(sample_t **samples) +{ + if (samples) { + free(samples[0]); + free(samples); + } +} diff --git a/plugins/dumb/dumb-kode54/src/helpers/silence.c b/plugins/dumb/dumb-kode54/src/helpers/silence.c index 794ae831..4d5fdcf4 100644 --- a/plugins/dumb/dumb-kode54/src/helpers/silence.c +++ b/plugins/dumb/dumb-kode54/src/helpers/silence.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * silence.c - Silencing helper. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <string.h>
-#include "dumb.h"
-
-
-
-void dumb_silence(sample_t *samples, long length)
-{
- memset(samples, 0, length * sizeof(*samples));
-}
-
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * silence.c - Silencing helper. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <string.h> +#include "dumb.h" + + + +void dumb_silence(sample_t *samples, long length) +{ + memset(samples, 0, length * sizeof(*samples)); +} + diff --git a/plugins/dumb/dumb-kode54/src/helpers/stdfile.c b/plugins/dumb/dumb-kode54/src/helpers/stdfile.c index aa398f50..2f02539a 100644 --- a/plugins/dumb/dumb-kode54/src/helpers/stdfile.c +++ b/plugins/dumb/dumb-kode54/src/helpers/stdfile.c @@ -1,93 +1,93 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * stdfile.c - stdio file input module. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdio.h>
-
-#include "dumb.h"
-
-
-
-static void *dumb_stdfile_open(const char *filename)
-{
- return fopen(filename, "rb");
-}
-
-
-
-static int dumb_stdfile_skip(void *f, long n)
-{
- return fseek(f, n, SEEK_CUR);
-}
-
-
-
-static int dumb_stdfile_getc(void *f)
-{
- return fgetc(f);
-}
-
-
-
-static long dumb_stdfile_getnc(char *ptr, long n, void *f)
-{
- return fread(ptr, 1, n, f);
-}
-
-
-
-static void dumb_stdfile_close(void *f)
-{
- fclose(f);
-}
-
-
-
-static DUMBFILE_SYSTEM stdfile_dfs = {
- &dumb_stdfile_open,
- &dumb_stdfile_skip,
- &dumb_stdfile_getc,
- &dumb_stdfile_getnc,
- &dumb_stdfile_close
-};
-
-
-
-void dumb_register_stdfiles(void)
-{
- register_dumbfile_system(&stdfile_dfs);
-}
-
-
-
-static DUMBFILE_SYSTEM stdfile_dfs_leave_open = {
- NULL,
- &dumb_stdfile_skip,
- &dumb_stdfile_getc,
- &dumb_stdfile_getnc,
- NULL
-};
-
-
-
-DUMBFILE *dumbfile_open_stdfile(FILE *p)
-{
- DUMBFILE *d = dumbfile_open_ex(p, &stdfile_dfs_leave_open);
-
- return d;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * stdfile.c - stdio file input module. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdio.h> + +#include "dumb.h" + + + +static void *dumb_stdfile_open(const char *filename) +{ + return fopen(filename, "rb"); +} + + + +static int dumb_stdfile_skip(void *f, long n) +{ + return fseek(f, n, SEEK_CUR); +} + + + +static int dumb_stdfile_getc(void *f) +{ + return fgetc(f); +} + + + +static long dumb_stdfile_getnc(char *ptr, long n, void *f) +{ + return fread(ptr, 1, n, f); +} + + + +static void dumb_stdfile_close(void *f) +{ + fclose(f); +} + + + +static DUMBFILE_SYSTEM stdfile_dfs = { + &dumb_stdfile_open, + &dumb_stdfile_skip, + &dumb_stdfile_getc, + &dumb_stdfile_getnc, + &dumb_stdfile_close +}; + + + +void dumb_register_stdfiles(void) +{ + register_dumbfile_system(&stdfile_dfs); +} + + + +static DUMBFILE_SYSTEM stdfile_dfs_leave_open = { + NULL, + &dumb_stdfile_skip, + &dumb_stdfile_getc, + &dumb_stdfile_getnc, + NULL +}; + + + +DUMBFILE *dumbfile_open_stdfile(FILE *p) +{ + DUMBFILE *d = dumbfile_open_ex(p, &stdfile_dfs_leave_open); + + return d; +} diff --git a/plugins/dumb/dumb-kode54/src/it/itload.c b/plugins/dumb/dumb-kode54/src/it/itload.c index 30004233..a26f5e10 100644 --- a/plugins/dumb/dumb-kode54/src/it/itload.c +++ b/plugins/dumb/dumb-kode54/src/it/itload.c @@ -1,43 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itload.c - Code to read an Impulse Tracker / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By entheh. Don't worry Bob, you're credited | \ / /
- * in itread.c! | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_it_quick(): loads an IT file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must pass
- * the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_it_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_it_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
-
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * itload.c - Code to read an Impulse Tracker / / \ \ + * file, opening and closing it for | < / \_ + * you. | \/ /\ / + * \_ / > / + * By entheh. Don't worry Bob, you're credited | \ / / + * in itread.c! | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_it_quick(): loads an IT file into a DUH struct, returning a + * pointer to the DUH struct. When you have finished with it, you must pass + * the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_it_quick(const char *filename) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_it_quick(f); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/itload2.c b/plugins/dumb/dumb-kode54/src/it/itload2.c index 15cff1d0..2dd65a71 100644 --- a/plugins/dumb/dumb-kode54/src/it/itload2.c +++ b/plugins/dumb/dumb-kode54/src/it/itload2.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itload2.c - Function to read an Impulse Tracker / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from itload.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_it(const char *filename)
-{
- DUH *duh = dumb_load_it_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * itload2.c - Function to read an Impulse Tracker / / \ \ + * file, opening and closing it for | < / \_ + * you, and do an initial run-through. | \/ /\ / + * \_ / > / + * Split off from itload.c by entheh. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_load_it(const char *filename) +{ + DUH *duh = dumb_load_it_quick(filename); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/itmisc.c b/plugins/dumb/dumb-kode54/src/it/itmisc.c index 22e18b78..0eee1717 100644 --- a/plugins/dumb/dumb-kode54/src/it/itmisc.c +++ b/plugins/dumb/dumb-kode54/src/it/itmisc.c @@ -1,247 +1,249 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itmisc.c - Miscellaneous functions relating / / \ \
- * to module files. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh)
-{
- return duh_get_raw_sigdata(duh, 0, SIGTYPE_IT);
-}
-
-
-
-const unsigned char *dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->song_message : NULL;
-}
-
-
-
-int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->n_orders : 0;
-}
-
-
-
-int dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->n_samples : 0;
-}
-
-
-
-int dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->n_instruments : 0;
-}
-
-
-
-const unsigned char *dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i)
-{
- ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples);
- return sd->sample[i].name;
-}
-
-
-
-const unsigned char *dumb_it_sd_get_sample_filename(DUMB_IT_SIGDATA *sd, int i)
-{
- ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples);
- return sd->sample[i].filename;
-}
-
-
-
-const unsigned char *dumb_it_sd_get_instrument_name(DUMB_IT_SIGDATA *sd, int i)
-{
- ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments);
- return sd->instrument[i].name;
-}
-
-
-
-const unsigned char *dumb_it_sd_get_instrument_filename(DUMB_IT_SIGDATA *sd, int i)
-{
- ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments);
- return sd->instrument[i].filename;
-}
-
-
-
-int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->global_volume : 0;
-}
-
-
-
-void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv)
-{
- if (sd) sd->global_volume = gv;
-}
-
-
-
-int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->mixing_volume : 0;
-}
-
-
-
-void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv)
-{
- if (sd) sd->mixing_volume = mv;
-}
-
-
-
-int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->speed : 0;
-}
-
-
-
-void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed)
-{
- if (sd) sd->speed = speed;
-}
-
-
-
-int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd)
-{
- return sd ? sd->tempo : 0;
-}
-
-
-
-void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo)
-{
- if (sd) sd->tempo = tempo;
-}
-
-
-
-int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel)
-{
- ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
- return sd ? sd->channel_volume[channel] : 0;
-}
-
-void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume)
-{
- ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS);
- if (sd) sd->channel_volume[channel] = volume;
-}
-
-
-
-int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr)
-{
- return sr ? sr->order : -1;
-}
-
-
-
-int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr)
-{
- return sr ? sr->row : -1;
-}
-
-
-
-int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr)
-{
- return sr ? sr->globalvolume : 0;
-}
-
-
-
-void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv)
-{
- if (sr) sr->globalvolume = gv;
-}
-
-
-
-int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr)
-{
- return sr ? sr->tempo : 0;
-}
-
-
-
-void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo)
-{
- if (sr) sr->tempo = tempo;
-}
-
-
-
-int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr)
-{
- return sr ? sr->speed : 0;
-}
-
-
-
-void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed)
-{
- if (sr) sr->speed = speed;
-}
-
-
-
-int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel)
-{
- return sr ? sr->channel[channel].channelvolume : 0;
-}
-
-
-
-void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume)
-{
- if (sr) sr->channel[channel].channelvolume = volume;
-}
-
-
-
-void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted)
-{
- if (sr) {
- if (muted)
- sr->channel[channel].flags |= IT_CHANNEL_MUTED;
- else
- sr->channel[channel].flags &= ~IT_CHANNEL_MUTED;
- }
-}
-
-
-
-int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel)
-{
- return sr ? (sr->channel[channel].flags & IT_CHANNEL_MUTED) != 0 : 0;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * itmisc.c - Miscellaneous functions relating / / \ \ + * to module files. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh) +{ + return duh_get_raw_sigdata(duh, 0, SIGTYPE_IT); +} + + + +const unsigned char *dumb_it_sd_get_song_message(DUMB_IT_SIGDATA *sd) +{ + return sd ? sd->song_message : NULL; +} + + + +int dumb_it_sd_get_n_orders(DUMB_IT_SIGDATA *sd) +{ + return sd ? sd->n_orders : 0; +} + + + +int dumb_it_sd_get_n_samples(DUMB_IT_SIGDATA *sd) +{ + return sd ? sd->n_samples : 0; +} + + + +int dumb_it_sd_get_n_instruments(DUMB_IT_SIGDATA *sd) +{ + return sd ? sd->n_instruments : 0; +} + + + +const unsigned char *dumb_it_sd_get_sample_name(DUMB_IT_SIGDATA *sd, int i) +{ + ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples); + return sd->sample[i].name; +} + + + +const unsigned char *dumb_it_sd_get_sample_filename(DUMB_IT_SIGDATA *sd, int i) +{ + ASSERT(sd && sd->sample && i >= 0 && i < sd->n_samples); + return sd->sample[i].filename; +} + + + +const unsigned char *dumb_it_sd_get_instrument_name(DUMB_IT_SIGDATA *sd, int i) +{ + ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments); + return sd->instrument[i].name; +} + + + +const unsigned char *dumb_it_sd_get_instrument_filename(DUMB_IT_SIGDATA *sd, int i) +{ + ASSERT(sd && sd->instrument && i >= 0 && i < sd->n_instruments); + return sd->instrument[i].filename; +} + + + +int dumb_it_sd_get_initial_global_volume(DUMB_IT_SIGDATA *sd) +{ + return sd ? sd->global_volume : 0; +} + + + +void dumb_it_sd_set_initial_global_volume(DUMB_IT_SIGDATA *sd, int gv) +{ + if (sd) sd->global_volume = gv; +} + + + +int dumb_it_sd_get_mixing_volume(DUMB_IT_SIGDATA *sd) +{ + return sd ? sd->mixing_volume : 0; +} + + + +void dumb_it_sd_set_mixing_volume(DUMB_IT_SIGDATA *sd, int mv) +{ + if (sd) sd->mixing_volume = mv; +} + + + +int dumb_it_sd_get_initial_speed(DUMB_IT_SIGDATA *sd) +{ + return sd ? sd->speed : 0; +} + + + +void dumb_it_sd_set_initial_speed(DUMB_IT_SIGDATA *sd, int speed) +{ + if (sd) sd->speed = speed; +} + + + +int dumb_it_sd_get_initial_tempo(DUMB_IT_SIGDATA *sd) +{ + return sd ? sd->tempo : 0; +} + + + +void dumb_it_sd_set_initial_tempo(DUMB_IT_SIGDATA *sd, int tempo) +{ + if (sd) sd->tempo = tempo; +} + + + +int dumb_it_sd_get_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel) +{ + ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS); + return sd ? sd->channel_volume[channel] : 0; +} + +void dumb_it_sd_set_initial_channel_volume(DUMB_IT_SIGDATA *sd, int channel, int volume) +{ + ASSERT(channel >= 0 && channel < DUMB_IT_N_CHANNELS); + if (sd) sd->channel_volume[channel] = volume; +} + + + +int dumb_it_sr_get_current_order(DUMB_IT_SIGRENDERER *sr) +{ + return sr ? sr->order : -1; +} + + + +int dumb_it_sr_get_current_row(DUMB_IT_SIGRENDERER *sr) +{ + return sr ? sr->row : -1; +} + + + +int dumb_it_sr_get_global_volume(DUMB_IT_SIGRENDERER *sr) +{ + return sr ? sr->globalvolume : 0; +} + + + +void dumb_it_sr_set_global_volume(DUMB_IT_SIGRENDERER *sr, int gv) +{ + if (sr) sr->globalvolume = gv; +} + + + +int dumb_it_sr_get_tempo(DUMB_IT_SIGRENDERER *sr) +{ + return sr ? sr->tempo : 0; +} + + + +void dumb_it_sr_set_tempo(DUMB_IT_SIGRENDERER *sr, int tempo) +{ + if (sr) sr->tempo = tempo; +} + + + +int dumb_it_sr_get_speed(DUMB_IT_SIGRENDERER *sr) +{ + return sr ? sr->speed : 0; +} + + + +void dumb_it_sr_set_speed(DUMB_IT_SIGRENDERER *sr, int speed) +{ + if (sr) sr->speed = speed; +} + + + +int dumb_it_sr_get_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel) +{ + return sr ? sr->channel[channel].channelvolume : 0; +} + + + +void dumb_it_sr_set_channel_volume(DUMB_IT_SIGRENDERER *sr, int channel, int volume) +{ + if (sr) sr->channel[channel].channelvolume = volume; +} + + + +void dumb_it_sr_set_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel, int muted) +{ + if (sr) { + if (muted) + sr->channel[channel].flags |= IT_CHANNEL_MUTED; + else + sr->channel[channel].flags &= ~IT_CHANNEL_MUTED; + } +} + + + +int dumb_it_sr_get_channel_muted(DUMB_IT_SIGRENDERER *sr, int channel) +{ + return sr ? (sr->channel[channel].flags & IT_CHANNEL_MUTED) != 0 : 0; +} + + diff --git a/plugins/dumb/dumb-kode54/src/it/itorder.c b/plugins/dumb/dumb-kode54/src/it/itorder.c index c3fe51cb..6959f054 100644 --- a/plugins/dumb/dumb-kode54/src/it/itorder.c +++ b/plugins/dumb/dumb-kode54/src/it/itorder.c @@ -1,63 +1,63 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itorder.c - Code to fix invalid patterns in / / \ \
- * the pattern table. | < / \_
- * | \/ /\ /
- * By Julien Cugniere. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* This function ensures that any pattern mentioned in the order table but
- * not present in the pattern table is treated as an empty 64 rows pattern.
- * This is done by adding such a dummy pattern at the end of the pattern
- * table, and redirect invalid orders to it.
- * Patterns 254 and 255 are left untouched, unless the signal is an XM.
- */
-int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata)
-{
- int i;
- int found_some = 0;
-
- int first_invalid = sigdata->n_patterns;
- int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;
-
- for (i = 0; i < sigdata->n_orders; i++) {
- if (sigdata->order[i] >= first_invalid && sigdata->order[i] <= last_invalid) {
- sigdata->order[i] = sigdata->n_patterns;
- found_some = 1;
- }
- }
-
- if (found_some) {
- IT_PATTERN *new_pattern = realloc(sigdata->pattern, sizeof(*sigdata->pattern) * (sigdata->n_patterns + 1));
- if (!new_pattern)
- return -1;
-
- new_pattern[sigdata->n_patterns].n_rows = 64;
- new_pattern[sigdata->n_patterns].n_entries = 0;
- new_pattern[sigdata->n_patterns].entry = NULL;
- sigdata->pattern = new_pattern;
- sigdata->n_patterns++;
- }
-
- return 0;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * itorder.c - Code to fix invalid patterns in / / \ \ + * the pattern table. | < / \_ + * | \/ /\ / + * By Julien Cugniere. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + + + +#include <stdlib.h> + +#include "dumb.h" +#include "internal/it.h" + + + +/* This function ensures that any pattern mentioned in the order table but + * not present in the pattern table is treated as an empty 64 rows pattern. + * This is done by adding such a dummy pattern at the end of the pattern + * table, and redirect invalid orders to it. + * Patterns 254 and 255 are left untouched, unless the signal is an XM. + */ +int _dumb_it_fix_invalid_orders(DUMB_IT_SIGDATA *sigdata) +{ + int i; + int found_some = 0; + + int first_invalid = sigdata->n_patterns; + int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253; + + for (i = 0; i < sigdata->n_orders; i++) { + if (sigdata->order[i] >= first_invalid && sigdata->order[i] <= last_invalid) { + sigdata->order[i] = sigdata->n_patterns; + found_some = 1; + } + } + + if (found_some) { + IT_PATTERN *new_pattern = realloc(sigdata->pattern, sizeof(*sigdata->pattern) * (sigdata->n_patterns + 1)); + if (!new_pattern) + return -1; + + new_pattern[sigdata->n_patterns].n_rows = 64; + new_pattern[sigdata->n_patterns].n_entries = 0; + new_pattern[sigdata->n_patterns].entry = NULL; + sigdata->pattern = new_pattern; + sigdata->n_patterns++; + } + + return 0; +} diff --git a/plugins/dumb/dumb-kode54/src/it/itread.c b/plugins/dumb/dumb-kode54/src/it/itread.c index 8f5e7ef6..7170a57f 100644 --- a/plugins/dumb/dumb-kode54/src/it/itread.c +++ b/plugins/dumb/dumb-kode54/src/it/itread.c @@ -1,1332 +1,1343 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itread.c - Code to read an Impulse Tracker / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * Based on the loader from an IT player by Bob. \_ / > /
- * Adapted for DUMB by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>//might not be necessary later; required for memset
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-#define INVESTIGATE_OLD_INSTRUMENTS
-
-
-
-static int it_seek(DUMBFILE *f, long offset)
-{
- long pos = dumbfile_pos(f);
-
- if (pos > offset)
- return -1;
-
- if (pos < offset)
- if (dumbfile_skip(f, offset - pos))
- return -1;
-
- return 0;
-}
-
-
-
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long dword;
-
-typedef struct readblock_crap readblock_crap;
-
-struct readblock_crap {
- unsigned char *sourcebuf;
- unsigned char *sourcepos;
- unsigned char *sourceend;
- int rembits;
-};
-
-
-static int readblock(DUMBFILE *f, readblock_crap * crap)
-{
- long size;
- int c;
-
- size = dumbfile_igetw(f);
- if (size < 0)
- return size;
-
- crap->sourcebuf = malloc(size);
- if (!crap->sourcebuf)
- return -1;
-
- c = dumbfile_getnc((char *)crap->sourcebuf, size, f);
- if (c < size) {
- free(crap->sourcebuf);
- crap->sourcebuf = NULL;
- return -1;
- }
-
- crap->sourcepos = crap->sourcebuf;
- crap->sourceend = crap->sourcebuf + size;
- crap->rembits = 8;
- return 0;
-}
-
-
-
-static void freeblock(readblock_crap * crap)
-{
- free(crap->sourcebuf);
- crap->sourcebuf = NULL;
-}
-
-
-
-static int readbits(int bitwidth, readblock_crap * crap)
-{
- int val = 0;
- int b = 0;
-
- if (crap->sourcepos >= crap->sourceend) return val;
-
- while (bitwidth > crap->rembits) {
- val |= *crap->sourcepos++ << b;
- if (crap->sourcepos >= crap->sourceend) return val;
- b += crap->rembits;
- bitwidth -= crap->rembits;
- crap->rembits = 8;
- }
-
- val |= (*crap->sourcepos & ((1 << bitwidth) - 1)) << b;
- *crap->sourcepos >>= bitwidth;
- crap->rembits -= bitwidth;
-
- return val;
-}
-
-
-
-/** WARNING - do we even need to pass `right`? */
-/** WARNING - why bother memsetting at all? The whole array is written... */
-// if we do memset, dumb_silence() would be neater...
-static int decompress8(DUMBFILE *f, signed char *data, int len, int it215)
-{
- int blocklen, blockpos;
- byte bitwidth;
- word val;
- char d1, d2;
- readblock_crap crap;
-
- memset(&crap, 0, sizeof(crap));
-
- memset(data, 0, len * sizeof(*data));
-
- while (len > 0) {
- //Read a block of compressed data:
- if (readblock(f, &crap))
- return -1;
- //Set up a few variables
- blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes
- blockpos = 0;
- bitwidth = 9;
- d1 = d2 = 0;
- //Start the decompression:
- while (blockpos < blocklen) {
- //Read a value:
- val = (word)readbits(bitwidth, &crap);
- //Check for bit width change:
-
- if (bitwidth < 7) { //Method 1:
- if (val == (1 << (bitwidth - 1))) {
- val = (word)readbits(3, &crap) + 1;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth < 9) { //Method 2
- byte border = (0xFF >> (9 - bitwidth)) - 4;
-
- if (val > border && val <= (border + 8)) {
- val -= border;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth == 9) { //Method 3
- if (val & 0x100) {
- bitwidth = (val + 1) & 0xFF;
- continue;
- }
- }
- else { //Illegal width, abort ?
- freeblock(&crap);
- return -1;
- }
-
- //Expand the value to signed byte:
- {
- char v; //The sample value:
- if (bitwidth < 8) {
- byte shift = 8 - bitwidth;
- v = (val << shift);
- v >>= shift;
- }
- else
- v = (char)val;
-
- //And integrate the sample value
- //(It always has to end with integration doesn't it ? ;-)
- d1 += v;
- d2 += d1;
- }
-
- //Store !
- /* Version 2.15 was an unofficial version with hacked compression
- * code. Yay, better compression :D
- */
- *data++ = it215 ? d2 : d1;
- len--;
- blockpos++;
- }
- freeblock(&crap);
- }
- return 0;
-}
-
-
-
-static int decompress16(DUMBFILE *f, short *data, int len, int it215)
-{
- int blocklen, blockpos;
- byte bitwidth;
- long val;
- short d1, d2;
- readblock_crap crap;
-
- memset(&crap, 0, sizeof(crap));
-
- memset(data, 0, len * sizeof(*data));
-
- while (len > 0) {
- //Read a block of compressed data:
- if (readblock(f, &crap))
- return -1;
- //Set up a few variables
- blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes
- blockpos = 0;
- bitwidth = 17;
- d1 = d2 = 0;
- //Start the decompression:
- while (blockpos < blocklen) {
- val = readbits(bitwidth, &crap);
- //Check for bit width change:
-
- if (bitwidth < 7) { //Method 1:
- if (val == (1 << (bitwidth - 1))) {
- val = readbits(4, &crap) + 1;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth < 17) { //Method 2
- word border = (0xFFFF >> (17 - bitwidth)) - 8;
-
- if (val > border && val <= (border + 16)) {
- val -= border;
- bitwidth = val < bitwidth ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth == 17) { //Method 3
- if (val & 0x10000) {
- bitwidth = (val + 1) & 0xFF;
- continue;
- }
- }
- else { //Illegal width, abort ?
- freeblock(&crap);
- return -1;
- }
-
- //Expand the value to signed byte:
- {
- short v; //The sample value:
- if (bitwidth < 16) {
- byte shift = 16 - bitwidth;
- v = (short)(val << shift);
- v >>= shift;
- }
- else
- v = (short)val;
-
- //And integrate the sample value
- //(It always has to end with integration doesn't it ? ;-)
- d1 += v;
- d2 += d1;
- }
-
- //Store !
- /* Version 2.15 was an unofficial version with hacked compression
- * code. Yay, better compression :D
- */
- *data++ = it215 ? d2 : d1;
- len--;
- blockpos++;
- }
- freeblock(&crap);
- }
- return 0;
-}
-
-
-
-static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f)
-{
- int n;
-
- envelope->flags = dumbfile_getc(f);
- envelope->n_nodes = dumbfile_getc(f);
- envelope->loop_start = dumbfile_getc(f);
- envelope->loop_end = dumbfile_getc(f);
- envelope->sus_loop_start = dumbfile_getc(f);
- envelope->sus_loop_end = dumbfile_getc(f);
- for (n = 0; n < envelope->n_nodes; n++) {
- envelope->node_y[n] = dumbfile_getc(f);
- envelope->node_t[n] = dumbfile_igetw(f);
- }
- dumbfile_skip(f, 75 - envelope->n_nodes * 3 + 1);
-
- if (envelope->n_nodes <= 0)
- envelope->flags &= ~IT_ENVELOPE_ON;
- else {
- if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON;
- if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;
- }
-
- return dumbfile_error(f);
-}
-
-
-
-static int it_read_old_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f)
-{
- int n;
-
- /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)
- return -1;*/
- // XXX
- dumbfile_skip(f, 4);
-
- dumbfile_getnc(instrument->filename, 13, f);
- instrument->filename[13] = 0;
-
- instrument->volume_envelope.flags = dumbfile_getc(f);
- instrument->volume_envelope.loop_start = dumbfile_getc(f);
- instrument->volume_envelope.loop_end = dumbfile_getc(f);
- instrument->volume_envelope.sus_loop_start = dumbfile_getc(f);
- instrument->volume_envelope.sus_loop_end = dumbfile_getc(f);
-
- /* Skip two unused bytes. */
- dumbfile_skip(f, 2);
-
- /* In the old instrument format, fadeout ranges from 0 to 64, and is
- * subtracted at intervals from a value starting at 512. In the new
- * format, all these values are doubled. Therefore we double when loading
- * from the old instrument format - that way we don't have to think about
- * it later.
- */
- instrument->fadeout = dumbfile_igetw(f) << 1;
- instrument->new_note_action = dumbfile_getc(f);
- instrument->dup_check_type = dumbfile_getc(f);
- instrument->dup_check_action = DCA_NOTE_CUT; // This might be wrong!
- /** WARNING - what is the duplicate check action for old-style instruments? */
-
- /* Skip Tracker Version and Number of Samples. These are only used in
- * separate instrument files. Also skip unused byte.
- */
- dumbfile_skip(f, 4);
-
- dumbfile_getnc(instrument->name, 26, f);
- instrument->name[26] = 0;
-
- /* Skip unused bytes following the Instrument Name. */
- dumbfile_skip(f, 6);
-
- instrument->pp_separation = 0;
- instrument->pp_centre = 60;
- instrument->global_volume = 128;
- /** WARNING - should global_volume be 64 or something? */
- instrument->default_pan = 32;
- /** WARNING - should default_pan be 128, meaning don`t use? */
- instrument->random_volume = 0;
- instrument->random_pan = 0;
-
- for (n = 0; n < 120; n++) {
- instrument->map_note[n] = dumbfile_getc(f);
- instrument->map_sample[n] = dumbfile_getc(f);
- }
-
- /* Skip "Volume envelope (200 bytes)". */
- // - need to know better what this is for though.
- dumbfile_skip(f, 200);
-
-#ifdef INVESTIGATE_OLD_INSTRUMENTS
- fprintf(stderr, "Inst %02d Env:", n);
-#endif
-
- for (n = 0; n < 25; n++)
- {
- instrument->volume_envelope.node_t[n] = dumbfile_getc(f);
- instrument->volume_envelope.node_y[n] = dumbfile_getc(f);
-
-#ifdef INVESTIGATE_OLD_INSTRUMENTS
- fprintf(stderr, " %d,%d",
- instrument->volume_envelope.node_t[n],
- instrument->volume_envelope.node_y[n]);
-#endif
-
- // This loop is unfinished, as we can probably escape from it before
- // the end if we want to. Hence the otherwise useless dumbfile_skip()
- // call below.
- }
- dumbfile_skip(f, 50 - (n << 1));
- instrument->volume_envelope.n_nodes = n;
-
-#ifdef INVESTIGATE_OLD_INSTRUMENTS
- fprintf(stderr, "\n");
-#endif
-
- if (dumbfile_error(f))
- return -1;
-
- {
- IT_ENVELOPE *envelope = &instrument->volume_envelope;
- if (envelope->n_nodes <= 0)
- envelope->flags &= ~IT_ENVELOPE_ON;
- else {
- if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON;
- if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;
- }
- }
-
- instrument->filter_cutoff = 127;
- instrument->filter_resonance = 0;
-
- instrument->pan_envelope.flags = 0;
- instrument->pitch_envelope.flags = 0;
-
- return 0;
-}
-
-
-
-static int it_read_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f, int maxlen)
-{
- int n, len;
-
- /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE)
- return -1;*/
- // XXX
-
- if (maxlen) len = dumbfile_pos(f);
-
- dumbfile_skip(f, 4);
-
- dumbfile_getnc(instrument->filename, 13, f);
- instrument->filename[13] = 0;
-
- instrument->new_note_action = dumbfile_getc(f);
- instrument->dup_check_type = dumbfile_getc(f);
- instrument->dup_check_action = dumbfile_getc(f);
- instrument->fadeout = dumbfile_igetw(f);
- instrument->pp_separation = dumbfile_getc(f);
- instrument->pp_centre = dumbfile_getc(f);
- instrument->global_volume = dumbfile_getc(f);
- instrument->default_pan = dumbfile_getc(f);
- instrument->random_volume = dumbfile_getc(f);
- instrument->random_pan = dumbfile_getc(f);
-
- /* Skip Tracker Version and Number of Samples. These are only used in
- * separate instrument files. Also skip unused byte.
- */
- dumbfile_skip(f, 4);
-
- dumbfile_getnc(instrument->name, 26, f);
- instrument->name[26] = 0;
-
- instrument->filter_cutoff = dumbfile_getc(f);
- instrument->filter_resonance = dumbfile_getc(f);
-
- /* Skip MIDI Channel, Program and Bank. */
- //dumbfile_skip(f, 4);
- /*instrument->output = dumbfile_getc(f);
- if ( instrument->output > 16 ) {
- instrument->output -= 128;
- } else {
- instrument->output = 0;
- }
- dumbfile_skip(f, 3);*/
- dumbfile_skip(f, 4);
-
- for (n = 0; n < 120; n++) {
- instrument->map_note[n] = dumbfile_getc(f);
- instrument->map_sample[n] = dumbfile_getc(f);
- }
-
- if (dumbfile_error(f))
- return -1;
-
- if (it_read_envelope(&instrument->volume_envelope, f)) return -1;
- if (it_read_envelope(&instrument->pan_envelope, f)) return -1;
- if (it_read_envelope(&instrument->pitch_envelope, f)) return -1;
-
- if (maxlen) {
- len = dumbfile_pos(f) - len;
- if ( maxlen - len < 124 ) return 0;
- }
-
- if ( dumbfile_mgetl(f) == IT_MPTX_SIGNATURE ) {
- for ( n = 0; n < 120; n++ ) {
- instrument->map_sample[ n ] += dumbfile_getc( f ) << 8;
- }
-
- if (dumbfile_error(f))
- return -1;
- }
-
- /*if ( dumbfile_mgetl(f) == IT_INSM_SIGNATURE ) {
- long end = dumbfile_igetl(f);
- end += dumbfile_pos(f);
- while ( dumbfile_pos(f) < end ) {
- int chunkid = dumbfile_igetl(f);
- switch ( chunkid ) {
- case DUMB_ID('P','L','U','G'):
- instrument->output = dumbfile_getc(f);
- break;
- default:
- chunkid = chunkid / 0x100 + dumbfile_getc(f) * 0x1000000;
- break;
- }
- }
-
- if (dumbfile_error(f))
- return -1;
- }*/
-
- return 0;
-}
-
-
-
-static int it_read_sample_header(IT_SAMPLE *sample, unsigned char *convert, long *offset, DUMBFILE *f)
-{
- /* XXX
- if (dumbfile_mgetl(f) != IT_SAMPLE_SIGNATURE)
- return -1;*/
- int hax = 0;
- long s = dumbfile_mgetl(f);
- if (s != IT_SAMPLE_SIGNATURE) {
- if ( s == ( IT_SAMPLE_SIGNATURE >> 16 ) ) {
- s <<= 16;
- s |= dumbfile_mgetw(f);
- if ( s != IT_SAMPLE_SIGNATURE )
- return -1;
- hax = 1;
- }
- }
-
- dumbfile_getnc(sample->filename, 13, f);
- sample->filename[13] = 0;
-
- sample->global_volume = dumbfile_getc(f);
- sample->flags = dumbfile_getc(f);
- sample->default_volume = dumbfile_getc(f);
-
- dumbfile_getnc(sample->name, 26, f);
- sample->name[26] = 0;
-
- *convert = dumbfile_getc(f);
- sample->default_pan = dumbfile_getc(f);
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = dumbfile_igetl(f);
- sample->C5_speed = dumbfile_igetl(f);
- sample->sus_loop_start = dumbfile_igetl(f);
- sample->sus_loop_end = dumbfile_igetl(f);
-
-#ifdef STEREO_SAMPLES_COUNT_AS_TWO
- if (sample->flags & IT_SAMPLE_STEREO) {
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- sample->C5_speed >>= 1;
- sample->sus_loop_start >>= 1;
- sample->sus_loop_end >>= 1;
- }
-#endif
-
- if (sample->flags & IT_SAMPLE_EXISTS) {
- if (sample->length <= 0)
- sample->flags &= ~IT_SAMPLE_EXISTS;
- else {
- if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
- sample->flags &= ~IT_SAMPLE_LOOP;
-
- if ((unsigned int)sample->sus_loop_end > (unsigned int)sample->length)
- sample->flags &= ~IT_SAMPLE_SUS_LOOP;
- else if ((unsigned int)sample->sus_loop_start >= (unsigned int)sample->sus_loop_end)
- sample->flags &= ~IT_SAMPLE_SUS_LOOP;
-
- /* We may be able to truncate the sample to save memory. */
- if (sample->flags & IT_SAMPLE_LOOP &&
- *convert != 0xFF) { /* not truncating compressed samples, for now... */
- if ((sample->flags & IT_SAMPLE_SUS_LOOP) && sample->sus_loop_end >= sample->loop_end)
- sample->length = sample->sus_loop_end;
- else
- sample->length = sample->loop_end;
- }
- }
- }
-
- *offset = dumbfile_igetl(f);
-
- sample->vibrato_speed = dumbfile_getc(f);
- sample->vibrato_depth = dumbfile_getc(f);
- if ( ! hax ) {
- sample->vibrato_rate = dumbfile_getc(f);
- sample->vibrato_waveform = dumbfile_getc(f);
- } else {
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = 0;
- }
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-long _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f)
-{
- long n, len, delta;
- signed char * ptr, * end;
- signed char compression_table[16];
- if (dumbfile_getnc(compression_table, 16, f) != 16)
- return -1;
- ptr = (signed char *) sample->data;
- delta = 0;
-
- end = ptr + sample->length;
- len = (sample->length + 1) / 2;
- for (n = 0; n < len; n++) {
- int b = dumbfile_getc(f);
- if (b < 0) return -1;
- delta += compression_table[b & 0x0F];
- *ptr++ = delta;
- if (ptr >= end) break;
- delta += compression_table[b >> 4];
- *ptr++ = delta;
- }
-
- return 0;
-}
-
-
-static long it_read_sample_data(int cmwt, IT_SAMPLE *sample, unsigned char convert, DUMBFILE *f)
-{
- long n;
-
- long datasize = sample->length;
- if (sample->flags & IT_SAMPLE_STEREO) datasize <<= 1;
-
- sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
- if (!sample->data)
- return -1;
-
- if (!(sample->flags & IT_SAMPLE_16BIT) && (convert == 0xFF)) {
- if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
- return -1;
- } else if (sample->flags & 8) {
- /* If the sample is packed, then we must unpack it. */
-
- /** WARNING - unresolved business here... test with ModPlug? */
-
- if (sample->flags & IT_SAMPLE_STEREO)
- //exit(37); // TODO: if this ever happens, maybe sample->length should be doubled below?
- return -1;
-
-/*
-//#ifndef STEREO_SAMPLES_COUNT_AS_TWO
- ASSERT(!(sample->flags & IT_SAMPLE_STEREO));
-//#endif
-*/
- if (sample->flags & IT_SAMPLE_16BIT)
- decompress16(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4)));
- else
- decompress8(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4)));
- } else if (sample->flags & IT_SAMPLE_16BIT) {
- if (convert & 2)
- for (n = 0; n < datasize; n++)
- ((short *)sample->data)[n] = dumbfile_mgetw(f);
- else
- for (n = 0; n < datasize; n++)
- ((short *)sample->data)[n] = dumbfile_igetw(f);
- } else
- for (n = 0; n < datasize; n++)
- ((signed char *)sample->data)[n] = dumbfile_getc(f);
-
- if (dumbfile_error(f))
- return -1;
-
- if (!(convert & 1)) {
- /* Convert to signed. */
- if (sample->flags & IT_SAMPLE_16BIT)
- for (n = 0; n < datasize; n++)
- ((short *)sample->data)[n] ^= 0x8000;
- else
- for (n = 0; n < datasize; n++)
- ((signed char *)sample->data)[n] ^= 0x80;
- }
-
- /* NOT SUPPORTED:
- *
- * convert & 4 - Samples stored as delta values
- * convert & 16 - Samples stored as TX-Wave 12-bit values
- * convert & 32 - Left/Right/All Stereo prompt
- */
-
- return 0;
-}
-
-
-
-//#define DETECT_DUPLICATE_CHANNELS
-#ifdef DETECT_DUPLICATE_CHANNELS
-#include <stdio.h>
-#endif
-static int it_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer)
-{
- unsigned char cmask[DUMB_IT_N_CHANNELS];
- unsigned char cnote[DUMB_IT_N_CHANNELS];
- unsigned char cinstrument[DUMB_IT_N_CHANNELS];
- unsigned char cvolpan[DUMB_IT_N_CHANNELS];
- unsigned char ceffect[DUMB_IT_N_CHANNELS];
- unsigned char ceffectvalue[DUMB_IT_N_CHANNELS];
-#ifdef DETECT_DUPLICATE_CHANNELS
- IT_ENTRY *dupentry[DUMB_IT_N_CHANNELS];
-#endif
-
- int n_entries = 0;
- int buflen;
- int bufpos = 0;
-
- IT_ENTRY *entry;
-
- unsigned char channel;
- unsigned char mask;
-
- memset(cmask, 0, sizeof(cmask));
- memset(cnote, 0, sizeof(cnote));
- memset(cinstrument, 0, sizeof(cinstrument));
- memset(cvolpan, 0, sizeof(cvolpan));
- memset(ceffect, 0, sizeof(ceffect));
- memset(ceffectvalue, 0, sizeof(ceffectvalue));
-#ifdef DETECT_DUPLICATE_CHANNELS
- {
- int i;
- for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL;
- }
-#endif
-
- buflen = dumbfile_igetw(f);
- pattern->n_rows = dumbfile_igetw(f);
-
- /* Skip four unused bytes. */
- dumbfile_skip(f, 4);
-
- if (dumbfile_error(f))
- return -1;
-
- /* Read in the pattern data. */
- dumbfile_getnc(buffer, buflen, f);
-
- if (dumbfile_error(f))
- return -1;
-
- /* Scan the pattern data, and work out how many entries we need room for. */
- while (bufpos < buflen) {
- unsigned char b = buffer[bufpos++];
-
- if (b == 0) {
- /* End of row */
- n_entries++;
- continue;
- }
-
- channel = (b - 1) & 63;
-
- if (b & 128)
- cmask[channel] = mask = buffer[bufpos++];
- else
- mask = cmask[channel];
-
- {
- static const unsigned char used[16] = {0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5};
- n_entries += (mask != 0);
- bufpos += used[mask & 15];
- }
- }
-
- pattern->n_entries = n_entries;
-
- pattern->entry = malloc(n_entries * sizeof(*pattern->entry));
-
- if (!pattern->entry)
- return -1;
-
- bufpos = 0;
- memset(cmask, 0, sizeof(cmask));
-
- entry = pattern->entry;
-
- while (bufpos < buflen) {
- unsigned char b = buffer[bufpos++];
-
- if (b == 0) {
- /* End of row */
- IT_SET_END_ROW(entry);
- entry++;
-#ifdef DETECT_DUPLICATE_CHANNELS
- {
- int i;
- for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL;
- }
-#endif
- continue;
- }
-
- channel = (b - 1) & 63;
-
- if (b & 128)
- cmask[channel] = mask = buffer[bufpos++];
- else
- mask = cmask[channel];
-
- if (mask) {
- entry->mask = (mask & 15) | (mask >> 4);
- entry->channel = channel;
-
- if (mask & IT_ENTRY_NOTE)
- cnote[channel] = entry->note = buffer[bufpos++];
- else if (mask & (IT_ENTRY_NOTE << 4))
- entry->note = cnote[channel];
-
- if (mask & IT_ENTRY_INSTRUMENT)
- cinstrument[channel] = entry->instrument = buffer[bufpos++];
- else if (mask & (IT_ENTRY_INSTRUMENT << 4))
- entry->instrument = cinstrument[channel];
-
- if (mask & IT_ENTRY_VOLPAN)
- cvolpan[channel] = entry->volpan = buffer[bufpos++];
- else if (mask & (IT_ENTRY_VOLPAN << 4))
- entry->volpan = cvolpan[channel];
-
- if (mask & IT_ENTRY_EFFECT) {
- ceffect[channel] = entry->effect = buffer[bufpos++];
- ceffectvalue[channel] = entry->effectvalue = buffer[bufpos++];
- } else {
- entry->effect = ceffect[channel];
- entry->effectvalue = ceffectvalue[channel];
- }
-
-#ifdef DETECT_DUPLICATE_CHANNELS
- if (dupentry[channel]) {
- FILE *f = fopen("dupentry.txt", "a");
- if (!f) abort();
- fprintf(f, "Two events on channel %d:", channel);
- fprintf(f, " Event #1:");
- if (dupentry[channel]->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", dupentry[channel]->note ); else fprintf(f, " ...");
- if (dupentry[channel]->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", dupentry[channel]->instrument); else fprintf(f, " ...");
- if (dupentry[channel]->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", dupentry[channel]->volpan ); else fprintf(f, " ...");
- if (dupentry[channel]->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + dupentry[channel]->effect, dupentry[channel]->effectvalue); else fprintf(f, " ...\n");
- fprintf(f, " Event #2:");
- if (entry->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", entry->note ); else fprintf(f, " ...");
- if (entry->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", entry->instrument); else fprintf(f, " ...");
- if (entry->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", entry->volpan ); else fprintf(f, " ...");
- if (entry->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + entry->effect, entry->effectvalue); else fprintf(f, " ...\n");
- fclose(f);
- }
- dupentry[channel] = entry;
-#endif
-
- entry++;
- }
- }
-
- ASSERT(entry == pattern->entry + n_entries);
-
- return 0;
-}
-
-
-
-/* Currently we assume the sample data are stored after the sample headers in
- * module files. This assumption may be unjustified; let me know if you have
- * trouble.
- */
-
-#define IT_COMPONENT_SONG_MESSAGE 1
-#define IT_COMPONENT_INSTRUMENT 2
-#define IT_COMPONENT_PATTERN 3
-#define IT_COMPONENT_SAMPLE 4
-
-typedef struct IT_COMPONENT
-{
- unsigned char type;
- unsigned short n;
- long offset;
- short sampfirst; /* component[sampfirst] = first sample data after this */
- short sampnext; /* sampnext is used to create linked lists of sample data */
-}
-IT_COMPONENT;
-
-
-
-static int it_component_compare(const void *e1, const void *e2)
-{
- return ((const IT_COMPONENT *)e1)->offset -
- ((const IT_COMPONENT *)e2)->offset;
-}
-
-
-
-static sigdata_t *it_load_sigdata(DUMBFILE *f)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int cwt, cmwt;
- int special;
- int message_length, message_offset;
-
- IT_COMPONENT *component;
- int n_components = 0;
-
- unsigned char sample_convert[4096];
-
- int n;
-
- unsigned char *buffer;
-
- if (dumbfile_mgetl(f) != IT_SIGNATURE)
- return NULL;
-
- sigdata = malloc(sizeof(*sigdata));
-
- if (!sigdata)
- return NULL;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- dumbfile_getnc(sigdata->name, 26, f);
- sigdata->name[26] = 0;
-
- /* Skip pattern row highlight info. */
- dumbfile_skip(f, 2);
-
- sigdata->n_orders = dumbfile_igetw(f);
- sigdata->n_instruments = dumbfile_igetw(f);
- sigdata->n_samples = dumbfile_igetw(f);
- sigdata->n_patterns = dumbfile_igetw(f);
-
- cwt = dumbfile_igetw(f);
- cmwt = dumbfile_igetw(f);
-
- sigdata->flags = dumbfile_igetw(f);
- special = dumbfile_igetw(f);
-
- sigdata->global_volume = dumbfile_getc(f);
- sigdata->mixing_volume = dumbfile_getc(f);
- sigdata->speed = dumbfile_getc(f);
- if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
- sigdata->tempo = dumbfile_getc(f);
- sigdata->pan_separation = dumbfile_getc(f); /** WARNING: use this */
-
- /* Skip Pitch Wheel Depth */
- dumbfile_skip(f, 1);
-
- message_length = dumbfile_igetw(f);
- message_offset = dumbfile_igetl(f);
-
- /* Skip Reserved. */
- dumbfile_skip(f, 4);
-
- dumbfile_getnc(sigdata->channel_pan, DUMB_IT_N_CHANNELS, f);
- dumbfile_getnc(sigdata->channel_volume, DUMB_IT_N_CHANNELS, f);
-
- // XXX sample count
- if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 4000 || sigdata->n_patterns > 256) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->order = malloc(sigdata->n_orders);
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (sigdata->n_instruments) {
- sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
- if (!sigdata->instrument) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
-
- if (sigdata->n_samples) {
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
- }
-
- if (sigdata->n_patterns) {
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
- }
-
- dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
- sigdata->restart_position = 0;
-
- component = malloc(769 * sizeof(*component));
- if (!component) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (special & 1) {
- component[n_components].type = IT_COMPONENT_SONG_MESSAGE;
- component[n_components].offset = message_offset;
- component[n_components].sampfirst = -1;
- n_components++;
- }
-
- for (n = 0; n < sigdata->n_instruments; n++) {
- component[n_components].type = IT_COMPONENT_INSTRUMENT;
- component[n_components].n = n;
- component[n_components].offset = dumbfile_igetl(f);
- component[n_components].sampfirst = -1;
- n_components++;
- }
-
- for (n = 0; n < sigdata->n_samples; n++) {
- component[n_components].type = IT_COMPONENT_SAMPLE;
- component[n_components].n = n;
- component[n_components].offset = dumbfile_igetl(f);
- component[n_components].sampfirst = -1;
- n_components++;
- }
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- long offset = dumbfile_igetl(f);
- if (offset) {
- component[n_components].type = IT_COMPONENT_PATTERN;
- component[n_components].n = n;
- component[n_components].offset = offset;
- component[n_components].sampfirst = -1;
- n_components++;
- } else {
- /* Empty 64-row pattern */
- sigdata->pattern[n].n_rows = 64;
- sigdata->pattern[n].n_entries = 0;
- }
- }
-
- if (dumbfile_error(f)) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- /*
- if (!(sigdata->flags & 128) != !(special & 8)) {
- fprintf(stderr, "Flags Bit 7 (\"Request embedded MIDI configuration\"): %s\n", sigdata->flags & 128 ? "=SET=" : "clear");
- fprintf(stderr, "Special Bit 3 (\"MIDI configuration embedded\") : %s\n", special & 8 ? "=SET=" : "clear");
- fprintf(stderr, "entheh would like to investigate this IT file.\n");
- fprintf(stderr, "Please contact him! entheh@users.sf.net\n");
- }
- */
-
- if (special & 8) {
- /* MIDI configuration is embedded. */
- unsigned char mididata[32];
- int i;
- sigdata->midi = malloc(sizeof(*sigdata->midi));
- if (!sigdata->midi) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- // Should we be happy with this outcome in some situations?
- }
- // What are we skipping?
- i = dumbfile_igetw(f);
- if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- /* Read embedded MIDI configuration */
- // What are the first 9 commands for?
- if (dumbfile_skip(f, 32*9)) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < 16; i++) {
- unsigned char len = 0;
- int j, leftdigit = -1;
- if (dumbfile_getnc(mididata, 32, f) < 32) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- sigdata->midi->SFmacroz[i] = 0;
- for (j = 0; j < 32; j++) {
- if (leftdigit >= 0) {
- if (mididata[j] == 0) {
- sigdata->midi->SFmacro[i][len++] = leftdigit;
- break;
- } else if (mididata[j] == ' ')
- sigdata->midi->SFmacro[i][len++] = leftdigit;
- else if (mididata[j] >= '0' && mididata[j] <= '9')
- sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0');
- else if (mididata[j] >= 'A' && mididata[j] <= 'F')
- sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA);
- leftdigit = -1;
- } else if (mididata[j] == 0)
- break;
- else if (mididata[j] == 'z')
- sigdata->midi->SFmacroz[i] |= 1 << len++;
- else if (mididata[j] >= '0' && mididata[j] <= '9')
- leftdigit = mididata[j] - '0';
- else if (mididata[j] >= 'A' && mididata[j] <= 'F')
- leftdigit = mididata[j] - 'A' + 0xA;
- }
- sigdata->midi->SFmacrolen[i] = len;
- }
- for (i = 0; i < 128; i++) {
- unsigned char len = 0;
- int j, leftdigit = -1;
- dumbfile_getnc(mididata, 32, f);
- for (j = 0; j < 32; j++) {
- if (leftdigit >= 0) {
- if (mididata[j] == 0) {
- sigdata->midi->Zmacro[i][len++] = leftdigit;
- break;
- } else if (mididata[j] == ' ')
- sigdata->midi->Zmacro[i][len++] = leftdigit;
- else if (mididata[j] >= '0' && mididata[j] <= '9')
- sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0');
- else if (mididata[j] >= 'A' && mididata[j] <= 'F')
- sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA);
- leftdigit = -1;
- } else if (mididata[j] == 0)
- break;
- else if (mididata[j] >= '0' && mididata[j] <= '9')
- leftdigit = mididata[j] - '0';
- else if (mididata[j] >= 'A' && mididata[j] <= 'F')
- leftdigit = mididata[j] - 'A' + 0xA;
- }
- sigdata->midi->Zmacrolen[i] = len;
- }
- }
-
- sigdata->flags &= IT_REAL_FLAGS;
-
- qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare);
-
- buffer = malloc(65536);
- if (!buffer) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < n_components; n++) {
- long offset;
- int m;
-
- /* XXX */
- if ( component[n].offset == 0 ) {
- switch (component[n].type) {
- case IT_COMPONENT_INSTRUMENT:
- memset( &sigdata->instrument[component[n].n], 0, sizeof(IT_INSTRUMENT) );
- break;
- case IT_COMPONENT_SAMPLE:
- memset( &sigdata->sample[component[n].n], 0, sizeof(IT_SAMPLE) );
- break;
- case IT_COMPONENT_PATTERN:
- {
- IT_PATTERN * p = &sigdata->pattern[component[n].n];
- p->entry = 0;
- p->n_rows = 64;
- p->n_entries = 0;
- }
- break;
- }
- continue;
- }
-
- if (it_seek(f, component[n].offset)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- switch (component[n].type) {
-
- case IT_COMPONENT_SONG_MESSAGE:
- if ( n < n_components ) {
- message_length = min( message_length, component[n+1].offset - component[n].offset );
- }
- sigdata->song_message = malloc(message_length + 1);
- if (sigdata->song_message) {
- if (dumbfile_getnc(sigdata->song_message, message_length, f) < message_length) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- sigdata->song_message[message_length] = 0;
- }
- break;
-
- case IT_COMPONENT_INSTRUMENT:
- if (cmwt < 0x200)
- m = it_read_old_instrument(&sigdata->instrument[component[n].n], f);
- else
- m = it_read_instrument(&sigdata->instrument[component[n].n], f, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0);
-
- if (m) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- break;
-
- case IT_COMPONENT_PATTERN:
- if (it_read_pattern(&sigdata->pattern[component[n].n], f, buffer)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- break;
-
- case IT_COMPONENT_SAMPLE:
- if (it_read_sample_header(&sigdata->sample[component[n].n], &sample_convert[component[n].n], &offset, f)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) {
- short *sample;
-
- for (m = n + 1; m < n_components; m++)
- if (component[m].offset > offset)
- break;
- m--;
-
- sample = &component[m].sampfirst;
-
- while (*sample >= 0 && component[*sample].offset <= offset)
- sample = &component[*sample].sampnext;
-
- component[n].sampnext = *sample;
- *sample = n;
-
- component[n].offset = offset;
- }
- }
-
- m = component[n].sampfirst;
-
- while (m >= 0) {
- if (it_seek(f, component[m].offset)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (it_read_sample_data(cmwt, &sigdata->sample[component[m].n], sample_convert[component[m].n], f)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- m = component[m].sampnext;
- }
- }
-
- free(buffer);
- free(component);
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-
-
-DUH *dumb_read_it_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_load_sigdata(f);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[1][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- return make_duh(-1, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * itread.c - Code to read an Impulse Tracker / / \ \ + * module from an open file. | < / \_ + * | \/ /\ / + * Based on the loader from an IT player by Bob. \_ / > / + * Adapted for DUMB by entheh. | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h>//might not be necessary later; required for memset + +#include "dumb.h" +#include "internal/it.h" + + + +#define INVESTIGATE_OLD_INSTRUMENTS + + + +static int it_seek(DUMBFILE *f, long offset) +{ + long pos = dumbfile_pos(f); + + if (pos > offset) + return -1; + + if (pos < offset) + if (dumbfile_skip(f, offset - pos)) + return -1; + + return 0; +} + + + +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned long dword; + +typedef struct readblock_crap readblock_crap; + +struct readblock_crap { + unsigned char *sourcebuf; + unsigned char *sourcepos; + unsigned char *sourceend; + int rembits; +}; + + +static int readblock(DUMBFILE *f, readblock_crap * crap) +{ + long size; + int c; + + size = dumbfile_igetw(f); + if (size < 0) + return size; + + crap->sourcebuf = malloc(size); + if (!crap->sourcebuf) + return -1; + + c = dumbfile_getnc((char *)crap->sourcebuf, size, f); + if (c < size) { + free(crap->sourcebuf); + crap->sourcebuf = NULL; + return -1; + } + + crap->sourcepos = crap->sourcebuf; + crap->sourceend = crap->sourcebuf + size; + crap->rembits = 8; + return 0; +} + + + +static void freeblock(readblock_crap * crap) +{ + free(crap->sourcebuf); + crap->sourcebuf = NULL; +} + + + +static int readbits(int bitwidth, readblock_crap * crap) +{ + int val = 0; + int b = 0; + + if (crap->sourcepos >= crap->sourceend) return val; + + while (bitwidth > crap->rembits) { + val |= *crap->sourcepos++ << b; + if (crap->sourcepos >= crap->sourceend) return val; + b += crap->rembits; + bitwidth -= crap->rembits; + crap->rembits = 8; + } + + val |= (*crap->sourcepos & ((1 << bitwidth) - 1)) << b; + *crap->sourcepos >>= bitwidth; + crap->rembits -= bitwidth; + + return val; +} + + + +/** WARNING - do we even need to pass `right`? */ +/** WARNING - why bother memsetting at all? The whole array is written... */ +// if we do memset, dumb_silence() would be neater... +static int decompress8(DUMBFILE *f, signed char *data, int len, int cmwt) +{ + int blocklen, blockpos; + byte bitwidth; + word val; + char d1, d2; + readblock_crap crap; + + memset(&crap, 0, sizeof(crap)); + + memset(data, 0, len * sizeof(*data)); + + while (len > 0) { + //Read a block of compressed data: + if (readblock(f, &crap)) + return -1; + //Set up a few variables + blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes + blockpos = 0; + bitwidth = 9; + d1 = d2 = 0; + //Start the decompression: + while (blockpos < blocklen) { + //Read a value: + val = (word)readbits(bitwidth, &crap); + //Check for bit width change: + + if (bitwidth < 7) { //Method 1: + if (val == (1 << (bitwidth - 1))) { + val = (word)readbits(3, &crap) + 1; + bitwidth = (val < bitwidth) ? val : val + 1; + continue; + } + } + else if (bitwidth < 9) { //Method 2 + byte border = (0xFF >> (9 - bitwidth)) - 4; + + if (val > border && val <= (border + 8)) { + val -= border; + bitwidth = (val < bitwidth) ? val : val + 1; + continue; + } + } + else if (bitwidth == 9) { //Method 3 + if (val & 0x100) { + bitwidth = (val + 1) & 0xFF; + continue; + } + } + else { //Illegal width, abort ? + freeblock(&crap); + return -1; + } + + //Expand the value to signed byte: + { + char v; //The sample value: + if (bitwidth < 8) { + byte shift = 8 - bitwidth; + v = (val << shift); + v >>= shift; + } + else + v = (char)val; + + //And integrate the sample value + //(It always has to end with integration doesn't it ? ;-) + d1 += v; + d2 += d1; + } + + //Store ! + /* Version 2.15 was an unofficial version with hacked compression + * code. Yay, better compression :D + */ + *data++ = cmwt == 0x215 ? d2 : d1; + len--; + blockpos++; + } + freeblock(&crap); + } + return 0; +} + + + +static int decompress16(DUMBFILE *f, short *data, int len, int cmwt) +{ + int blocklen, blockpos; + byte bitwidth; + long val; + short d1, d2; + readblock_crap crap; + + memset(&crap, 0, sizeof(crap)); + + memset(data, 0, len * sizeof(*data)); + + while (len > 0) { + //Read a block of compressed data: + if (readblock(f, &crap)) + return -1; + //Set up a few variables + blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes + blockpos = 0; + bitwidth = 17; + d1 = d2 = 0; + //Start the decompression: + while (blockpos < blocklen) { + val = readbits(bitwidth, &crap); + //Check for bit width change: + + if (bitwidth < 7) { //Method 1: + if (val == (1 << (bitwidth - 1))) { + val = readbits(4, &crap) + 1; + bitwidth = (val < bitwidth) ? val : val + 1; + continue; + } + } + else if (bitwidth < 17) { //Method 2 + word border = (0xFFFF >> (17 - bitwidth)) - 8; + + if (val > border && val <= (border + 16)) { + val -= border; + bitwidth = val < bitwidth ? val : val + 1; + continue; + } + } + else if (bitwidth == 17) { //Method 3 + if (val & 0x10000) { + bitwidth = (val + 1) & 0xFF; + continue; + } + } + else { //Illegal width, abort ? + freeblock(&crap); + return -1; + } + + //Expand the value to signed byte: + { + short v; //The sample value: + if (bitwidth < 16) { + byte shift = 16 - bitwidth; + v = (short)(val << shift); + v >>= shift; + } + else + v = (short)val; + + //And integrate the sample value + //(It always has to end with integration doesn't it ? ;-) + d1 += v; + d2 += d1; + } + + //Store ! + /* Version 2.15 was an unofficial version with hacked compression + * code. Yay, better compression :D + */ + *data++ = cmwt == 0x215 ? d2 : d1; + len--; + blockpos++; + } + freeblock(&crap); + } + return 0; +} + + + +static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f) +{ + int n; + + envelope->flags = dumbfile_getc(f); + envelope->n_nodes = dumbfile_getc(f); + envelope->loop_start = dumbfile_getc(f); + envelope->loop_end = dumbfile_getc(f); + envelope->sus_loop_start = dumbfile_getc(f); + envelope->sus_loop_end = dumbfile_getc(f); + for (n = 0; n < envelope->n_nodes; n++) { + envelope->node_y[n] = dumbfile_getc(f); + envelope->node_t[n] = dumbfile_igetw(f); + } + dumbfile_skip(f, 75 - envelope->n_nodes * 3 + 1); + + if (envelope->n_nodes <= 0) + envelope->flags &= ~IT_ENVELOPE_ON; + else { + if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON; + if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP; + } + + if (envelope->n_nodes <= 0) + envelope->flags &= ~IT_ENVELOPE_ON; + else { + if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON; + if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP; + } + + return dumbfile_error(f); +} + + + +static int it_read_old_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f) +{ + int n; + + /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE) + return -1;*/ + // XXX + dumbfile_skip(f, 4); + + dumbfile_getnc(instrument->filename, 13, f); + instrument->filename[13] = 0; + + instrument->volume_envelope.flags = dumbfile_getc(f); + instrument->volume_envelope.loop_start = dumbfile_getc(f); + instrument->volume_envelope.loop_end = dumbfile_getc(f); + instrument->volume_envelope.sus_loop_start = dumbfile_getc(f); + instrument->volume_envelope.sus_loop_end = dumbfile_getc(f); + + /* Skip two unused bytes. */ + dumbfile_skip(f, 2); + + /* In the old instrument format, fadeout ranges from 0 to 64, and is + * subtracted at intervals from a value starting at 512. In the new + * format, all these values are doubled. Therefore we double when loading + * from the old instrument format - that way we don't have to think about + * it later. + */ + instrument->fadeout = dumbfile_igetw(f) << 1; + instrument->new_note_action = dumbfile_getc(f); + instrument->dup_check_type = dumbfile_getc(f); + instrument->dup_check_action = DCA_NOTE_CUT; // This might be wrong! + /** WARNING - what is the duplicate check action for old-style instruments? */ + + /* Skip Tracker Version and Number of Samples. These are only used in + * separate instrument files. Also skip unused byte. + */ + dumbfile_skip(f, 4); + + dumbfile_getnc(instrument->name, 26, f); + instrument->name[26] = 0; + + /* Skip unused bytes following the Instrument Name. */ + dumbfile_skip(f, 6); + + instrument->pp_separation = 0; + instrument->pp_centre = 60; + instrument->global_volume = 128; + /** WARNING - should global_volume be 64 or something? */ + instrument->default_pan = 32; + /** WARNING - should default_pan be 128, meaning don`t use? */ + instrument->random_volume = 0; + instrument->random_pan = 0; + + for (n = 0; n < 120; n++) { + instrument->map_note[n] = dumbfile_getc(f); + instrument->map_sample[n] = dumbfile_getc(f); + } + + /* Skip "Volume envelope (200 bytes)". */ + // - need to know better what this is for though. + dumbfile_skip(f, 200); + +#ifdef INVESTIGATE_OLD_INSTRUMENTS + fprintf(stderr, "Inst %02d Env:", n); +#endif + + for (n = 0; n < 25; n++) + { + instrument->volume_envelope.node_t[n] = dumbfile_getc(f); + instrument->volume_envelope.node_y[n] = dumbfile_getc(f); + +#ifdef INVESTIGATE_OLD_INSTRUMENTS + fprintf(stderr, " %d,%d", + instrument->volume_envelope.node_t[n], + instrument->volume_envelope.node_y[n]); +#endif + + // This loop is unfinished, as we can probably escape from it before + // the end if we want to. Hence the otherwise useless dumbfile_skip() + // call below. + } + dumbfile_skip(f, 50 - (n << 1)); + instrument->volume_envelope.n_nodes = n; + +#ifdef INVESTIGATE_OLD_INSTRUMENTS + fprintf(stderr, "\n"); +#endif + + if (dumbfile_error(f)) + return -1; + + { + IT_ENVELOPE *envelope = &instrument->volume_envelope; + if (envelope->n_nodes <= 0) + envelope->flags &= ~IT_ENVELOPE_ON; + else { + if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON; + if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP; + } + } + + { + IT_ENVELOPE *envelope = &instrument->volume_envelope; + if (envelope->n_nodes <= 0) + envelope->flags &= ~IT_ENVELOPE_ON; + else { + if (envelope->loop_end >= envelope->n_nodes || envelope->loop_start > envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON; + if (envelope->sus_loop_end >= envelope->n_nodes || envelope->sus_loop_start > envelope->sus_loop_end) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP; + } + } + + instrument->filter_cutoff = 127; + instrument->filter_resonance = 0; + + instrument->pan_envelope.flags = 0; + instrument->pitch_envelope.flags = 0; + + return 0; +} + + + +static int it_read_instrument(IT_INSTRUMENT *instrument, DUMBFILE *f, int maxlen) +{ + int n, len; + + /*if (dumbfile_mgetl(f) != IT_INSTRUMENT_SIGNATURE) + return -1;*/ + // XXX + + if (maxlen) len = dumbfile_pos(f); + + dumbfile_skip(f, 4); + + dumbfile_getnc(instrument->filename, 13, f); + instrument->filename[13] = 0; + + instrument->new_note_action = dumbfile_getc(f); + instrument->dup_check_type = dumbfile_getc(f); + instrument->dup_check_action = dumbfile_getc(f); + instrument->fadeout = dumbfile_igetw(f); + instrument->pp_separation = dumbfile_getc(f); + instrument->pp_centre = dumbfile_getc(f); + instrument->global_volume = dumbfile_getc(f); + instrument->default_pan = dumbfile_getc(f); + instrument->random_volume = dumbfile_getc(f); + instrument->random_pan = dumbfile_getc(f); + + /* Skip Tracker Version and Number of Samples. These are only used in + * separate instrument files. Also skip unused byte. + */ + dumbfile_skip(f, 4); + + dumbfile_getnc(instrument->name, 26, f); + instrument->name[26] = 0; + + instrument->filter_cutoff = dumbfile_getc(f); + instrument->filter_resonance = dumbfile_getc(f); + + /* Skip MIDI Channel, Program and Bank. */ + //dumbfile_skip(f, 4); + /*instrument->output = dumbfile_getc(f); + if ( instrument->output > 16 ) { + instrument->output -= 128; + } else { + instrument->output = 0; + } + dumbfile_skip(f, 3);*/ + dumbfile_skip(f, 4); + + for (n = 0; n < 120; n++) { + instrument->map_note[n] = dumbfile_getc(f); + instrument->map_sample[n] = dumbfile_getc(f); + } + + if (dumbfile_error(f)) + return -1; + + if (it_read_envelope(&instrument->volume_envelope, f)) return -1; + if (it_read_envelope(&instrument->pan_envelope, f)) return -1; + if (it_read_envelope(&instrument->pitch_envelope, f)) return -1; + + if (maxlen) { + len = dumbfile_pos(f) - len; + if ( maxlen - len < 124 ) return 0; + } + + if ( dumbfile_mgetl(f) == IT_MPTX_SIGNATURE ) { + for ( n = 0; n < 120; n++ ) { + instrument->map_sample[ n ] += dumbfile_getc( f ) << 8; + } + + if (dumbfile_error(f)) + return -1; + } + + /*if ( dumbfile_mgetl(f) == IT_INSM_SIGNATURE ) { + long end = dumbfile_igetl(f); + end += dumbfile_pos(f); + while ( dumbfile_pos(f) < end ) { + int chunkid = dumbfile_igetl(f); + switch ( chunkid ) { + case DUMB_ID('P','L','U','G'): + instrument->output = dumbfile_getc(f); + break; + default: + chunkid = chunkid / 0x100 + dumbfile_getc(f) * 0x1000000; + break; + } + } + + if (dumbfile_error(f)) + return -1; + }*/ + + return 0; +} + + + +static int it_read_sample_header(IT_SAMPLE *sample, unsigned char *convert, long *offset, DUMBFILE *f) +{ + /* XXX + if (dumbfile_mgetl(f) != IT_SAMPLE_SIGNATURE) + return -1;*/ + int hax = 0; + long s = dumbfile_mgetl(f); + if (s != IT_SAMPLE_SIGNATURE) { + if ( s == ( IT_SAMPLE_SIGNATURE >> 16 ) ) { + s <<= 16; + s |= dumbfile_mgetw(f); + if ( s != IT_SAMPLE_SIGNATURE ) + return -1; + hax = 1; + } + } + + dumbfile_getnc(sample->filename, 13, f); + sample->filename[13] = 0; + + sample->global_volume = dumbfile_getc(f); + sample->flags = dumbfile_getc(f); + sample->default_volume = dumbfile_getc(f); + + dumbfile_getnc(sample->name, 26, f); + sample->name[26] = 0; + + *convert = dumbfile_getc(f); + sample->default_pan = dumbfile_getc(f); + sample->length = dumbfile_igetl(f); + sample->loop_start = dumbfile_igetl(f); + sample->loop_end = dumbfile_igetl(f); + sample->C5_speed = dumbfile_igetl(f); + sample->sus_loop_start = dumbfile_igetl(f); + sample->sus_loop_end = dumbfile_igetl(f); + +#ifdef STEREO_SAMPLES_COUNT_AS_TWO + if (sample->flags & IT_SAMPLE_STEREO) { + sample->length >>= 1; + sample->loop_start >>= 1; + sample->loop_end >>= 1; + sample->C5_speed >>= 1; + sample->sus_loop_start >>= 1; + sample->sus_loop_end >>= 1; + } +#endif + + if (sample->flags & IT_SAMPLE_EXISTS) { + if (sample->length <= 0) + sample->flags &= ~IT_SAMPLE_EXISTS; + else { + if ((unsigned int)sample->loop_end > (unsigned int)sample->length) + sample->flags &= ~IT_SAMPLE_LOOP; + else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end) + sample->flags &= ~IT_SAMPLE_LOOP; + + if ((unsigned int)sample->sus_loop_end > (unsigned int)sample->length) + sample->flags &= ~IT_SAMPLE_SUS_LOOP; + else if ((unsigned int)sample->sus_loop_start >= (unsigned int)sample->sus_loop_end) + sample->flags &= ~IT_SAMPLE_SUS_LOOP; + + /* We may be able to truncate the sample to save memory. */ + if (sample->flags & IT_SAMPLE_LOOP && + *convert != 0xFF) { /* not truncating compressed samples, for now... */ + if ((sample->flags & IT_SAMPLE_SUS_LOOP) && sample->sus_loop_end >= sample->loop_end) + sample->length = sample->sus_loop_end; + else + sample->length = sample->loop_end; + } + } + } + + *offset = dumbfile_igetl(f); + + sample->vibrato_speed = dumbfile_getc(f); + sample->vibrato_depth = dumbfile_getc(f); + if ( ! hax ) { + sample->vibrato_rate = dumbfile_getc(f); + sample->vibrato_waveform = dumbfile_getc(f); + } else { + sample->vibrato_rate = 0; + sample->vibrato_waveform = 0; + } + sample->finetune = 0; + sample->max_resampling_quality = -1; + + return dumbfile_error(f); +} + +long _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f) +{ + long n, len, delta; + signed char * ptr, * end; + signed char compression_table[16]; + if (dumbfile_getnc(compression_table, 16, f) != 16) + return -1; + ptr = (signed char *) sample->data; + delta = 0; + + end = ptr + sample->length; + len = (sample->length + 1) / 2; + for (n = 0; n < len; n++) { + int b = dumbfile_getc(f); + if (b < 0) return -1; + delta += compression_table[b & 0x0F]; + *ptr++ = delta; + if (ptr >= end) break; + delta += compression_table[b >> 4]; + *ptr++ = delta; + } + + return 0; +} + + +static long it_read_sample_data(int cmwt, IT_SAMPLE *sample, unsigned char convert, DUMBFILE *f) +{ + long n; + + long datasize = sample->length; + if (sample->flags & IT_SAMPLE_STEREO) datasize <<= 1; + + sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1)); + if (!sample->data) + return -1; + + if (!(sample->flags & IT_SAMPLE_16BIT) && (convert == 0xFF)) { + if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0) + return -1; + } else if (sample->flags & 8) { + /* If the sample is packed, then we must unpack it. */ + + /** WARNING - unresolved business here... test with ModPlug? */ + + if (sample->flags & IT_SAMPLE_STEREO) + return -1; + +/* +//#ifndef STEREO_SAMPLES_COUNT_AS_TWO + ASSERT(!(sample->flags & IT_SAMPLE_STEREO)); +//#endif +*/ + if (sample->flags & IT_SAMPLE_16BIT) + decompress16(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4))); + else + decompress8(f, sample->data, datasize, ((cmwt >= 0x215) && (convert & 4))); + } else if (sample->flags & IT_SAMPLE_16BIT) { + if (convert & 2) + for (n = 0; n < datasize; n++) + ((short *)sample->data)[n] = dumbfile_mgetw(f); + else + for (n = 0; n < datasize; n++) + ((short *)sample->data)[n] = dumbfile_igetw(f); + } else + for (n = 0; n < datasize; n++) + ((signed char *)sample->data)[n] = dumbfile_getc(f); + + if (dumbfile_error(f)) + return -1; + + if (!(convert & 1)) { + /* Convert to signed. */ + if (sample->flags & IT_SAMPLE_16BIT) + for (n = 0; n < datasize; n++) + ((short *)sample->data)[n] ^= 0x8000; + else + for (n = 0; n < datasize; n++) + ((signed char *)sample->data)[n] ^= 0x80; + } + + /* NOT SUPPORTED: + * + * convert & 4 - Samples stored as delta values + * convert & 16 - Samples stored as TX-Wave 12-bit values + * convert & 32 - Left/Right/All Stereo prompt + */ + + return 0; +} + + + +//#define DETECT_DUPLICATE_CHANNELS +#ifdef DETECT_DUPLICATE_CHANNELS +#include <stdio.h> +#endif +static int it_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer) +{ + unsigned char cmask[DUMB_IT_N_CHANNELS]; + unsigned char cnote[DUMB_IT_N_CHANNELS]; + unsigned char cinstrument[DUMB_IT_N_CHANNELS]; + unsigned char cvolpan[DUMB_IT_N_CHANNELS]; + unsigned char ceffect[DUMB_IT_N_CHANNELS]; + unsigned char ceffectvalue[DUMB_IT_N_CHANNELS]; +#ifdef DETECT_DUPLICATE_CHANNELS + IT_ENTRY *dupentry[DUMB_IT_N_CHANNELS]; +#endif + + int n_entries = 0; + int buflen; + int bufpos = 0; + + IT_ENTRY *entry; + + unsigned char channel; + unsigned char mask; + + memset(cmask, 0, sizeof(cmask)); + memset(cnote, 0, sizeof(cnote)); + memset(cinstrument, 0, sizeof(cinstrument)); + memset(cvolpan, 0, sizeof(cvolpan)); + memset(ceffect, 0, sizeof(ceffect)); + memset(ceffectvalue, 0, sizeof(ceffectvalue)); +#ifdef DETECT_DUPLICATE_CHANNELS + { + int i; + for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL; + } +#endif + + buflen = dumbfile_igetw(f); + pattern->n_rows = dumbfile_igetw(f); + + /* Skip four unused bytes. */ + dumbfile_skip(f, 4); + + if (dumbfile_error(f)) + return -1; + + /* Read in the pattern data. */ + dumbfile_getnc(buffer, buflen, f); + + if (dumbfile_error(f)) + return -1; + + /* Scan the pattern data, and work out how many entries we need room for. */ + while (bufpos < buflen) { + unsigned char b = buffer[bufpos++]; + + if (b == 0) { + /* End of row */ + n_entries++; + continue; + } + + channel = (b - 1) & 63; + + if (b & 128) + cmask[channel] = mask = buffer[bufpos++]; + else + mask = cmask[channel]; + + { + static const unsigned char used[16] = {0, 1, 1, 2, 1, 2, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5}; + n_entries += (mask != 0); + bufpos += used[mask & 15]; + } + } + + pattern->n_entries = n_entries; + + pattern->entry = malloc(n_entries * sizeof(*pattern->entry)); + + if (!pattern->entry) + return -1; + + bufpos = 0; + memset(cmask, 0, sizeof(cmask)); + + entry = pattern->entry; + + while (bufpos < buflen) { + unsigned char b = buffer[bufpos++]; + + if (b == 0) { + /* End of row */ + IT_SET_END_ROW(entry); + entry++; +#ifdef DETECT_DUPLICATE_CHANNELS + { + int i; + for (i = 0; i < DUMB_IT_N_CHANNELS; i++) dupentry[i] = NULL; + } +#endif + continue; + } + + channel = (b - 1) & 63; + + if (b & 128) + cmask[channel] = mask = buffer[bufpos++]; + else + mask = cmask[channel]; + + if (mask) { + entry->mask = (mask & 15) | (mask >> 4); + entry->channel = channel; + + if (mask & IT_ENTRY_NOTE) + cnote[channel] = entry->note = buffer[bufpos++]; + else if (mask & (IT_ENTRY_NOTE << 4)) + entry->note = cnote[channel]; + + if (mask & IT_ENTRY_INSTRUMENT) + cinstrument[channel] = entry->instrument = buffer[bufpos++]; + else if (mask & (IT_ENTRY_INSTRUMENT << 4)) + entry->instrument = cinstrument[channel]; + + if (mask & IT_ENTRY_VOLPAN) + cvolpan[channel] = entry->volpan = buffer[bufpos++]; + else if (mask & (IT_ENTRY_VOLPAN << 4)) + entry->volpan = cvolpan[channel]; + + if (mask & IT_ENTRY_EFFECT) { + ceffect[channel] = entry->effect = buffer[bufpos++]; + ceffectvalue[channel] = entry->effectvalue = buffer[bufpos++]; + } else { + entry->effect = ceffect[channel]; + entry->effectvalue = ceffectvalue[channel]; + } + +#ifdef DETECT_DUPLICATE_CHANNELS + if (dupentry[channel]) { + FILE *f = fopen("dupentry.txt", "a"); + if (!f) abort(); + fprintf(f, "Two events on channel %d:", channel); + fprintf(f, " Event #1:"); + if (dupentry[channel]->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", dupentry[channel]->note ); else fprintf(f, " ..."); + if (dupentry[channel]->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", dupentry[channel]->instrument); else fprintf(f, " ..."); + if (dupentry[channel]->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", dupentry[channel]->volpan ); else fprintf(f, " ..."); + if (dupentry[channel]->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + dupentry[channel]->effect, dupentry[channel]->effectvalue); else fprintf(f, " ...\n"); + fprintf(f, " Event #2:"); + if (entry->mask & IT_ENTRY_NOTE ) fprintf(f, " %03d", entry->note ); else fprintf(f, " ..."); + if (entry->mask & IT_ENTRY_INSTRUMENT) fprintf(f, " %03d", entry->instrument); else fprintf(f, " ..."); + if (entry->mask & IT_ENTRY_VOLPAN ) fprintf(f, " %03d", entry->volpan ); else fprintf(f, " ..."); + if (entry->mask & IT_ENTRY_EFFECT) fprintf(f, " %c%02X\n", 'A' - 1 + entry->effect, entry->effectvalue); else fprintf(f, " ...\n"); + fclose(f); + } + dupentry[channel] = entry; +#endif + + entry++; + } + } + + ASSERT(entry == pattern->entry + n_entries); + + return 0; +} + + + +/* Currently we assume the sample data are stored after the sample headers in + * module files. This assumption may be unjustified; let me know if you have + * trouble. + */ + +#define IT_COMPONENT_SONG_MESSAGE 1 +#define IT_COMPONENT_INSTRUMENT 2 +#define IT_COMPONENT_PATTERN 3 +#define IT_COMPONENT_SAMPLE 4 + +typedef struct IT_COMPONENT +{ + unsigned char type; + unsigned short n; + long offset; + short sampfirst; /* component[sampfirst] = first sample data after this */ + short sampnext; /* sampnext is used to create linked lists of sample data */ +} +IT_COMPONENT; + + + +static int it_component_compare(const void *e1, const void *e2) +{ + return ((const IT_COMPONENT *)e1)->offset - + ((const IT_COMPONENT *)e2)->offset; +} + + + +static sigdata_t *it_load_sigdata(DUMBFILE *f) +{ + DUMB_IT_SIGDATA *sigdata; + + int cwt, cmwt; + int special; + int message_length, message_offset; + + IT_COMPONENT *component; + int n_components = 0; + + unsigned char sample_convert[4096]; + + int n; + + unsigned char *buffer; + + if (dumbfile_mgetl(f) != IT_SIGNATURE) + return NULL; + + sigdata = malloc(sizeof(*sigdata)); + + if (!sigdata) + return NULL; + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->sample = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + dumbfile_getnc(sigdata->name, 26, f); + sigdata->name[26] = 0; + + /* Skip pattern row highlight info. */ + dumbfile_skip(f, 2); + + sigdata->n_orders = dumbfile_igetw(f); + sigdata->n_instruments = dumbfile_igetw(f); + sigdata->n_samples = dumbfile_igetw(f); + sigdata->n_patterns = dumbfile_igetw(f); + + cwt = dumbfile_igetw(f); + cmwt = dumbfile_igetw(f); + + sigdata->flags = dumbfile_igetw(f); + special = dumbfile_igetw(f); + + sigdata->global_volume = dumbfile_getc(f); + sigdata->mixing_volume = dumbfile_getc(f); + sigdata->speed = dumbfile_getc(f); + if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo? + sigdata->tempo = dumbfile_getc(f); + sigdata->pan_separation = dumbfile_getc(f); /** WARNING: use this */ + + /* Skip Pitch Wheel Depth */ + dumbfile_skip(f, 1); + + message_length = dumbfile_igetw(f); + message_offset = dumbfile_igetl(f); + + /* Skip Reserved. */ + dumbfile_skip(f, 4); + + dumbfile_getnc(sigdata->channel_pan, DUMB_IT_N_CHANNELS, f); + dumbfile_getnc(sigdata->channel_volume, DUMB_IT_N_CHANNELS, f); + + // XXX sample count + if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_instruments > 256 || sigdata->n_samples > 4000 || sigdata->n_patterns > 256) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + sigdata->order = malloc(sigdata->n_orders); + if (!sigdata->order) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (sigdata->n_instruments) { + sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument)); + if (!sigdata->instrument) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + + if (sigdata->n_samples) { + sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); + if (!sigdata->sample) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (n = 0; n < sigdata->n_samples; n++) + sigdata->sample[n].data = NULL; + } + + if (sigdata->n_patterns) { + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (n = 0; n < sigdata->n_patterns; n++) + sigdata->pattern[n].entry = NULL; + } + + dumbfile_getnc(sigdata->order, sigdata->n_orders, f); + sigdata->restart_position = 0; + + component = malloc(769 * sizeof(*component)); + if (!component) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (special & 1) { + component[n_components].type = IT_COMPONENT_SONG_MESSAGE; + component[n_components].offset = message_offset; + component[n_components].sampfirst = -1; + n_components++; + } + + for (n = 0; n < sigdata->n_instruments; n++) { + component[n_components].type = IT_COMPONENT_INSTRUMENT; + component[n_components].n = n; + component[n_components].offset = dumbfile_igetl(f); + component[n_components].sampfirst = -1; + n_components++; + } + + for (n = 0; n < sigdata->n_samples; n++) { + component[n_components].type = IT_COMPONENT_SAMPLE; + component[n_components].n = n; + component[n_components].offset = dumbfile_igetl(f); + component[n_components].sampfirst = -1; + n_components++; + } + + for (n = 0; n < sigdata->n_patterns; n++) { + long offset = dumbfile_igetl(f); + if (offset) { + component[n_components].type = IT_COMPONENT_PATTERN; + component[n_components].n = n; + component[n_components].offset = offset; + component[n_components].sampfirst = -1; + n_components++; + } else { + /* Empty 64-row pattern */ + sigdata->pattern[n].n_rows = 64; + sigdata->pattern[n].n_entries = 0; + } + } + + if (dumbfile_error(f)) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + /* + if (!(sigdata->flags & 128) != !(special & 8)) { + fprintf(stderr, "Flags Bit 7 (\"Request embedded MIDI configuration\"): %s\n", sigdata->flags & 128 ? "=SET=" : "clear"); + fprintf(stderr, "Special Bit 3 (\"MIDI configuration embedded\") : %s\n", special & 8 ? "=SET=" : "clear"); + fprintf(stderr, "entheh would like to investigate this IT file.\n"); + fprintf(stderr, "Please contact him! entheh@users.sf.net\n"); + } + */ + + if (special & 8) { + /* MIDI configuration is embedded. */ + unsigned char mididata[32]; + int i; + sigdata->midi = malloc(sizeof(*sigdata->midi)); + if (!sigdata->midi) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + // Should we be happy with this outcome in some situations? + } + // What are we skipping? + i = dumbfile_igetw(f); + if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + /* Read embedded MIDI configuration */ + // What are the first 9 commands for? + if (dumbfile_skip(f, 32*9)) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (i = 0; i < 16; i++) { + unsigned char len = 0; + int j, leftdigit = -1; + if (dumbfile_getnc(mididata, 32, f) < 32) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + sigdata->midi->SFmacroz[i] = 0; + for (j = 0; j < 32; j++) { + if (leftdigit >= 0) { + if (mididata[j] == 0) { + sigdata->midi->SFmacro[i][len++] = leftdigit; + break; + } else if (mididata[j] == ' ') + sigdata->midi->SFmacro[i][len++] = leftdigit; + else if (mididata[j] >= '0' && mididata[j] <= '9') + sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0'); + else if (mididata[j] >= 'A' && mididata[j] <= 'F') + sigdata->midi->SFmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA); + leftdigit = -1; + } else if (mididata[j] == 0) + break; + else if (mididata[j] == 'z') + sigdata->midi->SFmacroz[i] |= 1 << len++; + else if (mididata[j] >= '0' && mididata[j] <= '9') + leftdigit = mididata[j] - '0'; + else if (mididata[j] >= 'A' && mididata[j] <= 'F') + leftdigit = mididata[j] - 'A' + 0xA; + } + sigdata->midi->SFmacrolen[i] = len; + } + for (i = 0; i < 128; i++) { + unsigned char len = 0; + int j, leftdigit = -1; + dumbfile_getnc(mididata, 32, f); + for (j = 0; j < 32; j++) { + if (leftdigit >= 0) { + if (mididata[j] == 0) { + sigdata->midi->Zmacro[i][len++] = leftdigit; + break; + } else if (mididata[j] == ' ') + sigdata->midi->Zmacro[i][len++] = leftdigit; + else if (mididata[j] >= '0' && mididata[j] <= '9') + sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - '0'); + else if (mididata[j] >= 'A' && mididata[j] <= 'F') + sigdata->midi->Zmacro[i][len++] = (leftdigit << 4) | (mididata[j] - 'A' + 0xA); + leftdigit = -1; + } else if (mididata[j] == 0) + break; + else if (mididata[j] >= '0' && mididata[j] <= '9') + leftdigit = mididata[j] - '0'; + else if (mididata[j] >= 'A' && mididata[j] <= 'F') + leftdigit = mididata[j] - 'A' + 0xA; + } + sigdata->midi->Zmacrolen[i] = len; + } + } + + sigdata->flags &= IT_REAL_FLAGS; + + qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare); + + buffer = malloc(65536); + if (!buffer) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + for (n = 0; n < n_components; n++) { + long offset; + int m; + + /* XXX */ + if ( component[n].offset == 0 ) { + switch (component[n].type) { + case IT_COMPONENT_INSTRUMENT: + memset( &sigdata->instrument[component[n].n], 0, sizeof(IT_INSTRUMENT) ); + break; + case IT_COMPONENT_SAMPLE: + memset( &sigdata->sample[component[n].n], 0, sizeof(IT_SAMPLE) ); + break; + case IT_COMPONENT_PATTERN: + { + IT_PATTERN * p = &sigdata->pattern[component[n].n]; + p->entry = 0; + p->n_rows = 64; + p->n_entries = 0; + } + break; + } + continue; + } + + if (it_seek(f, component[n].offset)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + switch (component[n].type) { + + case IT_COMPONENT_SONG_MESSAGE: + sigdata->song_message = malloc(message_length + 1); + if (sigdata->song_message) { + if (dumbfile_getnc(sigdata->song_message, message_length, f) < message_length) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + sigdata->song_message[message_length] = 0; + } + break; + + case IT_COMPONENT_INSTRUMENT: + if (cmwt < 0x200) + m = it_read_old_instrument(&sigdata->instrument[component[n].n], f); + else + m = it_read_instrument(&sigdata->instrument[component[n].n], f, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0); + + if (m) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + break; + + case IT_COMPONENT_PATTERN: + if (it_read_pattern(&sigdata->pattern[component[n].n], f, buffer)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + break; + + case IT_COMPONENT_SAMPLE: + if (it_read_sample_header(&sigdata->sample[component[n].n], &sample_convert[component[n].n], &offset, f)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) { + short *sample; + + for (m = n + 1; m < n_components; m++) + if (component[m].offset > offset) + break; + m--; + + sample = &component[m].sampfirst; + + while (*sample >= 0 && component[*sample].offset <= offset) + sample = &component[*sample].sampnext; + + component[n].sampnext = *sample; + *sample = n; + + component[n].offset = offset; + } + } + + m = component[n].sampfirst; + + while (m >= 0) { + if (it_seek(f, component[m].offset)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (it_read_sample_data(cmwt, &sigdata->sample[component[m].n], sample_convert[component[m].n], f)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + m = component[m].sampnext; + } + } + + free(buffer); + free(component); + + _dumb_it_fix_invalid_orders(sigdata); + + return sigdata; +} + +DUH *dumb_read_it_quick(DUMBFILE *f) +{ + sigdata_t *sigdata; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_load_sigdata(f); + + if (!sigdata) + return NULL; + + { + const char *tag[1][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + return make_duh(-1, 1, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/itread2.c b/plugins/dumb/dumb-kode54/src/it/itread2.c index 202b8bb9..e152737e 100644 --- a/plugins/dumb/dumb-kode54/src/it/itread2.c +++ b/plugins/dumb/dumb-kode54/src/it/itread2.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itread2.c - Function to read an Impulse Tracker / / \ \
- * module from an open file and do an | < / \_
- * initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from itread.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_read_it(DUMBFILE *f)
-{
- DUH *duh = dumb_read_it_quick(f);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * itread2.c - Function to read an Impulse Tracker / / \ \ + * module from an open file and do an | < / \_ + * initial run-through. | \/ /\ / + * \_ / > / + * Split off from itread.c by entheh. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_read_it(DUMBFILE *f) +{ + DUH *duh = dumb_read_it_quick(f); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/itrender.c b/plugins/dumb/dumb-kode54/src/it/itrender.c index 5dd8e4ef..d1ffc559 100644 --- a/plugins/dumb/dumb-kode54/src/it/itrender.c +++ b/plugins/dumb/dumb-kode54/src/it/itrender.c @@ -500,7 +500,6 @@ static void it_reset_filter_state(IT_FILTER_STATE *state) * output starting at dst[pos]. The pos parameter is required for getting
* click removal right.
*/
-
static void it_filter(DUMB_CLICK_REMOVER *cr, IT_FILTER_STATE *state, sample_t *dst, long pos, sample_t *src, long size, int step, int sampfreq, int cutoff, int resonance)
{
sample_t currsample = state->currsample;
@@ -732,7 +731,6 @@ static void reset_tick_counts(DUMB_IT_SIGRENDERER *sigrenderer) }
-
static void reset_channel_effects(IT_CHANNEL *channel)
{
channel->volslide = 0;
@@ -1058,6 +1056,24 @@ static void update_effects(DUMB_IT_SIGRENDERER *sigrenderer) }
}
+ if (channel->panslide && !IT_IS_SURROUND(channel->pan)) {
+ if (sigrenderer->sigdata->flags & IT_WAS_AN_XM) {
+ if (channel->panslide == -128)
+ channel->truepan = 32;
+ else
+ channel->truepan = MID(32, channel->truepan + channel->panslide*64, 32+255*64);
+ } else {
+ channel->pan += channel->panslide;
+ if (channel->pan > 64) {
+ if (channel->panslide >= 0)
+ channel->pan = 64;
+ else
+ channel->pan = 0;
+ }
+ channel->truepan = channel->pan << IT_ENVELOPE_SHIFT;
+ }
+ }
+
if (channel->channelvolslide) {
channel->channelvolume += channel->channelvolslide;
if (channel->channelvolume > 64) {
@@ -1685,6 +1701,12 @@ static void get_default_volpan(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) return;
}
+ if (sigdata->flags & IT_WAS_AN_XM) {
+ if (!(sigdata->flags & IT_WAS_A_MOD))
+ channel->truepan = 32 + sigdata->sample[channel->sample-1].default_pan*64;
+ return;
+ }
+
{
int pan = sigdata->sample[channel->sample-1].default_pan;
if (pan >= 128 && pan <= 192) {
@@ -5540,3 +5562,4 @@ int dumb_it_scan_for_playable_orders(DUMB_IT_SIGDATA *sigdata, dumb_scan_callbac return 0;
}
+
diff --git a/plugins/dumb/dumb-kode54/src/it/itunload.c b/plugins/dumb/dumb-kode54/src/it/itunload.c index 136fd5c5..efed192a 100644 --- a/plugins/dumb/dumb-kode54/src/it/itunload.c +++ b/plugins/dumb/dumb-kode54/src/it/itunload.c @@ -1,72 +1,72 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * itunload.c - Code to free an Impulse Tracker / / \ \
- * module from memory. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-void _dumb_it_unload_sigdata(sigdata_t *vsigdata)
-{
- if (vsigdata) {
- DUMB_IT_SIGDATA *sigdata = vsigdata;
- int n;
-
- if (sigdata->song_message)
- free(sigdata->song_message);
-
- if (sigdata->order)
- free(sigdata->order);
-
- if (sigdata->instrument)
- free(sigdata->instrument);
-
- if (sigdata->sample) {
- for (n = 0; n < sigdata->n_samples; n++)
- if (sigdata->sample[n].data)
- free(sigdata->sample[n].data);
-
- free(sigdata->sample);
- }
-
- if (sigdata->pattern) {
- for (n = 0; n < sigdata->n_patterns; n++)
- if (sigdata->pattern[n].entry)
- free(sigdata->pattern[n].entry);
- free(sigdata->pattern);
- }
-
- if (sigdata->midi)
- free(sigdata->midi);
-
- {
- IT_CHECKPOINT *checkpoint = sigdata->checkpoint;
- while (checkpoint) {
- IT_CHECKPOINT *next = checkpoint->next;
- _dumb_it_end_sigrenderer(checkpoint->sigrenderer);
- free(checkpoint);
- checkpoint = next;
- }
- }
-
- free(vsigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * itunload.c - Code to free an Impulse Tracker / / \ \ + * module from memory. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> + +#include "dumb.h" +#include "internal/it.h" + + + +void _dumb_it_unload_sigdata(sigdata_t *vsigdata) +{ + if (vsigdata) { + DUMB_IT_SIGDATA *sigdata = vsigdata; + int n; + + if (sigdata->song_message) + free(sigdata->song_message); + + if (sigdata->order) + free(sigdata->order); + + if (sigdata->instrument) + free(sigdata->instrument); + + if (sigdata->sample) { + for (n = 0; n < sigdata->n_samples; n++) + if (sigdata->sample[n].data) + free(sigdata->sample[n].data); + + free(sigdata->sample); + } + + if (sigdata->pattern) { + for (n = 0; n < sigdata->n_patterns; n++) + if (sigdata->pattern[n].entry) + free(sigdata->pattern[n].entry); + free(sigdata->pattern); + } + + if (sigdata->midi) + free(sigdata->midi); + + { + IT_CHECKPOINT *checkpoint = sigdata->checkpoint; + while (checkpoint) { + IT_CHECKPOINT *next = checkpoint->next; + _dumb_it_end_sigrenderer(checkpoint->sigrenderer); + free(checkpoint); + checkpoint = next; + } + } + + free(vsigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/load669.c b/plugins/dumb/dumb-kode54/src/it/load669.c index e5a3fc3f..5fbe92c8 100644 --- a/plugins/dumb/dumb-kode54/src/it/load669.c +++ b/plugins/dumb/dumb-kode54/src/it/load669.c @@ -1,42 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmod.c - Code to read a 669 Composer module / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_669_quick(): loads a 669 file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_669_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_669_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadmod.c - Code to read a 669 Composer module / / \ \ + * file, opening and closing it for | < / \_ + * you. | \/ /\ / + * \_ / > / + * By Chris Moeller | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_669_quick(): loads a 669 file into a DUH struct, returning a + * pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_669_quick(const char *filename) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_669_quick(f); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/load6692.c b/plugins/dumb/dumb-kode54/src/it/load6692.c index 2358838f..20a18012 100644 --- a/plugins/dumb/dumb-kode54/src/it/load6692.c +++ b/plugins/dumb/dumb-kode54/src/it/load6692.c @@ -1,34 +1,34 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmod2.c - Code to read a 669 Composer module / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_669(): loads a 669 file into a DUH struct, returning a pointer
- * to the DUH struct. When you have finished with it, you must pass the
- * pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_669(const char *filename)
-{
- DUH *duh = dumb_load_669_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadmod2.c - Code to read a 669 Composer module / / \ \ + * file, opening and closing it for | < / \_ + * you, and do an initial run-through. | \/ /\ / + * \_ / > / + * By Chris Moeller | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_669(): loads a 669 file into a DUH struct, returning a pointer + * to the DUH struct. When you have finished with it, you must pass the + * pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_669(const char *filename) +{ + DUH *duh = dumb_load_669_quick(filename); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadasy.c b/plugins/dumb/dumb-kode54/src/it/loadasy.c index 86c6ad8c..1bd481af 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadasy.c +++ b/plugins/dumb/dumb-kode54/src/it/loadasy.c @@ -1,42 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadasy.c - Code to read an ASYLUM Music Format / / \ \
- * module file, opening and closing it | < / \_
- * for you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_asy_quick(): loads a AMF file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_asy_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_asy_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadasy.c - Code to read an ASYLUM Music Format / / \ \ + * module file, opening and closing it | < / \_ + * for you. | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_asy_quick(): loads a AMF file into a DUH struct, returning a + * pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_asy_quick(const char *filename) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_asy_quick(f); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadasy2.c b/plugins/dumb/dumb-kode54/src/it/loadasy2.c index 7b253320..845b26cb 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadasy2.c +++ b/plugins/dumb/dumb-kode54/src/it/loadasy2.c @@ -1,34 +1,34 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadasy2.c - Code to read an ASYLUM Music Format / / \ \
- * module file, opening and closing it | < / \_
- * for you, and do an initial run- | \/ /\ /
- * through. \_ / > /
- * | \ / /
- * By Chris Moeller. | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_asy(): loads a AMF file into a DUH struct, returning a pointer
- * to the DUH struct. When you have finished with it, you must pass the
- * pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_asy(const char *filename)
-{
- DUH *duh = dumb_load_asy_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadasy2.c - Code to read an ASYLUM Music Format / / \ \ + * module file, opening and closing it | < / \_ + * for you, and do an initial run- | \/ /\ / + * through. \_ / > / + * | \ / / + * By Chris Moeller. | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_asy(): loads a AMF file into a DUH struct, returning a pointer + * to the DUH struct. When you have finished with it, you must pass the + * pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_asy(const char *filename) +{ + DUH *duh = dumb_load_asy_quick(filename); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadmod.c b/plugins/dumb/dumb-kode54/src/it/loadmod.c index 1c76302d..0b7dc618 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadmod.c +++ b/plugins/dumb/dumb-kode54/src/it/loadmod.c @@ -1,42 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmod.c - Code to read a good old-fashioned / / \ \
- * Amiga module file, opening and | < / \_
- * closing it for you. | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_mod_quick(): loads a MOD file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_mod_quick(const char *filename, int restrict)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_mod_quick(f, restrict);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadmod.c - Code to read a good old-fashioned / / \ \ + * Amiga module file, opening and | < / \_ + * closing it for you. | \/ /\ / + * \_ / > / + * By entheh. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_mod_quick(): loads a MOD file into a DUH struct, returning a + * pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_mod_quick(const char *filename, int restrict) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_mod_quick(f, restrict); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadmod2.c b/plugins/dumb/dumb-kode54/src/it/loadmod2.c index f5ca5310..7847d19f 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadmod2.c +++ b/plugins/dumb/dumb-kode54/src/it/loadmod2.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmod2.c - Function to read a good old- / / \ \
- * fashioned Amiga module file, | < / \_
- * opening and closing it for you, | \/ /\ /
- * and do an initial run-through. \_ / > /
- * | \ / /
- * Split off from loadmod.c by entheh. | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_mod(const char *filename, int restrict)
-{
- DUH *duh = dumb_load_mod_quick(filename, restrict);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadmod2.c - Function to read a good old- / / \ \ + * fashioned Amiga module file, | < / \_ + * opening and closing it for you, | \/ /\ / + * and do an initial run-through. \_ / > / + * | \ / / + * Split off from loadmod.c by entheh. | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_load_mod(const char *filename, int restrict) +{ + DUH *duh = dumb_load_mod_quick(filename, restrict); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadmtm.c b/plugins/dumb/dumb-kode54/src/it/loadmtm.c index 3c974880..1cfe4643 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadmtm.c +++ b/plugins/dumb/dumb-kode54/src/it/loadmtm.c @@ -1,42 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmtm.c - Code to read a MultiTracker Module / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_mtm_quick(): loads a MTM file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_mtm_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_mtm_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadmtm.c - Code to read a MultiTracker Module / / \ \ + * file, opening and closing it for | < / \_ + * you. | \/ /\ / + * \_ / > / + * By Chris Moeller | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_mtm_quick(): loads a MTM file into a DUH struct, returning a + * pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_mtm_quick(const char *filename) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_mtm_quick(f); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadmtm2.c b/plugins/dumb/dumb-kode54/src/it/loadmtm2.c index 9fc23890..11c0c567 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadmtm2.c +++ b/plugins/dumb/dumb-kode54/src/it/loadmtm2.c @@ -1,34 +1,34 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadmtm2.c - Code to read a MultiTracker Module / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_mtm(): loads a MTM file into a DUH struct, returning a pointer
- * to the DUH struct. When you have finished with it, you must pass the
- * pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_mtm(const char *filename)
-{
- DUH *duh = dumb_load_mtm_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadmtm2.c - Code to read a MultiTracker Module / / \ \ + * file, opening and closing it for | < / \_ + * you, and do an initial run-through. | \/ /\ / + * \_ / > / + * By Chris Moeller | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_mtm(): loads a MTM file into a DUH struct, returning a pointer + * to the DUH struct. When you have finished with it, you must pass the + * pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_mtm(const char *filename) +{ + DUH *duh = dumb_load_mtm_quick(filename); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadoldpsm.c b/plugins/dumb/dumb-kode54/src/it/loadoldpsm.c index 547294b3..568d1af6 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadoldpsm.c +++ b/plugins/dumb/dumb-kode54/src/it/loadoldpsm.c @@ -1,43 +1,43 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadoldpsm.c - Code to read a ProTracker Studio / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_old_psm_quick(): loads an old PSM file into a DUH struct,
- * returning a pointer to the DUH struct. When you have finished with it,
- * you must pass the pointer to unload_duh() so that the memory can be
- * freed.
- */
-DUH *dumb_load_old_psm_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_old_psm_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadoldpsm.c - Code to read a ProTracker Studio / / \ \ + * file, opening and closing it for | < / \_ + * you. | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_old_psm_quick(): loads an old PSM file into a DUH struct, + * returning a pointer to the DUH struct. When you have finished with it, + * you must pass the pointer to unload_duh() so that the memory can be + * freed. + */ +DUH *dumb_load_old_psm_quick(const char *filename) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_old_psm_quick(f); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadoldpsm2.c b/plugins/dumb/dumb-kode54/src/it/loadoldpsm2.c index ff2e427c..f9aaaed6 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadoldpsm2.c +++ b/plugins/dumb/dumb-kode54/src/it/loadoldpsm2.c @@ -1,34 +1,34 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadoldpsm2.c - Code to read a ProTracker Studio / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run- | \/ /\ /
- * through. \_ / > /
- * | \ / /
- * By Chris Moeller. | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_old_psm(): loads an old PSM file into a DUH struct, returning
- * a pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_old_psm(const char *filename)
-{
- DUH *duh = dumb_load_old_psm_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadoldpsm2.c - Code to read a ProTracker Studio / / \ \ + * file, opening and closing it for | < / \_ + * you, and do an initial run- | \/ /\ / + * through. \_ / > / + * | \ / / + * By Chris Moeller. | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_old_psm(): loads an old PSM file into a DUH struct, returning + * a pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_old_psm(const char *filename) +{ + DUH *duh = dumb_load_old_psm_quick(filename); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadpsm.c b/plugins/dumb/dumb-kode54/src/it/loadpsm.c index a6851d5b..9f2e81ef 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadpsm.c +++ b/plugins/dumb/dumb-kode54/src/it/loadpsm.c @@ -1,42 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadpsm.c - Code to read a ProTracker Studio / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_psm_quick(): loads a PSM file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_psm_quick(const char *filename, int subsong)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_psm_quick(f, subsong);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadpsm.c - Code to read a ProTracker Studio / / \ \ + * file, opening and closing it for | < / \_ + * you. | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_psm_quick(): loads a PSM file into a DUH struct, returning a + * pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_psm_quick(const char *filename, int subsong) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_psm_quick(f, subsong); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadpsm2.c b/plugins/dumb/dumb-kode54/src/it/loadpsm2.c index 7a12257a..d6fa4359 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadpsm2.c +++ b/plugins/dumb/dumb-kode54/src/it/loadpsm2.c @@ -1,34 +1,34 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadpsm2.c - Code to read a ProTracker Studio / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_psm(): loads a PSM file into a DUH struct, returning a pointer
- * to the DUH struct. When you have finished with it, you must pass the
- * pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_psm(const char *filename, int subsong)
-{
- DUH *duh = dumb_load_psm_quick(filename, subsong);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadpsm2.c - Code to read a ProTracker Studio / / \ \ + * file, opening and closing it for | < / \_ + * you, and do an initial run-through. | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_psm(): loads a PSM file into a DUH struct, returning a pointer + * to the DUH struct. When you have finished with it, you must pass the + * pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_psm(const char *filename, int subsong) +{ + DUH *duh = dumb_load_psm_quick(filename, subsong); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadptm.c b/plugins/dumb/dumb-kode54/src/it/loadptm.c index ddcaaec9..2a3e0fc1 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadptm.c +++ b/plugins/dumb/dumb-kode54/src/it/loadptm.c @@ -1,42 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadptm.c - Code to read a Poly Tracker v2.03 / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_ptm_quick(): loads a PTM file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_ptm_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_ptm_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadptm.c - Code to read a Poly Tracker v2.03 / / \ \ + * file, opening and closing it for | < / \_ + * you. | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_ptm_quick(): loads a PTM file into a DUH struct, returning a + * pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_ptm_quick(const char *filename) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_ptm_quick(f); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadptm2.c b/plugins/dumb/dumb-kode54/src/it/loadptm2.c index ea8982f2..4befb3b6 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadptm2.c +++ b/plugins/dumb/dumb-kode54/src/it/loadptm2.c @@ -1,34 +1,34 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadptm2.c - Code to read a Poly Tracker v2.03 / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_ptm(): loads a PTM file into a DUH struct, returning a pointer
- * to the DUH struct. When you have finished with it, you must pass the
- * pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_ptm(const char *filename)
-{
- DUH *duh = dumb_load_ptm_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadptm2.c - Code to read a Poly Tracker v2.03 / / \ \ + * file, opening and closing it for | < / \_ + * you, and do an initial run-through. | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_ptm(): loads a PTM file into a DUH struct, returning a pointer + * to the DUH struct. When you have finished with it, you must pass the + * pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_ptm(const char *filename) +{ + DUH *duh = dumb_load_ptm_quick(filename); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadriff.c b/plugins/dumb/dumb-kode54/src/it/loadriff.c index 07994b0f..edaf43a6 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadriff.c +++ b/plugins/dumb/dumb-kode54/src/it/loadriff.c @@ -1,42 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadriff.c - Code to read a RIFF module file / / \ \
- * opening and closing it for you. | < / \_
- * | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_riff_quick(): loads a RIFF file into a DUH struct, returning
- * a pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH * dumb_load_riff_quick( const char *filename )
-{
- DUH * duh;
- DUMBFILE * f = dumbfile_open( filename );
-
- if ( ! f )
- return NULL;
-
- duh = dumb_read_riff_quick( f );
-
- dumbfile_close( f );
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadriff.c - Code to read a RIFF module file / / \ \ + * opening and closing it for you. | < / \_ + * | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_riff_quick(): loads a RIFF file into a DUH struct, returning + * a pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH * dumb_load_riff_quick( const char *filename ) +{ + DUH * duh; + DUMBFILE * f = dumbfile_open( filename ); + + if ( ! f ) + return NULL; + + duh = dumb_read_riff_quick( f ); + + dumbfile_close( f ); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadriff2.c b/plugins/dumb/dumb-kode54/src/it/loadriff2.c index 11c5d497..5745041e 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadriff2.c +++ b/plugins/dumb/dumb-kode54/src/it/loadriff2.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadriff2.c - Code to read a RIFF module file / / \ \
- * opening and closing it for you, | < / \_
- * and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_riff(const char *filename)
-{
- DUH *duh = dumb_load_riff_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadriff2.c - Code to read a RIFF module file / / \ \ + * opening and closing it for you, | < / \_ + * and do an initial run-through. | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_load_riff(const char *filename) +{ + DUH *duh = dumb_load_riff_quick(filename); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loads3m.c b/plugins/dumb/dumb-kode54/src/it/loads3m.c index 41af114e..777151c6 100644 --- a/plugins/dumb/dumb-kode54/src/it/loads3m.c +++ b/plugins/dumb/dumb-kode54/src/it/loads3m.c @@ -1,42 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loads3m.c - Code to read a ScreamTracker 3 / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_s3m_quick(): loads an S3M file into a DUH struct, returning
- * a pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_s3m_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_s3m_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loads3m.c - Code to read a ScreamTracker 3 / / \ \ + * file, opening and closing it for | < / \_ + * you. | \/ /\ / + * \_ / > / + * By entheh. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_s3m_quick(): loads an S3M file into a DUH struct, returning + * a pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_s3m_quick(const char *filename) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_s3m_quick(f); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loads3m2.c b/plugins/dumb/dumb-kode54/src/it/loads3m2.c index de81e09a..8b55e83d 100644 --- a/plugins/dumb/dumb-kode54/src/it/loads3m2.c +++ b/plugins/dumb/dumb-kode54/src/it/loads3m2.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loads3m2.c - Function to read a ScreamTracker 3 / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from loads3m.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_s3m(const char *filename)
-{
- DUH *duh = dumb_load_s3m_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loads3m2.c - Function to read a ScreamTracker 3 / / \ \ + * file, opening and closing it for | < / \_ + * you, and do an initial run-through. | \/ /\ / + * \_ / > / + * Split off from loads3m.c by entheh. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_load_s3m(const char *filename) +{ + DUH *duh = dumb_load_s3m_quick(filename); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadstm.c b/plugins/dumb/dumb-kode54/src/it/loadstm.c index 84785208..94e713c3 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadstm.c +++ b/plugins/dumb/dumb-kode54/src/it/loadstm.c @@ -1,42 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadstm.c - Code to read a ScreamTracker 2 / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_stm_quick(): loads an STM file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_stm_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_stm_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadstm.c - Code to read a ScreamTracker 2 / / \ \ + * file, opening and closing it for | < / \_ + * you. | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_stm_quick(): loads an STM file into a DUH struct, returning a + * pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_stm_quick(const char *filename) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_stm_quick(f); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadstm2.c b/plugins/dumb/dumb-kode54/src/it/loadstm2.c index 4655b52d..ca0f134d 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadstm2.c +++ b/plugins/dumb/dumb-kode54/src/it/loadstm2.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadstm2.c - Function to read a ScreamTracker 2 / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_stm(const char *filename)
-{
- DUH *duh = dumb_load_stm_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadstm2.c - Function to read a ScreamTracker 2 / / \ \ + * file, opening and closing it for | < / \_ + * you, and do an initial run-through. | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_load_stm(const char *filename) +{ + DUH *duh = dumb_load_stm_quick(filename); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadxm.c b/plugins/dumb/dumb-kode54/src/it/loadxm.c index a0eba616..2c8067cb 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadxm.c +++ b/plugins/dumb/dumb-kode54/src/it/loadxm.c @@ -1,42 +1,42 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadxm.c - Code to read a Fast Tracker II / / \ \
- * file, opening and closing it for | < / \_
- * you. | \/ /\ /
- * \_ / > /
- * By entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/* dumb_load_xm_quick(): loads an XM file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must
- * pass the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_load_xm_quick(const char *filename)
-{
- DUH *duh;
- DUMBFILE *f = dumbfile_open(filename);
-
- if (!f)
- return NULL;
-
- duh = dumb_read_xm_quick(f);
-
- dumbfile_close(f);
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadxm.c - Code to read a Fast Tracker II / / \ \ + * file, opening and closing it for | < / \_ + * you. | \/ /\ / + * \_ / > / + * By entheh. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" + + + +/* dumb_load_xm_quick(): loads an XM file into a DUH struct, returning a + * pointer to the DUH struct. When you have finished with it, you must + * pass the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_load_xm_quick(const char *filename) +{ + DUH *duh; + DUMBFILE *f = dumbfile_open(filename); + + if (!f) + return NULL; + + duh = dumb_read_xm_quick(f); + + dumbfile_close(f); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/loadxm2.c b/plugins/dumb/dumb-kode54/src/it/loadxm2.c index 242a586d..a596542a 100644 --- a/plugins/dumb/dumb-kode54/src/it/loadxm2.c +++ b/plugins/dumb/dumb-kode54/src/it/loadxm2.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * loadxm2.c - Function to read a Fast Tracker II / / \ \
- * file, opening and closing it for | < / \_
- * you, and do an initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from loadxm.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_load_xm(const char *filename)
-{
- DUH *duh = dumb_load_xm_quick(filename);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * loadxm2.c - Function to read a Fast Tracker II / / \ \ + * file, opening and closing it for | < / \_ + * you, and do an initial run-through. | \/ /\ / + * \_ / > / + * Split off from loadxm.c by entheh. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_load_xm(const char *filename) +{ + DUH *duh = dumb_load_xm_quick(filename); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/ptmeffect.c b/plugins/dumb/dumb-kode54/src/it/ptmeffect.c index b05a5d74..cbc2e90c 100644 --- a/plugins/dumb/dumb-kode54/src/it/ptmeffect.c +++ b/plugins/dumb/dumb-kode54/src/it/ptmeffect.c @@ -1,125 +1,125 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * ptmeffect.c - Code for converting PTM / / \ \
- * effects to IT effects. | < / \_
- * | \/ /\ /
- * By Chris Moeller. Based on xmeffect.c \_ / > /
- * by Julien Cugniere. | \ / /
- * | ' /
- * \__/
- */
-
-
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry)
-{
- if (effect >= PTM_N_EFFECTS)
- return;
-
- /* Linearisation of the effect number... */
- if (effect == PTM_E) {
- effect = PTM_EBASE + HIGH(value);
- value = LOW(value);
- }
-
- /* convert effect */
- entry->mask |= IT_ENTRY_EFFECT;
- switch (effect) {
-
- case PTM_APPREGIO: effect = IT_ARPEGGIO; break;
- case PTM_PORTAMENTO_UP: effect = IT_PORTAMENTO_UP; break;
- case PTM_PORTAMENTO_DOWN: effect = IT_PORTAMENTO_DOWN; break;
- case PTM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break;
- case PTM_VIBRATO: effect = IT_VIBRATO; break;
- case PTM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break;
- case PTM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break;
- case PTM_TREMOLO: effect = IT_TREMOLO; break;
- case PTM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break;
- case PTM_VOLUME_SLIDE: effect = IT_VOLUME_SLIDE; break;
- case PTM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break;
- case PTM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break;
- case PTM_PATTERN_BREAK: effect = IT_BREAK_TO_ROW; break;
- case PTM_SET_GLOBAL_VOLUME: effect = IT_SET_GLOBAL_VOLUME; break;
- case PTM_RETRIGGER: effect = IT_RETRIGGER_NOTE; break;
- case PTM_FINE_VIBRATO: effect = IT_FINE_VIBRATO; break;
-
- /* TODO properly */
- case PTM_NOTE_SLIDE_UP: effect = IT_PTM_NOTE_SLIDE_UP; break;
- case PTM_NOTE_SLIDE_DOWN: effect = IT_PTM_NOTE_SLIDE_DOWN; break;
- case PTM_NOTE_SLIDE_UP_RETRIG: effect = IT_PTM_NOTE_SLIDE_UP_RETRIG; break;
- case PTM_NOTE_SLIDE_DOWN_RETRIG: effect = IT_PTM_NOTE_SLIDE_DOWN_RETRIG; break;
-
- case PTM_SET_TEMPO_BPM:
- effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
- break;
-
- case PTM_EBASE+PTM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break; /** TODO */
- case PTM_EBASE+PTM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break;
- case PTM_EBASE+PTM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break;
- case PTM_EBASE+PTM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break;
- case PTM_EBASE+PTM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break;
- case PTM_EBASE+PTM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break;
-
- case PTM_EBASE+PTM_E_FINE_VOLSLIDE_UP:
- effect = IT_VOLUME_SLIDE;
- value = EFFECT_VALUE(value, 0xF);
- break;
-
- case PTM_EBASE + PTM_E_FINE_VOLSLIDE_DOWN:
- effect = IT_VOLUME_SLIDE;
- value = EFFECT_VALUE(0xF, value);
- break;
-
- case PTM_EBASE + PTM_E_FINE_PORTA_UP:
- effect = IT_PORTAMENTO_UP;
- value = EFFECT_VALUE(0xF, value);
- break;
-
- case PTM_EBASE + PTM_E_FINE_PORTA_DOWN:
- effect = IT_PORTAMENTO_DOWN;
- value = EFFECT_VALUE(0xF, value);
- break;
-
- case PTM_EBASE + PTM_E_RETRIG_NOTE:
- effect = IT_XM_RETRIGGER_NOTE;
- value = EFFECT_VALUE(0, value);
- break;
-
- case PTM_EBASE + PTM_E_SET_VIBRATO_CONTROL:
- effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM;
- value &= ~4; /** TODO: value&4 -> don't retrig wave */
- break;
-
- case PTM_EBASE + PTM_E_SET_TREMOLO_CONTROL:
- effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM;
- value &= ~4; /** TODO: value&4 -> don't retrig wave */
- break;
-
- default:
- /* user effect (often used in demos for synchronisation) */
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
-
- /* Inverse linearisation... */
- if (effect >= SBASE && effect < SBASE+16) {
- value = EFFECT_VALUE(effect-SBASE, value);
- effect = IT_S;
- }
-
- entry->effect = effect;
- entry->effectvalue = value;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * ptmeffect.c - Code for converting PTM / / \ \ + * effects to IT effects. | < / \_ + * | \/ /\ / + * By Chris Moeller. Based on xmeffect.c \_ / > / + * by Julien Cugniere. | \ / / + * | ' / + * \__/ + */ + + + +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" +#include "internal/it.h" + +void _dumb_it_ptm_convert_effect(int effect, int value, IT_ENTRY *entry) +{ + if (effect >= PTM_N_EFFECTS) + return; + + /* Linearisation of the effect number... */ + if (effect == PTM_E) { + effect = PTM_EBASE + HIGH(value); + value = LOW(value); + } + + /* convert effect */ + entry->mask |= IT_ENTRY_EFFECT; + switch (effect) { + + case PTM_APPREGIO: effect = IT_ARPEGGIO; break; + case PTM_PORTAMENTO_UP: effect = IT_PORTAMENTO_UP; break; + case PTM_PORTAMENTO_DOWN: effect = IT_PORTAMENTO_DOWN; break; + case PTM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break; + case PTM_VIBRATO: effect = IT_VIBRATO; break; + case PTM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break; + case PTM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break; + case PTM_TREMOLO: effect = IT_TREMOLO; break; + case PTM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break; + case PTM_VOLUME_SLIDE: effect = IT_VOLUME_SLIDE; break; + case PTM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break; + case PTM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break; + case PTM_PATTERN_BREAK: effect = IT_BREAK_TO_ROW; break; + case PTM_SET_GLOBAL_VOLUME: effect = IT_SET_GLOBAL_VOLUME; break; + case PTM_RETRIGGER: effect = IT_RETRIGGER_NOTE; break; + case PTM_FINE_VIBRATO: effect = IT_FINE_VIBRATO; break; + + /* TODO properly */ + case PTM_NOTE_SLIDE_UP: effect = IT_PTM_NOTE_SLIDE_UP; break; + case PTM_NOTE_SLIDE_DOWN: effect = IT_PTM_NOTE_SLIDE_DOWN; break; + case PTM_NOTE_SLIDE_UP_RETRIG: effect = IT_PTM_NOTE_SLIDE_UP_RETRIG; break; + case PTM_NOTE_SLIDE_DOWN_RETRIG: effect = IT_PTM_NOTE_SLIDE_DOWN_RETRIG; break; + + case PTM_SET_TEMPO_BPM: + effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO); + break; + + case PTM_EBASE+PTM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break; /** TODO */ + case PTM_EBASE+PTM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break; + case PTM_EBASE+PTM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break; + case PTM_EBASE+PTM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break; + case PTM_EBASE+PTM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break; + case PTM_EBASE+PTM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break; + + case PTM_EBASE+PTM_E_FINE_VOLSLIDE_UP: + effect = IT_VOLUME_SLIDE; + value = EFFECT_VALUE(value, 0xF); + break; + + case PTM_EBASE + PTM_E_FINE_VOLSLIDE_DOWN: + effect = IT_VOLUME_SLIDE; + value = EFFECT_VALUE(0xF, value); + break; + + case PTM_EBASE + PTM_E_FINE_PORTA_UP: + effect = IT_PORTAMENTO_UP; + value = EFFECT_VALUE(0xF, value); + break; + + case PTM_EBASE + PTM_E_FINE_PORTA_DOWN: + effect = IT_PORTAMENTO_DOWN; + value = EFFECT_VALUE(0xF, value); + break; + + case PTM_EBASE + PTM_E_RETRIG_NOTE: + effect = IT_XM_RETRIGGER_NOTE; + value = EFFECT_VALUE(0, value); + break; + + case PTM_EBASE + PTM_E_SET_VIBRATO_CONTROL: + effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM; + value &= ~4; /** TODO: value&4 -> don't retrig wave */ + break; + + case PTM_EBASE + PTM_E_SET_TREMOLO_CONTROL: + effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM; + value &= ~4; /** TODO: value&4 -> don't retrig wave */ + break; + + default: + /* user effect (often used in demos for synchronisation) */ + entry->mask &= ~IT_ENTRY_EFFECT; + } + + /* Inverse linearisation... */ + if (effect >= SBASE && effect < SBASE+16) { + value = EFFECT_VALUE(effect-SBASE, value); + effect = IT_S; + } + + entry->effect = effect; + entry->effectvalue = value; +} diff --git a/plugins/dumb/dumb-kode54/src/it/read669.c b/plugins/dumb/dumb-kode54/src/it/read669.c index 4cb88d30..f52d397f 100644 --- a/plugins/dumb/dumb-kode54/src/it/read669.c +++ b/plugins/dumb/dumb-kode54/src/it/read669.c @@ -1,447 +1,447 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * read669.c - Code to read a 669 Composer module / / \ \
- * from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-static int it_669_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int tempo, int breakpoint, unsigned char *buffer, int * used_channels)
-{
- int pos;
- int channel;
- int row;
- IT_ENTRY *entry;
-
- pattern->n_rows = 64;
-
- if (dumbfile_getnc(buffer, 64 * 3 * 8, f) < 64 * 3 * 8)
- return -1;
-
- /* compute number of entries */
- pattern->n_entries = 64 + 1; /* Account for the row end markers, speed command */
- if (breakpoint < 63) pattern->n_entries++; /* and break to row 0 */
-
- pos = 0;
- for (row = 0; row < 64; row++) {
- for (channel = 0; channel < 8; channel++) {
- if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF)
- pattern->n_entries++;
- pos += 3;
- }
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
- if (!pattern->entry)
- return -1;
-
- if (breakpoint == 63) breakpoint++;
-
- entry = pattern->entry;
-
- entry->channel = 8;
- entry->mask = IT_ENTRY_EFFECT;
- entry->effect = IT_SET_SPEED;
- entry->effectvalue = tempo;
- entry++;
-
- pos = 0;
- for (row = 0; row < 64; row++) {
-
- if (row == breakpoint) {
- entry->channel = 8;
- entry->mask = IT_ENTRY_EFFECT;
- entry->effect = IT_BREAK_TO_ROW;
- entry->effectvalue = 0;
- entry++;
- }
-
- for (channel = 0; channel < 8; channel++) {
- if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF) {
- entry->channel = channel;
- entry->mask = 0;
-
- if (buffer[pos+0] < 0xFE) {
- entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT;
- entry->note = (buffer[pos+0] >> 2) + 36;
- entry->instrument = (((buffer[pos+0] << 4) | (buffer[pos+1] >> 4)) & 0x3F) + 1;
- }
- if (buffer[pos+0] <= 0xFE) {
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->volpan = ((buffer[pos+1] & 15) << 6) / 15;
- if (*used_channels < channel + 1) *used_channels = channel + 1;
- }
- if (buffer[pos+2] != 0xFF) {
- entry->mask |= IT_ENTRY_EFFECT;
- entry->effectvalue = buffer[pos+2] & 15;
- switch (buffer[pos+2] >> 4) {
- case 0:
- entry->effect = IT_PORTAMENTO_UP;
- break;
- case 1:
- entry->effect = IT_PORTAMENTO_DOWN;
- break;
- case 2:
- entry->effect = IT_TONE_PORTAMENTO;
- break;
- case 3:
- entry->effect = IT_S;
- entry->effectvalue += IT_S_FINETUNE * 16 + 8;
- break;
- case 4:
- entry->effect = IT_VIBRATO;
- // XXX speed unknown
- entry->effectvalue |= 0x10;
- break;
- case 5:
- if (entry->effectvalue) {
- entry->effect = IT_SET_SPEED;
- } else {
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
- break;
-#if 0
- /* dunno about this, really... */
- case 6:
- if (entry->effectvalue == 0) {
- entry->effect = IT_PANNING_SLIDE;
- entry->effectvalue = 0xFE;
- } else if (entry->effectvalue == 1) {
- entry->effect = IT_PANNING_SLIDE;
- entry->effectvalue = 0xEF;
- } else {
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
- break;
-#endif
- default:
- entry->mask &= ~IT_ENTRY_EFFECT;
- break;
- }
- if (*used_channels < channel + 1) *used_channels = channel + 1;
- }
-
- entry++;
- }
- pos += 3;
- }
- IT_SET_END_ROW(entry);
- entry++;
- }
-
- return 0;
-}
-
-
-
-static int it_669_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
-{
- dumbfile_getnc(sample->name, 13, f);
- sample->name[13] = 0;
-
- sample->filename[0] = 0;
-
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = dumbfile_igetl(f);
-
- if (dumbfile_error(f))
- return -1;
-
- if (sample->length <= 0) {
- sample->flags = 0;
- return 0;
- }
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- sample->global_volume = 64;
- sample->default_volume = 64;
-
- sample->default_pan = 0;
- sample->C5_speed = 8363;
- // the above line might be wrong
-
- if ((sample->loop_end > sample->length) && !(sample->loop_start))
- sample->loop_end = 0;
-
- if (sample->loop_end > sample->length)
- sample->loop_end = sample->length;
-
- if (sample->loop_end - sample->loop_start > 2)
- sample->flags |= IT_SAMPLE_LOOP;
-
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = 0; // do we have to set _all_ these?
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- return 0;
-}
-
-
-
-static int it_669_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f)
-{
- long i;
- long truncated_size;
-
- /* let's get rid of the sample data coming after the end of the loop */
- if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
- truncated_size = sample->length - sample->loop_end;
- sample->length = sample->loop_end;
- } else {
- truncated_size = 0;
- }
-
- sample->data = malloc(sample->length);
-
- if (!sample->data)
- return -1;
-
- if (sample->length)
- {
- i = dumbfile_getnc(sample->data, sample->length, f);
-
- if (i < sample->length) {
- //return -1;
- // ficking truncated files
- if (i <= 0) {
- sample->flags = 0;
- return 0;
- }
- sample->length = i;
- if (sample->loop_end > i) sample->loop_end = i;
- } else {
- /* skip truncated data */
- dumbfile_skip(f, truncated_size);
- // Should we be truncating it?
- if (dumbfile_error(f))
- return -1;
- }
-
- for (i = 0; i < sample->length; i++)
- ((signed char *)sample->data)[i] ^= 0x80;
- }
-
- return 0;
-}
-
-
-static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext)
-{
- DUMB_IT_SIGDATA *sigdata;
- int n_channels;
- int i;
- unsigned char tempolist[128];
- unsigned char breaklist[128];
-
- i = dumbfile_igetw(f);
- if (i != 0x6669 && i != 0x4E4A) return NULL;
-
- *ext = (i == 0x4E4A);
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) {
- return NULL;
- }
-
- if (dumbfile_getnc(sigdata->name, 36, f) < 36) {
- free(sigdata);
- return NULL;
- }
- sigdata->name[36] = 0;
-
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
- sigdata->sample = NULL;
-
- sigdata->n_instruments = 0;
-
- sigdata->song_message = malloc(72 + 2 + 1);
- if (!sigdata->song_message) {
- free(sigdata);
- return NULL;
- }
- if (dumbfile_getnc(sigdata->song_message, 36, f) < 36) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- sigdata->song_message[36] = 13;
- sigdata->song_message[36 + 1] = 10;
- if (dumbfile_getnc(sigdata->song_message + 38, 36, f) < 36) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- sigdata->song_message[38 + 36] = 0;
-
- sigdata->n_samples = dumbfile_getc(f);
- sigdata->n_patterns = dumbfile_getc(f);
- sigdata->restart_position = dumbfile_getc(f);
-
- if ((sigdata->n_samples) > 64 || (sigdata->n_patterns > 128)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->order = malloc(128); /* We may need to scan the extra ones! */
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- if (dumbfile_getnc(sigdata->order, 128, f) < 128) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (i = 0; i < 128; i++) {
- if (sigdata->order[i] == 255) break;
- if (sigdata->order[i] >= sigdata->n_patterns) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- if (!i) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- sigdata->n_orders = i;
-
- if (dumbfile_getnc(tempolist, 128, f) < 128) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (dumbfile_getnc(breaklist, 128, f) < 128) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (i = 0; i < sigdata->n_samples; i++)
- sigdata->sample[i].data = NULL;
-
- for (i = 0; i < sigdata->n_samples; i++) {
- if (it_669_read_sample_header(&sigdata->sample[i], f)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
-
- /* May as well try to save a tiny bit of memory. */
- if (sigdata->n_orders < 128) {
- unsigned char *order = realloc(sigdata->order, sigdata->n_orders);
- if (order) sigdata->order = order;
- }
-
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++)
- sigdata->pattern[i].entry = NULL;
-
- n_channels = 0;
-
- /* Read in the patterns */
- {
- unsigned char *buffer = malloc(64 * 3 * 8); /* 64 rows * 3 bytes * 8 channels */
- if (!buffer) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++) {
- if (it_669_read_pattern(&sigdata->pattern[i], f, tempolist[i], breaklist[i], buffer, &n_channels) != 0) {
- free(buffer);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- free(buffer);
- }
-
- sigdata->n_pchannels = n_channels;
-
- /* And finally, the sample data */
- for (i = 0; i < sigdata->n_samples; i++) {
- if (it_669_read_sample_data(&sigdata->sample[i], f)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
-
- /* Now let's initialise the remaining variables, and we're done! */
- sigdata->flags = IT_OLD_EFFECTS | IT_LINEAR_SLIDES | IT_STEREO | IT_WAS_A_669;
-
- sigdata->global_volume = 128;
- sigdata->mixing_volume = 48;
- sigdata->speed = 4;
- sigdata->tempo = 78;
- sigdata->pan_separation = 128;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (i = 0; i < DUMB_IT_N_CHANNELS; i += 2) {
- sigdata->channel_pan[i+0] = 48;
- sigdata->channel_pan[i+1] = 16;
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-
-
-DUH *dumb_read_669_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
- int ext;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_669_load_sigdata(f, &ext);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = ext ? "669 Extended" : "669";
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * read669.c - Code to read a 669 Composer module / / \ \ + * from an open file. | < / \_ + * | \/ /\ / + * By Chris Moeller. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "dumb.h" +#include "internal/it.h" + + + +static int it_669_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int tempo, int breakpoint, unsigned char *buffer, int * used_channels) +{ + int pos; + int channel; + int row; + IT_ENTRY *entry; + + pattern->n_rows = 64; + + if (dumbfile_getnc(buffer, 64 * 3 * 8, f) < 64 * 3 * 8) + return -1; + + /* compute number of entries */ + pattern->n_entries = 64 + 1; /* Account for the row end markers, speed command */ + if (breakpoint < 63) pattern->n_entries++; /* and break to row 0 */ + + pos = 0; + for (row = 0; row < 64; row++) { + for (channel = 0; channel < 8; channel++) { + if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF) + pattern->n_entries++; + pos += 3; + } + } + + pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); + if (!pattern->entry) + return -1; + + if (breakpoint == 63) breakpoint++; + + entry = pattern->entry; + + entry->channel = 8; + entry->mask = IT_ENTRY_EFFECT; + entry->effect = IT_SET_SPEED; + entry->effectvalue = tempo; + entry++; + + pos = 0; + for (row = 0; row < 64; row++) { + + if (row == breakpoint) { + entry->channel = 8; + entry->mask = IT_ENTRY_EFFECT; + entry->effect = IT_BREAK_TO_ROW; + entry->effectvalue = 0; + entry++; + } + + for (channel = 0; channel < 8; channel++) { + if (buffer[pos+0] != 0xFF || buffer[pos+2] != 0xFF) { + entry->channel = channel; + entry->mask = 0; + + if (buffer[pos+0] < 0xFE) { + entry->mask |= IT_ENTRY_NOTE | IT_ENTRY_INSTRUMENT; + entry->note = (buffer[pos+0] >> 2) + 36; + entry->instrument = (((buffer[pos+0] << 4) | (buffer[pos+1] >> 4)) & 0x3F) + 1; + } + if (buffer[pos+0] <= 0xFE) { + entry->mask |= IT_ENTRY_VOLPAN; + entry->volpan = ((buffer[pos+1] & 15) << 6) / 15; + if (*used_channels < channel + 1) *used_channels = channel + 1; + } + if (buffer[pos+2] != 0xFF) { + entry->mask |= IT_ENTRY_EFFECT; + entry->effectvalue = buffer[pos+2] & 15; + switch (buffer[pos+2] >> 4) { + case 0: + entry->effect = IT_PORTAMENTO_UP; + break; + case 1: + entry->effect = IT_PORTAMENTO_DOWN; + break; + case 2: + entry->effect = IT_TONE_PORTAMENTO; + break; + case 3: + entry->effect = IT_S; + entry->effectvalue += IT_S_FINETUNE * 16 + 8; + break; + case 4: + entry->effect = IT_VIBRATO; + // XXX speed unknown + entry->effectvalue |= 0x10; + break; + case 5: + if (entry->effectvalue) { + entry->effect = IT_SET_SPEED; + } else { + entry->mask &= ~IT_ENTRY_EFFECT; + } + break; +#if 0 + /* dunno about this, really... */ + case 6: + if (entry->effectvalue == 0) { + entry->effect = IT_PANNING_SLIDE; + entry->effectvalue = 0xFE; + } else if (entry->effectvalue == 1) { + entry->effect = IT_PANNING_SLIDE; + entry->effectvalue = 0xEF; + } else { + entry->mask &= ~IT_ENTRY_EFFECT; + } + break; +#endif + default: + entry->mask &= ~IT_ENTRY_EFFECT; + break; + } + if (*used_channels < channel + 1) *used_channels = channel + 1; + } + + entry++; + } + pos += 3; + } + IT_SET_END_ROW(entry); + entry++; + } + + return 0; +} + + + +static int it_669_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) +{ + dumbfile_getnc(sample->name, 13, f); + sample->name[13] = 0; + + sample->filename[0] = 0; + + sample->length = dumbfile_igetl(f); + sample->loop_start = dumbfile_igetl(f); + sample->loop_end = dumbfile_igetl(f); + + if (dumbfile_error(f)) + return -1; + + if (sample->length <= 0) { + sample->flags = 0; + return 0; + } + + sample->flags = IT_SAMPLE_EXISTS; + + sample->global_volume = 64; + sample->default_volume = 64; + + sample->default_pan = 0; + sample->C5_speed = 8363; + // the above line might be wrong + + if ((sample->loop_end > sample->length) && !(sample->loop_start)) + sample->loop_end = 0; + + if (sample->loop_end > sample->length) + sample->loop_end = sample->length; + + if (sample->loop_end - sample->loop_start > 2) + sample->flags |= IT_SAMPLE_LOOP; + + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = 0; // do we have to set _all_ these? + sample->finetune = 0; + sample->max_resampling_quality = -1; + + return 0; +} + + + +static int it_669_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f) +{ + long i; + long truncated_size; + + /* let's get rid of the sample data coming after the end of the loop */ + if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) { + truncated_size = sample->length - sample->loop_end; + sample->length = sample->loop_end; + } else { + truncated_size = 0; + } + + sample->data = malloc(sample->length); + + if (!sample->data) + return -1; + + if (sample->length) + { + i = dumbfile_getnc(sample->data, sample->length, f); + + if (i < sample->length) { + //return -1; + // ficking truncated files + if (i <= 0) { + sample->flags = 0; + return 0; + } + sample->length = i; + if (sample->loop_end > i) sample->loop_end = i; + } else { + /* skip truncated data */ + dumbfile_skip(f, truncated_size); + // Should we be truncating it? + if (dumbfile_error(f)) + return -1; + } + + for (i = 0; i < sample->length; i++) + ((signed char *)sample->data)[i] ^= 0x80; + } + + return 0; +} + + +static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext) +{ + DUMB_IT_SIGDATA *sigdata; + int n_channels; + int i; + unsigned char tempolist[128]; + unsigned char breaklist[128]; + + i = dumbfile_igetw(f); + if (i != 0x6669 && i != 0x4E4A) return NULL; + + *ext = (i == 0x4E4A); + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) { + return NULL; + } + + if (dumbfile_getnc(sigdata->name, 36, f) < 36) { + free(sigdata); + return NULL; + } + sigdata->name[36] = 0; + + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + sigdata->sample = NULL; + + sigdata->n_instruments = 0; + + sigdata->song_message = malloc(72 + 2 + 1); + if (!sigdata->song_message) { + free(sigdata); + return NULL; + } + if (dumbfile_getnc(sigdata->song_message, 36, f) < 36) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + sigdata->song_message[36] = 13; + sigdata->song_message[36 + 1] = 10; + if (dumbfile_getnc(sigdata->song_message + 38, 36, f) < 36) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + sigdata->song_message[38 + 36] = 0; + + sigdata->n_samples = dumbfile_getc(f); + sigdata->n_patterns = dumbfile_getc(f); + sigdata->restart_position = dumbfile_getc(f); + + if ((sigdata->n_samples) > 64 || (sigdata->n_patterns > 128)) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + sigdata->order = malloc(128); /* We may need to scan the extra ones! */ + if (!sigdata->order) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + if (dumbfile_getnc(sigdata->order, 128, f) < 128) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + for (i = 0; i < 128; i++) { + if (sigdata->order[i] == 255) break; + if (sigdata->order[i] >= sigdata->n_patterns) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + if (!i) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + sigdata->n_orders = i; + + if (dumbfile_getnc(tempolist, 128, f) < 128) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (dumbfile_getnc(breaklist, 128, f) < 128) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); + if (!sigdata->sample) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + for (i = 0; i < sigdata->n_samples; i++) + sigdata->sample[i].data = NULL; + + for (i = 0; i < sigdata->n_samples; i++) { + if (it_669_read_sample_header(&sigdata->sample[i], f)) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + + /* May as well try to save a tiny bit of memory. */ + if (sigdata->n_orders < 128) { + unsigned char *order = realloc(sigdata->order, sigdata->n_orders); + if (order) sigdata->order = order; + } + + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (i = 0; i < sigdata->n_patterns; i++) + sigdata->pattern[i].entry = NULL; + + n_channels = 0; + + /* Read in the patterns */ + { + unsigned char *buffer = malloc(64 * 3 * 8); /* 64 rows * 3 bytes * 8 channels */ + if (!buffer) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (i = 0; i < sigdata->n_patterns; i++) { + if (it_669_read_pattern(&sigdata->pattern[i], f, tempolist[i], breaklist[i], buffer, &n_channels) != 0) { + free(buffer); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + free(buffer); + } + + sigdata->n_pchannels = n_channels; + + /* And finally, the sample data */ + for (i = 0; i < sigdata->n_samples; i++) { + if (it_669_read_sample_data(&sigdata->sample[i], f)) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + + /* Now let's initialise the remaining variables, and we're done! */ + sigdata->flags = IT_OLD_EFFECTS | IT_LINEAR_SLIDES | IT_STEREO | IT_WAS_A_669; + + sigdata->global_volume = 128; + sigdata->mixing_volume = 48; + sigdata->speed = 4; + sigdata->tempo = 78; + sigdata->pan_separation = 128; + + memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); + + for (i = 0; i < DUMB_IT_N_CHANNELS; i += 2) { + sigdata->channel_pan[i+0] = 48; + sigdata->channel_pan[i+1] = 16; + } + + _dumb_it_fix_invalid_orders(sigdata); + + return sigdata; +} + + + +DUH *dumb_read_669_quick(DUMBFILE *f) +{ + sigdata_t *sigdata; + int ext; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_669_load_sigdata(f, &ext); + + if (!sigdata) + return NULL; + + { + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = ext ? "669 Extended" : "669"; + return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/readam.c b/plugins/dumb/dumb-kode54/src/it/readam.c index 14ad3c07..b51a80d6 100644 --- a/plugins/dumb/dumb-kode54/src/it/readam.c +++ b/plugins/dumb/dumb-kode54/src/it/readam.c @@ -1,752 +1,752 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readam.c - Code to read a RIFF AM module / / \ \
- * from a parsed RIFF structure. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-#include "internal/riff.h"
-
-static int it_riff_am_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len, int ver )
-{
- int header_length;
- int default_pan;
- int default_volume;
- int flags;
- int length;
- int length_bytes;
- int loop_start;
- int loop_end;
- int sample_rate;
-
- if ( ver == 0 )
- {
- if ( len < 0x38 )
- return -1;
-
- header_length = 0x38;
-
- memcpy( sample->name, data, 28 );
- sample->name[ 28 ] = 0;
-
- default_pan = data[ 0x1C ];
- default_volume = data[ 0x1D ];
- flags = data[ 0x1E ] | ( data[ 0x1F ] << 8 );
- length = data[ 0x20 ] | ( data[ 0x21 ] << 8 ) | ( data[ 0x22 ] << 16 ) | ( data[ 0x23 ] << 24 );
- loop_start = data[ 0x24 ] | ( data[ 0x25 ] << 8 ) | ( data[ 0x26 ] << 16 ) | ( data[ 0x27 ] << 24 );
- loop_end = data[ 0x28 ] | ( data[ 0x29 ] << 8 ) | ( data[ 0x2A ] << 16 ) | ( data[ 0x2B ] << 24 );
- sample_rate = data[ 0x2C ] | ( data[ 0x2D ] << 8 ) | ( data[ 0x2E ] << 16 ) | ( data[ 0x2F ] << 24 );
- }
- else
- {
- if (len < 4) return -1;
-
- header_length = data[ 0 ] | ( data[ 1 ] << 8 ) | ( data[ 2 ] << 16 ) | ( data[ 3 ] << 24 );
- if ( header_length < 0x40 )
- return -1;
- if ( header_length + 4 > len )
- return -1;
-
- data += 4;
- len -= 4;
-
- memcpy( sample->name, data, 32 );
- sample->name[ 32 ] = 0;
-
- default_pan = data[ 0x20 ] | ( data[ 0x21 ] << 8 );
- default_volume = data[ 0x22 ] | ( data[ 0x23 ] << 8 );
- flags = data[ 0x24 ] | ( data[ 0x25 ] << 8 ); /* | ( data[ 0x26 ] << 16 ) | ( data[ 0x27 ] << 24 );*/
- length = data[ 0x28 ] | ( data[ 0x29 ] << 8 ) | ( data[ 0x2A ] << 16 ) | ( data[ 0x2B ] << 24 );
- loop_start = data[ 0x2C ] | ( data[ 0x2D ] << 8 ) | ( data[ 0x2E ] << 16 ) | ( data[ 0x2F ] << 24 );
- loop_end = data[ 0x30 ] | ( data[ 0x31 ] << 8 ) | ( data[ 0x32 ] << 16 ) | ( data[ 0x33 ] << 24 );
- sample_rate = data[ 0x34 ] | ( data[ 0x35 ] << 8 ) | ( data[ 0x36 ] << 16 ) | ( data[ 0x37 ] << 24 );
-
- if ( default_pan > 0x7FFF || default_volume > 0x7FFF )
- return -1;
-
- default_pan = default_pan * 64 / 32767;
- default_volume = default_volume * 64 / 32767;
- }
-
- /*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] )
- return -1;*/
-
- if ( ! length ) {
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return 0;
- }
-
- if ( flags & ~( 0x8000 | 0x80 | 0x20 | 0x10 | 0x08 | 0x04 ) )
- return -1;
-
- length_bytes = length << ( ( flags & 0x04 ) >> 2 );
-
- if ( length_bytes + header_length > len )
- return -1;
-
- sample->flags = 0;
-
- if ( flags & 0x80 ) sample->flags |= IT_SAMPLE_EXISTS;
- if ( flags & 0x04 ) sample->flags |= IT_SAMPLE_16BIT;
-
- sample->length = length;
- sample->loop_start = loop_start;
- sample->loop_end = loop_end;
- sample->C5_speed = sample_rate;
- sample->default_volume = default_volume;
- sample->default_pan = default_pan | ( ( flags & 0x20 ) << 2 );
- sample->filename[0] = 0;
- sample->global_volume = 64;
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- if ( flags & 0x08 )
- {
- if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) &&
- ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end))
- {
- sample->length = sample->loop_end;
- sample->flags |= IT_SAMPLE_LOOP;
- if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
- }
- }
-
- length_bytes = sample->length << ( ( flags & 0x04 ) >> 2 );
-
- sample->data = malloc( length_bytes );
- if ( ! sample->data )
- return -1;
-
- memcpy( sample->data, data + header_length, length_bytes );
-
- return 0;
-}
-
-static int it_riff_am_process_pattern( IT_PATTERN * pattern, const unsigned char * data, int len, int ver )
-{
- int nrows, row, pos;
- unsigned flags;
- IT_ENTRY * entry;
-
- nrows = data[0] + 1;
-
- pattern->n_rows = nrows;
-
- data += 1;
- len -= 1;
-
- pattern->n_entries = 0;
-
- row = 0;
- pos = 0;
-
- while ( (row < nrows) && (pos < len) ) {
- if ( ! data[ pos ] ) {
- ++ row;
- ++ pos;
- continue;
- }
-
- flags = data[ pos++ ] & 0xE0;
-
- if (flags) {
- ++ pattern->n_entries;
- if (flags & 0x80) pos += 2;
- if (flags & 0x40) pos += 2;
- if (flags & 0x20) pos ++;
- }
- }
-
- if ( ! pattern->n_entries ) return 0;
-
- pattern->n_entries += nrows;
-
- pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) );
- if ( ! pattern->entry ) return -1;
-
- entry = pattern->entry;
-
- row = 0;
- pos = 0;
-
- while ( ( row < nrows ) && ( pos < len ) )
- {
- if ( ! data[ pos ] )
- {
- IT_SET_END_ROW( entry );
- ++ entry;
- ++ row;
- ++ pos;
- continue;
- }
-
- flags = data[ pos++ ];
- entry->channel = flags & 0x1F;
- entry->mask = 0;
-
- if (flags & 0xE0)
- {
- if ( flags & 0x80 )
- {
- _dumb_it_xm_convert_effect( data[ pos + 1 ], data[ pos ], entry, 0 );
- pos += 2;
- }
-
- if ( flags & 0x40 )
- {
- if ( data[ pos ] )
- {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = data[ pos ];
- }
- if ( data[ pos + 1 ] )
- {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = data[ pos + 1 ] - 1;
- }
- pos += 2;
- }
-
- if ( flags & 0x20 )
- {
- entry->mask |= IT_ENTRY_VOLPAN;
- if ( ver == 0 ) entry->volpan = data[ pos ];
- else entry->volpan = data[ pos ] * 64 / 127;
- ++ pos;
- }
-
- if (entry->mask) entry++;
- }
- }
-
- while ( row < nrows )
- {
- IT_SET_END_ROW( entry );
- ++ entry;
- ++ row;
- }
-
- pattern->n_entries = entry - pattern->entry;
- if ( ! pattern->n_entries ) return -1;
-
- return 0;
-}
-
-static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( struct riff * stream )
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int n, o, found;
-
- unsigned char * ptr;
-
- if ( ! stream ) goto error;
-
- if ( stream->type != DUMB_ID( 'A', 'M', 'F', 'F' ) ) goto error;
-
- sigdata = malloc( sizeof( *sigdata ) );
- if ( ! sigdata ) goto error;
-
- sigdata->n_patterns = 0;
- sigdata->n_samples = 0;
- sigdata->name[0] = 0;
-
- found = 0;
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch( c->type )
- {
- case DUMB_ID( 'M', 'A', 'I', 'N' ):
- /* initialization data */
- if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd;
- found |= 1;
- break;
-
- case DUMB_ID( 'O', 'R', 'D', 'R' ):
- if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd;
- found |= 2;
- break;
-
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- ptr = ( unsigned char * ) c->data;
- if ( ptr[ 0 ] >= sigdata->n_patterns ) sigdata->n_patterns = ptr[ 0 ] + 1;
- o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
- if ( o + 5 > c->size ) goto error_sd;
- break;
-
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- {
- if ( c->size < 0xE1 ) goto error;
- ptr = ( unsigned char * ) c->data;
- if ( ptr[ 1 ] >= sigdata->n_samples ) sigdata->n_samples = ptr[ 1 ] + 1;
- if ( c->size >= 0x121 && ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' &&
- ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' ) )
- {
- unsigned size = ptr[ 0xE5 ] | ( ptr[ 0xE6 ] << 8 ) | ( ptr[ 0xE7 ] << 16 ) | ( ptr[ 0xE8 ] << 24 );
- if ( size + 0xE1 + 8 > c->size ) goto error;
- }
- }
- break;
- }
- }
-
- if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd;
-
- if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- sigdata->n_instruments = 0;
- sigdata->n_orders = 0;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'M', 'A', 'I', 'N' ):
- ptr = ( unsigned char * ) c->data;
- memcpy( sigdata->name, c->data, 64 );
- sigdata->name[ 64 ] = 0;
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
- if ( ! ( ptr[ 0x40 ] & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES;
- if ( ( ptr[ 0x40 ] & ~3 ) || ! ( ptr[ 0x40 ] & 2 ) ) goto error_usd; // unknown flags
- sigdata->n_pchannels = ptr[ 0x41 ];
- sigdata->speed = ptr[ 0x42 ];
- sigdata->tempo = ptr[ 0x43 ];
-
- sigdata->global_volume = ptr[ 0x48 ];
-
- if ( c->size < 0x48 + sigdata->n_pchannels ) goto error_usd;
-
- for ( o = 0; o < sigdata->n_pchannels; ++o )
- {
- sigdata->channel_pan[ o ] = ptr[ 0x49 + o ];
- if ( ptr[ 0x49 + o ] >= 128 )
- {
- sigdata->channel_volume[ o ] = 0;
- }
- }
- break;
- }
- }
-
- sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
- if ( ! sigdata->pattern ) goto error_usd;
- for ( n = 0; n < sigdata->n_patterns; ++n )
- sigdata->pattern[ n ].entry = NULL;
-
- sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
- if ( ! sigdata->sample ) goto error_usd;
- for ( n = 0; n < sigdata->n_samples; ++n )
- {
- IT_SAMPLE * sample = sigdata->sample + n;
- sample->data = NULL;
- sample->flags = 0;
- sample->name[ 0 ] = 0;
- }
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'O', 'R', 'D', 'R' ):
- ptr = ( unsigned char * ) c->data;
- sigdata->n_orders = ptr[ 0 ] + 1;
- if ( sigdata->n_orders + 1 > c->size ) goto error_usd;
- sigdata->order = malloc( sigdata->n_orders );
- if ( ! sigdata->order ) goto error_usd;
- memcpy( sigdata->order, ptr + 1, sigdata->n_orders );
- break;
-
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- ptr = ( unsigned char * ) c->data;
- o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
- if ( it_riff_am_process_pattern( sigdata->pattern + ptr[ 0 ], ptr + 5, o, 0 ) ) goto error_usd;
- break;
-
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- {
- IT_SAMPLE * sample;
- ptr = ( unsigned char * ) c->data;
- sample = sigdata->sample + ptr[ 1 ];
- if ( c->size >= 0x121 && ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' &&
- ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' ) )
- {
- unsigned size = ptr[ 0xE5 ] | ( ptr[ 0xE6 ] << 8 ) | ( ptr[ 0xE7 ] << 16 ) | ( ptr[ 0xE8 ] << 24 );
- if ( it_riff_am_process_sample( sample, ptr + 0xE1 + 8, size, 0 ) ) goto error_usd;
- }
- else
- {
- memcpy( sample->name, ptr + 2, 28 );
- sample->name[ 28 ] = 0;
- }
- }
- break;
- }
- }
-
- _dumb_it_fix_invalid_orders( sigdata );
-
- return sigdata;
-
-error_usd:
- _dumb_it_unload_sigdata( sigdata );
- goto error;
-error_sd:
- free( sigdata );
-error:
- return NULL;
-}
-
-static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream )
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int n, o, p, found;
-
- unsigned char * ptr;
-
- if ( ! stream ) goto error;
-
- if ( stream->type != DUMB_ID( 'A', 'M', ' ', ' ' ) ) goto error;
-
- sigdata = malloc(sizeof(*sigdata));
- if ( ! sigdata ) goto error;
-
- sigdata->n_patterns = 0;
- sigdata->n_samples = 0;
- sigdata->name[0] = 0;
-
- found = 0;
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch( c->type )
- {
- case DUMB_ID( 'I' ,'N' ,'I' ,'T' ):
- /* initialization data */
- if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd;
- found |= 1;
- break;
-
- case DUMB_ID( 'O', 'R', 'D', 'R' ):
- if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd;
- found |= 2;
- break;
-
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- ptr = ( unsigned char * ) c->data;
- if ( ptr[ 0 ] >= sigdata->n_patterns ) sigdata->n_patterns = ptr[ 0 ] + 1;
- o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
- if ( o + 5 > c->size ) goto error_sd;
- break;
-
- case DUMB_ID( 'R', 'I', 'F', 'F' ):
- {
- struct riff * str = ( struct riff * ) c->data;
- switch ( str->type )
- {
- case DUMB_ID( 'A', 'I', ' ', ' ' ):
- for ( o = 0; o < str->chunk_count; ++o )
- {
- struct riff_chunk * chk = str->chunks + o;
- switch( chk->type )
- {
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- {
- struct riff * temp;
- unsigned size;
- unsigned sample_found;
- ptr = ( unsigned char * ) chk->data;
- size = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) | ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 );
- if ( size < 0x142 ) goto error;
- sample_found = 0;
- if ( ptr[ 5 ] >= sigdata->n_samples ) sigdata->n_samples = ptr[ 5 ] + 1;
- temp = riff_parse( ptr + 4 + size, chk->size - size - 4, 1 );
- if ( temp )
- {
- if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) )
- {
- for ( p = 0; p < temp->chunk_count; ++p )
- {
- if ( temp->chunks[ p ].type == DUMB_ID( 'S', 'A', 'M', 'P' ) )
- {
- if ( sample_found )
- {
- riff_free( temp );
- goto error;
- }
- sample_found = 1;
- }
- }
- }
- riff_free( temp );
- }
- }
- }
- }
- }
- }
- break;
- }
- }
-
- if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd;
-
- if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- sigdata->n_instruments = 0;
- sigdata->n_orders = 0;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'I', 'N', 'I', 'T' ):
- ptr = ( unsigned char * ) c->data;
- memcpy( sigdata->name, c->data, 64 );
- sigdata->name[ 64 ] = 0;
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
- if ( ! ( ptr[ 0x40 ] & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES;
- if ( ( ptr[ 0x40 ] & ~3 ) || ! ( ptr[ 0x40 ] & 2 ) ) goto error_usd; // unknown flags
- sigdata->n_pchannels = ptr[ 0x41 ];
- sigdata->speed = ptr[ 0x42 ];
- sigdata->tempo = ptr[ 0x43 ];
-
- sigdata->global_volume = ptr[ 0x48 ];
-
- if ( c->size < 0x48 + sigdata->n_pchannels ) goto error_usd;
-
- for ( o = 0; o < sigdata->n_pchannels; ++o )
- {
- if ( ptr[ 0x49 + o ] <= 128 )
- {
- sigdata->channel_pan[ o ] = ptr[ 0x49 + o ] / 2;
- }
- else
- {
- sigdata->channel_volume[ o ] = 0;
- }
- }
- break;
- }
- }
-
- sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
- if ( ! sigdata->pattern ) goto error_usd;
- for ( n = 0; n < sigdata->n_patterns; ++n )
- sigdata->pattern[ n ].entry = NULL;
-
- sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
- if ( ! sigdata->sample ) goto error_usd;
- for ( n = 0; n < sigdata->n_samples; ++n )
- {
- IT_SAMPLE * sample = sigdata->sample + n;
- sample->data = NULL;
- sample->flags = 0;
- sample->name[ 0 ] = 0;
- }
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'O', 'R', 'D', 'R' ):
- ptr = ( unsigned char * ) c->data;
- sigdata->n_orders = ptr[ 0 ] + 1;
- if ( sigdata->n_orders + 1 > c->size ) goto error_usd;
- sigdata->order = malloc( sigdata->n_orders );
- if ( ! sigdata->order ) goto error_usd;
- memcpy( sigdata->order, ptr + 1, sigdata->n_orders );
- break;
-
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- ptr = ( unsigned char * ) c->data;
- o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 );
- if ( it_riff_am_process_pattern( sigdata->pattern + ptr[ 0 ], ptr + 5, o, 1 ) ) goto error_usd;
- break;
-
- case DUMB_ID( 'R', 'I', 'F', 'F' ):
- {
- struct riff * str = ( struct riff * ) c->data;
- switch ( str->type )
- {
- case DUMB_ID('A', 'I', ' ', ' '):
- for ( o = 0; o < str->chunk_count; ++o )
- {
- struct riff_chunk * chk = str->chunks + o;
- switch( chk->type )
- {
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- {
- struct riff * temp;
- unsigned size;
- unsigned sample_found;
- IT_SAMPLE * sample;
- ptr = ( unsigned char * ) chk->data;
- size = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) | ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 );
- temp = riff_parse( ptr + 4 + size, chk->size - size - 4, 1 );
- sample_found = 0;
- sample = sigdata->sample + ptr[ 5 ];
- if ( temp )
- {
- if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) )
- {
- for ( p = 0; p < temp->chunk_count; ++p )
- {
- struct riff_chunk * c = temp->chunks + p;
- if ( c->type == DUMB_ID( 'S', 'A', 'M', 'P' ) )
- {
- if ( sample_found )
- {
- riff_free( temp );
- goto error_usd;
- }
- if ( it_riff_am_process_sample( sigdata->sample + ptr[ 5 ], ( unsigned char * ) c->data, c->size, 1 ) )
- {
- riff_free( temp );
- goto error_usd;
- }
- sample_found = 1;
- }
- }
- }
- riff_free( temp );
- }
- if ( ! sample_found )
- {
- memcpy( sample->name, ptr + 6, 32 );
- sample->name[ 32 ] = 0;
- }
- }
- }
- }
- }
- }
- break;
- }
- }
-
- _dumb_it_fix_invalid_orders( sigdata );
-
- return sigdata;
-
-error_usd:
- _dumb_it_unload_sigdata( sigdata );
- goto error;
-error_sd:
- free( sigdata );
-error:
- return NULL;
-}
-
-DUH *dumb_read_riff_amff( struct riff * stream )
-{
- sigdata_t *sigdata;
- long length;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_riff_amff_load_sigdata( stream );
-
- if (!sigdata)
- return NULL;
-
- length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "RIFF AMFF";
- return make_duh( length, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
- }
-}
-
-DUH *dumb_read_riff_am( struct riff * stream )
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_riff_am_load_sigdata( stream );
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "RIFF AM";
- return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readam.c - Code to read a RIFF AM module / / \ \ + * from a parsed RIFF structure. | < / \_ + * | \/ /\ / + * By Chris Moeller. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" +#include "internal/it.h" +#include "internal/riff.h" + +static int it_riff_am_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len, int ver ) +{ + int header_length; + int default_pan; + int default_volume; + int flags; + int length; + int length_bytes; + int loop_start; + int loop_end; + int sample_rate; + + if ( ver == 0 ) + { + if ( len < 0x38 ) + return -1; + + header_length = 0x38; + + memcpy( sample->name, data, 28 ); + sample->name[ 28 ] = 0; + + default_pan = data[ 0x1C ]; + default_volume = data[ 0x1D ]; + flags = data[ 0x1E ] | ( data[ 0x1F ] << 8 ); + length = data[ 0x20 ] | ( data[ 0x21 ] << 8 ) | ( data[ 0x22 ] << 16 ) | ( data[ 0x23 ] << 24 ); + loop_start = data[ 0x24 ] | ( data[ 0x25 ] << 8 ) | ( data[ 0x26 ] << 16 ) | ( data[ 0x27 ] << 24 ); + loop_end = data[ 0x28 ] | ( data[ 0x29 ] << 8 ) | ( data[ 0x2A ] << 16 ) | ( data[ 0x2B ] << 24 ); + sample_rate = data[ 0x2C ] | ( data[ 0x2D ] << 8 ) | ( data[ 0x2E ] << 16 ) | ( data[ 0x2F ] << 24 ); + } + else + { + if (len < 4) return -1; + + header_length = data[ 0 ] | ( data[ 1 ] << 8 ) | ( data[ 2 ] << 16 ) | ( data[ 3 ] << 24 ); + if ( header_length < 0x40 ) + return -1; + if ( header_length + 4 > len ) + return -1; + + data += 4; + len -= 4; + + memcpy( sample->name, data, 32 ); + sample->name[ 32 ] = 0; + + default_pan = data[ 0x20 ] | ( data[ 0x21 ] << 8 ); + default_volume = data[ 0x22 ] | ( data[ 0x23 ] << 8 ); + flags = data[ 0x24 ] | ( data[ 0x25 ] << 8 ); /* | ( data[ 0x26 ] << 16 ) | ( data[ 0x27 ] << 24 );*/ + length = data[ 0x28 ] | ( data[ 0x29 ] << 8 ) | ( data[ 0x2A ] << 16 ) | ( data[ 0x2B ] << 24 ); + loop_start = data[ 0x2C ] | ( data[ 0x2D ] << 8 ) | ( data[ 0x2E ] << 16 ) | ( data[ 0x2F ] << 24 ); + loop_end = data[ 0x30 ] | ( data[ 0x31 ] << 8 ) | ( data[ 0x32 ] << 16 ) | ( data[ 0x33 ] << 24 ); + sample_rate = data[ 0x34 ] | ( data[ 0x35 ] << 8 ) | ( data[ 0x36 ] << 16 ) | ( data[ 0x37 ] << 24 ); + + if ( default_pan > 0x7FFF || default_volume > 0x7FFF ) + return -1; + + default_pan = default_pan * 64 / 32767; + default_volume = default_volume * 64 / 32767; + } + + /*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] ) + return -1;*/ + + if ( ! length ) { + sample->flags &= ~IT_SAMPLE_EXISTS; + return 0; + } + + if ( flags & ~( 0x8000 | 0x80 | 0x20 | 0x10 | 0x08 | 0x04 ) ) + return -1; + + length_bytes = length << ( ( flags & 0x04 ) >> 2 ); + + if ( length_bytes + header_length > len ) + return -1; + + sample->flags = 0; + + if ( flags & 0x80 ) sample->flags |= IT_SAMPLE_EXISTS; + if ( flags & 0x04 ) sample->flags |= IT_SAMPLE_16BIT; + + sample->length = length; + sample->loop_start = loop_start; + sample->loop_end = loop_end; + sample->C5_speed = sample_rate; + sample->default_volume = default_volume; + sample->default_pan = default_pan | ( ( flags & 0x20 ) << 2 ); + sample->filename[0] = 0; + sample->global_volume = 64; + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = IT_VIBRATO_SINE; + sample->finetune = 0; + sample->max_resampling_quality = -1; + + if ( flags & 0x08 ) + { + if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) && + ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end)) + { + sample->length = sample->loop_end; + sample->flags |= IT_SAMPLE_LOOP; + if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP; + } + } + + length_bytes = sample->length << ( ( flags & 0x04 ) >> 2 ); + + sample->data = malloc( length_bytes ); + if ( ! sample->data ) + return -1; + + memcpy( sample->data, data + header_length, length_bytes ); + + return 0; +} + +static int it_riff_am_process_pattern( IT_PATTERN * pattern, const unsigned char * data, int len, int ver ) +{ + int nrows, row, pos; + unsigned flags; + IT_ENTRY * entry; + + nrows = data[0] + 1; + + pattern->n_rows = nrows; + + data += 1; + len -= 1; + + pattern->n_entries = 0; + + row = 0; + pos = 0; + + while ( (row < nrows) && (pos < len) ) { + if ( ! data[ pos ] ) { + ++ row; + ++ pos; + continue; + } + + flags = data[ pos++ ] & 0xE0; + + if (flags) { + ++ pattern->n_entries; + if (flags & 0x80) pos += 2; + if (flags & 0x40) pos += 2; + if (flags & 0x20) pos ++; + } + } + + if ( ! pattern->n_entries ) return 0; + + pattern->n_entries += nrows; + + pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) ); + if ( ! pattern->entry ) return -1; + + entry = pattern->entry; + + row = 0; + pos = 0; + + while ( ( row < nrows ) && ( pos < len ) ) + { + if ( ! data[ pos ] ) + { + IT_SET_END_ROW( entry ); + ++ entry; + ++ row; + ++ pos; + continue; + } + + flags = data[ pos++ ]; + entry->channel = flags & 0x1F; + entry->mask = 0; + + if (flags & 0xE0) + { + if ( flags & 0x80 ) + { + _dumb_it_xm_convert_effect( data[ pos + 1 ], data[ pos ], entry, 0 ); + pos += 2; + } + + if ( flags & 0x40 ) + { + if ( data[ pos ] ) + { + entry->mask |= IT_ENTRY_INSTRUMENT; + entry->instrument = data[ pos ]; + } + if ( data[ pos + 1 ] ) + { + entry->mask |= IT_ENTRY_NOTE; + entry->note = data[ pos + 1 ] - 1; + } + pos += 2; + } + + if ( flags & 0x20 ) + { + entry->mask |= IT_ENTRY_VOLPAN; + if ( ver == 0 ) entry->volpan = data[ pos ]; + else entry->volpan = data[ pos ] * 64 / 127; + ++ pos; + } + + if (entry->mask) entry++; + } + } + + while ( row < nrows ) + { + IT_SET_END_ROW( entry ); + ++ entry; + ++ row; + } + + pattern->n_entries = entry - pattern->entry; + if ( ! pattern->n_entries ) return -1; + + return 0; +} + +static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( struct riff * stream ) +{ + DUMB_IT_SIGDATA *sigdata; + + int n, o, found; + + unsigned char * ptr; + + if ( ! stream ) goto error; + + if ( stream->type != DUMB_ID( 'A', 'M', 'F', 'F' ) ) goto error; + + sigdata = malloc( sizeof( *sigdata ) ); + if ( ! sigdata ) goto error; + + sigdata->n_patterns = 0; + sigdata->n_samples = 0; + sigdata->name[0] = 0; + + found = 0; + + for ( n = 0; n < stream->chunk_count; ++n ) + { + struct riff_chunk * c = stream->chunks + n; + switch( c->type ) + { + case DUMB_ID( 'M', 'A', 'I', 'N' ): + /* initialization data */ + if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd; + found |= 1; + break; + + case DUMB_ID( 'O', 'R', 'D', 'R' ): + if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd; + found |= 2; + break; + + case DUMB_ID( 'P', 'A', 'T', 'T' ): + ptr = ( unsigned char * ) c->data; + if ( ptr[ 0 ] >= sigdata->n_patterns ) sigdata->n_patterns = ptr[ 0 ] + 1; + o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 ); + if ( o + 5 > c->size ) goto error_sd; + break; + + case DUMB_ID( 'I', 'N', 'S', 'T' ): + { + if ( c->size < 0xE1 ) goto error; + ptr = ( unsigned char * ) c->data; + if ( ptr[ 1 ] >= sigdata->n_samples ) sigdata->n_samples = ptr[ 1 ] + 1; + if ( c->size >= 0x121 && ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' && + ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' ) ) + { + unsigned size = ptr[ 0xE5 ] | ( ptr[ 0xE6 ] << 8 ) | ( ptr[ 0xE7 ] << 16 ) | ( ptr[ 0xE8 ] << 24 ); + if ( size + 0xE1 + 8 > c->size ) goto error; + } + } + break; + } + } + + if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd; + + if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd; + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->sample = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->mixing_volume = 48; + sigdata->pan_separation = 128; + + sigdata->n_instruments = 0; + sigdata->n_orders = 0; + + memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); + + for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { + sigdata->channel_pan[n ] = 16; + sigdata->channel_pan[n+1] = 48; + sigdata->channel_pan[n+2] = 48; + sigdata->channel_pan[n+3] = 16; + } + + for ( n = 0; n < stream->chunk_count; ++n ) + { + struct riff_chunk * c = stream->chunks + n; + switch ( c->type ) + { + case DUMB_ID( 'M', 'A', 'I', 'N' ): + ptr = ( unsigned char * ) c->data; + memcpy( sigdata->name, c->data, 64 ); + sigdata->name[ 64 ] = 0; + sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M; + if ( ! ( ptr[ 0x40 ] & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES; + if ( ( ptr[ 0x40 ] & ~3 ) || ! ( ptr[ 0x40 ] & 2 ) ) goto error_usd; // unknown flags + sigdata->n_pchannels = ptr[ 0x41 ]; + sigdata->speed = ptr[ 0x42 ]; + sigdata->tempo = ptr[ 0x43 ]; + + sigdata->global_volume = ptr[ 0x48 ]; + + if ( c->size < 0x48 + sigdata->n_pchannels ) goto error_usd; + + for ( o = 0; o < sigdata->n_pchannels; ++o ) + { + sigdata->channel_pan[ o ] = ptr[ 0x49 + o ]; + if ( ptr[ 0x49 + o ] >= 128 ) + { + sigdata->channel_volume[ o ] = 0; + } + } + break; + } + } + + sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) ); + if ( ! sigdata->pattern ) goto error_usd; + for ( n = 0; n < sigdata->n_patterns; ++n ) + sigdata->pattern[ n ].entry = NULL; + + sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) ); + if ( ! sigdata->sample ) goto error_usd; + for ( n = 0; n < sigdata->n_samples; ++n ) + { + IT_SAMPLE * sample = sigdata->sample + n; + sample->data = NULL; + sample->flags = 0; + sample->name[ 0 ] = 0; + } + + for ( n = 0; n < stream->chunk_count; ++n ) + { + struct riff_chunk * c = stream->chunks + n; + switch ( c->type ) + { + case DUMB_ID( 'O', 'R', 'D', 'R' ): + ptr = ( unsigned char * ) c->data; + sigdata->n_orders = ptr[ 0 ] + 1; + if ( sigdata->n_orders + 1 > c->size ) goto error_usd; + sigdata->order = malloc( sigdata->n_orders ); + if ( ! sigdata->order ) goto error_usd; + memcpy( sigdata->order, ptr + 1, sigdata->n_orders ); + break; + + case DUMB_ID( 'P', 'A', 'T', 'T' ): + ptr = ( unsigned char * ) c->data; + o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 ); + if ( it_riff_am_process_pattern( sigdata->pattern + ptr[ 0 ], ptr + 5, o, 0 ) ) goto error_usd; + break; + + case DUMB_ID( 'I', 'N', 'S', 'T' ): + { + IT_SAMPLE * sample; + ptr = ( unsigned char * ) c->data; + sample = sigdata->sample + ptr[ 1 ]; + if ( c->size >= 0x121 && ( ptr[ 0xE1 ] == 'S' && ptr[ 0xE2 ] == 'A' && + ptr[ 0xE3 ] == 'M' && ptr[ 0xE4 ] == 'P' ) ) + { + unsigned size = ptr[ 0xE5 ] | ( ptr[ 0xE6 ] << 8 ) | ( ptr[ 0xE7 ] << 16 ) | ( ptr[ 0xE8 ] << 24 ); + if ( it_riff_am_process_sample( sample, ptr + 0xE1 + 8, size, 0 ) ) goto error_usd; + } + else + { + memcpy( sample->name, ptr + 2, 28 ); + sample->name[ 28 ] = 0; + } + } + break; + } + } + + _dumb_it_fix_invalid_orders( sigdata ); + + return sigdata; + +error_usd: + _dumb_it_unload_sigdata( sigdata ); + goto error; +error_sd: + free( sigdata ); +error: + return NULL; +} + +static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( struct riff * stream ) +{ + DUMB_IT_SIGDATA *sigdata; + + int n, o, p, found; + + unsigned char * ptr; + + if ( ! stream ) goto error; + + if ( stream->type != DUMB_ID( 'A', 'M', ' ', ' ' ) ) goto error; + + sigdata = malloc(sizeof(*sigdata)); + if ( ! sigdata ) goto error; + + sigdata->n_patterns = 0; + sigdata->n_samples = 0; + sigdata->name[0] = 0; + + found = 0; + + for ( n = 0; n < stream->chunk_count; ++n ) + { + struct riff_chunk * c = stream->chunks + n; + switch( c->type ) + { + case DUMB_ID( 'I' ,'N' ,'I' ,'T' ): + /* initialization data */ + if ( ( found & 1 ) || ( c->size < 0x48 ) ) goto error_sd; + found |= 1; + break; + + case DUMB_ID( 'O', 'R', 'D', 'R' ): + if ( ( found & 2 ) || ( c->size < 1 ) ) goto error_sd; + found |= 2; + break; + + case DUMB_ID( 'P', 'A', 'T', 'T' ): + ptr = ( unsigned char * ) c->data; + if ( ptr[ 0 ] >= sigdata->n_patterns ) sigdata->n_patterns = ptr[ 0 ] + 1; + o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 ); + if ( o + 5 > c->size ) goto error_sd; + break; + + case DUMB_ID( 'R', 'I', 'F', 'F' ): + { + struct riff * str = ( struct riff * ) c->data; + switch ( str->type ) + { + case DUMB_ID( 'A', 'I', ' ', ' ' ): + for ( o = 0; o < str->chunk_count; ++o ) + { + struct riff_chunk * chk = str->chunks + o; + switch( chk->type ) + { + case DUMB_ID( 'I', 'N', 'S', 'T' ): + { + struct riff * temp; + unsigned size; + unsigned sample_found; + ptr = ( unsigned char * ) chk->data; + size = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) | ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 ); + if ( size < 0x142 ) goto error; + sample_found = 0; + if ( ptr[ 5 ] >= sigdata->n_samples ) sigdata->n_samples = ptr[ 5 ] + 1; + temp = riff_parse( ptr + 4 + size, chk->size - size - 4, 1 ); + if ( temp ) + { + if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) ) + { + for ( p = 0; p < temp->chunk_count; ++p ) + { + if ( temp->chunks[ p ].type == DUMB_ID( 'S', 'A', 'M', 'P' ) ) + { + if ( sample_found ) + { + riff_free( temp ); + goto error; + } + sample_found = 1; + } + } + } + riff_free( temp ); + } + } + } + } + } + } + break; + } + } + + if ( found != 3 || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd; + + if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd; + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->sample = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->mixing_volume = 48; + sigdata->pan_separation = 128; + + sigdata->n_instruments = 0; + sigdata->n_orders = 0; + + memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); + + for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { + sigdata->channel_pan[n ] = 16; + sigdata->channel_pan[n+1] = 48; + sigdata->channel_pan[n+2] = 48; + sigdata->channel_pan[n+3] = 16; + } + + for ( n = 0; n < stream->chunk_count; ++n ) + { + struct riff_chunk * c = stream->chunks + n; + switch ( c->type ) + { + case DUMB_ID( 'I', 'N', 'I', 'T' ): + ptr = ( unsigned char * ) c->data; + memcpy( sigdata->name, c->data, 64 ); + sigdata->name[ 64 ] = 0; + sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M; + if ( ! ( ptr[ 0x40 ] & 1 ) ) sigdata->flags |= IT_LINEAR_SLIDES; + if ( ( ptr[ 0x40 ] & ~3 ) || ! ( ptr[ 0x40 ] & 2 ) ) goto error_usd; // unknown flags + sigdata->n_pchannels = ptr[ 0x41 ]; + sigdata->speed = ptr[ 0x42 ]; + sigdata->tempo = ptr[ 0x43 ]; + + sigdata->global_volume = ptr[ 0x48 ]; + + if ( c->size < 0x48 + sigdata->n_pchannels ) goto error_usd; + + for ( o = 0; o < sigdata->n_pchannels; ++o ) + { + if ( ptr[ 0x49 + o ] <= 128 ) + { + sigdata->channel_pan[ o ] = ptr[ 0x49 + o ] / 2; + } + else + { + sigdata->channel_volume[ o ] = 0; + } + } + break; + } + } + + sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) ); + if ( ! sigdata->pattern ) goto error_usd; + for ( n = 0; n < sigdata->n_patterns; ++n ) + sigdata->pattern[ n ].entry = NULL; + + sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) ); + if ( ! sigdata->sample ) goto error_usd; + for ( n = 0; n < sigdata->n_samples; ++n ) + { + IT_SAMPLE * sample = sigdata->sample + n; + sample->data = NULL; + sample->flags = 0; + sample->name[ 0 ] = 0; + } + + for ( n = 0; n < stream->chunk_count; ++n ) + { + struct riff_chunk * c = stream->chunks + n; + switch ( c->type ) + { + case DUMB_ID( 'O', 'R', 'D', 'R' ): + ptr = ( unsigned char * ) c->data; + sigdata->n_orders = ptr[ 0 ] + 1; + if ( sigdata->n_orders + 1 > c->size ) goto error_usd; + sigdata->order = malloc( sigdata->n_orders ); + if ( ! sigdata->order ) goto error_usd; + memcpy( sigdata->order, ptr + 1, sigdata->n_orders ); + break; + + case DUMB_ID( 'P', 'A', 'T', 'T' ): + ptr = ( unsigned char * ) c->data; + o = ptr[ 1 ] | ( ptr[ 2 ] << 8 ) | ( ptr[ 3 ] << 16 ) | ( ptr[ 4 ] << 24 ); + if ( it_riff_am_process_pattern( sigdata->pattern + ptr[ 0 ], ptr + 5, o, 1 ) ) goto error_usd; + break; + + case DUMB_ID( 'R', 'I', 'F', 'F' ): + { + struct riff * str = ( struct riff * ) c->data; + switch ( str->type ) + { + case DUMB_ID('A', 'I', ' ', ' '): + for ( o = 0; o < str->chunk_count; ++o ) + { + struct riff_chunk * chk = str->chunks + o; + switch( chk->type ) + { + case DUMB_ID( 'I', 'N', 'S', 'T' ): + { + struct riff * temp; + unsigned size; + unsigned sample_found; + IT_SAMPLE * sample; + ptr = ( unsigned char * ) chk->data; + size = ptr[ 0 ] | ( ptr[ 1 ] << 8 ) | ( ptr[ 2 ] << 16 ) | ( ptr[ 3 ] << 24 ); + temp = riff_parse( ptr + 4 + size, chk->size - size - 4, 1 ); + sample_found = 0; + sample = sigdata->sample + ptr[ 5 ]; + if ( temp ) + { + if ( temp->type == DUMB_ID( 'A', 'S', ' ', ' ' ) ) + { + for ( p = 0; p < temp->chunk_count; ++p ) + { + struct riff_chunk * c = temp->chunks + p; + if ( c->type == DUMB_ID( 'S', 'A', 'M', 'P' ) ) + { + if ( sample_found ) + { + riff_free( temp ); + goto error_usd; + } + if ( it_riff_am_process_sample( sigdata->sample + ptr[ 5 ], ( unsigned char * ) c->data, c->size, 1 ) ) + { + riff_free( temp ); + goto error_usd; + } + sample_found = 1; + } + } + } + riff_free( temp ); + } + if ( ! sample_found ) + { + memcpy( sample->name, ptr + 6, 32 ); + sample->name[ 32 ] = 0; + } + } + } + } + } + } + break; + } + } + + _dumb_it_fix_invalid_orders( sigdata ); + + return sigdata; + +error_usd: + _dumb_it_unload_sigdata( sigdata ); + goto error; +error_sd: + free( sigdata ); +error: + return NULL; +} + +DUH *dumb_read_riff_amff( struct riff * stream ) +{ + sigdata_t *sigdata; + long length; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_riff_amff_load_sigdata( stream ); + + if (!sigdata) + return NULL; + + length = 0;/*_dumb_it_build_checkpoints(sigdata, 0);*/ + + { + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = "RIFF AMFF"; + return make_duh( length, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata ); + } +} + +DUH *dumb_read_riff_am( struct riff * stream ) +{ + sigdata_t *sigdata; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_riff_am_load_sigdata( stream ); + + if (!sigdata) + return NULL; + + { + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = "RIFF AM"; + return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata ); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/readasy.c b/plugins/dumb/dumb-kode54/src/it/readasy.c index 4c1c09f8..2969eb6f 100644 --- a/plugins/dumb/dumb-kode54/src/it/readasy.c +++ b/plugins/dumb/dumb-kode54/src/it/readasy.c @@ -1,331 +1,331 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readasy.c - Code to read an ASYLUM Music Format / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer )
-{
- int pos;
- int channel;
- int row;
- IT_ENTRY *entry;
-
- pattern->n_rows = 64;
-
- if ( dumbfile_getnc( buffer, 64 * 8 * 4, f ) != 64 * 8 * 4 )
- return -1;
-
- /* compute number of entries */
- pattern->n_entries = 64; /* Account for the row end markers */
- pos = 0;
- for ( row = 0; row < 64; ++row ) {
- for ( channel = 0; channel < 8; ++channel ) {
- if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] )
- ++pattern->n_entries;
- pos += 4;
- }
- }
-
- pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) );
- if ( !pattern->entry )
- return -1;
-
- entry = pattern->entry;
- pos = 0;
- for ( row = 0; row < 64; ++row ) {
- for ( channel = 0; channel < 8; ++channel ) {
- if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) {
- entry->channel = channel;
- entry->mask = 0;
-
- if ( buffer[ pos + 0 ] && buffer[ pos + 0 ] < 96 ) {
- entry->note = buffer[ pos + 0 ];
- entry->mask |= IT_ENTRY_NOTE;
- }
-
- if ( buffer[ pos + 1 ] && buffer[ pos + 1 ] <= 64 ) {
- entry->instrument = buffer[ pos + 1 ];
- entry->mask |= IT_ENTRY_INSTRUMENT;
- }
-
- _dumb_it_xm_convert_effect( buffer[ pos + 2 ] & 0x0F, buffer[ pos + 3 ], entry, 1 );
-
- if ( entry->mask ) ++entry;
- }
- pos += 4;
- }
- IT_SET_END_ROW( entry );
- ++entry;
- }
-
- pattern->n_entries = entry - pattern->entry;
-
- return 0;
-}
-
-
-
-static int it_asy_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f )
-{
- int finetune;
-
-/**
- 21 22 Chars Sample 1 name. If the name is not a full
- 22 chars in length, it will be null
- terminated.
-
-If
-the sample name begins with a '#' character (ASCII $23 (35)) then this is
-assumed not to be an instrument name, and is probably a message.
-*/
- dumbfile_getnc( sample->name, 22, f );
- sample->name[22] = 0;
-
- sample->filename[0] = 0;
-
-/** Each finetune step changes the note 1/8th of a semitone. */
- finetune = ( signed char ) ( dumbfile_getc( f ) << 4 ) >> 4; /* signed nibble */
- sample->default_volume = dumbfile_getc( f ); // Should we be setting global_volume to this instead?
- sample->global_volume = 64;
- if ( sample->default_volume > 64 ) sample->default_volume = 64;
- dumbfile_skip( f, 1 ); /* XXX unknown */
- sample->length = dumbfile_igetl( f );
- sample->loop_start = dumbfile_igetl( f );
- sample->loop_end = sample->loop_start + dumbfile_igetl( f );
-
- if ( sample->length <= 0 ) {
- sample->flags = 0;
- return 0;
- }
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- sample->default_pan = 0;
- sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//( long )( 16726.0 * pow( DUMB_PITCH_BASE, finetune * 32 ) );
- sample->finetune = finetune * 32;
- // the above line might be wrong
-
- if ( ( sample->loop_end - sample->loop_start > 2 ) && ( sample->loop_end <= sample->length ) )
- sample->flags |= IT_SAMPLE_LOOP;
-
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = 0; // do we have to set _all_ these?
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-
-
-static int it_asy_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f )
-{
- long truncated_size;
-
- /* let's get rid of the sample data coming after the end of the loop */
- if ( ( sample->flags & IT_SAMPLE_LOOP ) && sample->loop_end < sample->length ) {
- truncated_size = sample->length - sample->loop_end;
- sample->length = sample->loop_end;
- } else {
- truncated_size = 0;
- }
-
- sample->data = malloc( sample->length );
-
- if ( !sample->data )
- return -1;
-
- if ( sample->length )
- dumbfile_getnc( sample->data, sample->length, f );
-
- dumbfile_skip( f, truncated_size );
-
- return dumbfile_error( f );
-}
-
-
-
-static DUMB_IT_SIGDATA *it_asy_load_sigdata(DUMBFILE *f)
-{
- DUMB_IT_SIGDATA *sigdata;
- int i;
-
- static const char sig_part[] = "ASYLUM Music Format";
- static const char sig_rest[] = " V1.0"; /* whee, string space optimization with format type below */
-
- char signature [32];
-
- if ( dumbfile_getnc( signature, 32, f ) != 32 ||
- memcmp( signature, sig_part, 19 ) ||
- memcmp( signature + 19, sig_rest, 5 ) ) {
- return NULL;
- }
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) {
- return NULL;
- }
-
- sigdata->speed = dumbfile_getc( f ); /* XXX seems to fit the files I have */
- sigdata->tempo = dumbfile_getc( f ); /* ditto */
- sigdata->n_samples = dumbfile_getc( f ); /* ditto */
- sigdata->n_patterns = dumbfile_getc( f );
- sigdata->n_orders = dumbfile_getc( f );
- sigdata->restart_position = dumbfile_getc( f );
-
- if ( dumbfile_error( f ) || !sigdata->n_samples || sigdata->n_samples > 64 || !sigdata->n_patterns ||
- !sigdata->n_orders ) {
- free( sigdata );
- return NULL;
- }
-
- if ( sigdata->restart_position > sigdata->n_orders ) /* XXX */
- sigdata->restart_position = 0;
-
- sigdata->order = malloc( sigdata->n_orders );
- if ( !sigdata->order ) {
- free( sigdata );
- return NULL;
- }
-
- if ( dumbfile_getnc( sigdata->order, sigdata->n_orders, f ) != sigdata->n_orders ||
- dumbfile_skip( f, 256 - sigdata->n_orders ) ) {
- free( sigdata->order );
- free( sigdata );
- return NULL;
- }
-
- sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
- if ( !sigdata->sample ) {
- free( sigdata->order );
- free( sigdata );
- return NULL;
- }
-
- sigdata->song_message = NULL;
- sigdata->instrument = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
-
- for ( i = 0; i < sigdata->n_samples; ++i )
- sigdata->sample[i].data = NULL;
-
- for ( i = 0; i < sigdata->n_samples; ++i ) {
- if ( it_asy_read_sample_header( &sigdata->sample[i], f ) ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
-
- if ( dumbfile_skip( f, 37 * ( 64 - sigdata->n_samples ) ) ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
-
- sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
- if ( !sigdata->pattern ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; ++i)
- sigdata->pattern[i].entry = NULL;
-
- /* Read in the patterns */
- {
- unsigned char *buffer = malloc( 64 * 8 * 4 ); /* 64 rows * 8 channels * 4 bytes */
- if ( !buffer ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- for ( i = 0; i < sigdata->n_patterns; ++i ) {
- if ( it_asy_read_pattern( &sigdata->pattern[i], f, buffer ) != 0 ) {
- free( buffer );
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
- free( buffer );
- }
-
- /* And finally, the sample data */
- for ( i = 0; i < sigdata->n_samples; ++i ) {
- if ( it_asy_read_sample_data( &sigdata->sample[i], f ) ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
-
- /* Now let's initialise the remaining variables, and we're done! */
- sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
-
- sigdata->global_volume = 128;
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- sigdata->n_pchannels = 8;
-
- sigdata->name[0] = 0;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
- sigdata->channel_pan[i+0] = 16;
- sigdata->channel_pan[i+1] = 48;
- sigdata->channel_pan[i+2] = 48;
- sigdata->channel_pan[i+3] = 16;
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-
-
-DUH *dumb_read_asy_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_asy_load_sigdata(f);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "ASYLUM Music Format";
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readasy.c - Code to read an ASYLUM Music Format / / \ \ + * module from an open file. | < / \_ + * | \/ /\ / + * By Chris Moeller. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "dumb.h" +#include "internal/it.h" + + + +static int it_asy_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer ) +{ + int pos; + int channel; + int row; + IT_ENTRY *entry; + + pattern->n_rows = 64; + + if ( dumbfile_getnc( buffer, 64 * 8 * 4, f ) != 64 * 8 * 4 ) + return -1; + + /* compute number of entries */ + pattern->n_entries = 64; /* Account for the row end markers */ + pos = 0; + for ( row = 0; row < 64; ++row ) { + for ( channel = 0; channel < 8; ++channel ) { + if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) + ++pattern->n_entries; + pos += 4; + } + } + + pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) ); + if ( !pattern->entry ) + return -1; + + entry = pattern->entry; + pos = 0; + for ( row = 0; row < 64; ++row ) { + for ( channel = 0; channel < 8; ++channel ) { + if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) { + entry->channel = channel; + entry->mask = 0; + + if ( buffer[ pos + 0 ] && buffer[ pos + 0 ] < 96 ) { + entry->note = buffer[ pos + 0 ]; + entry->mask |= IT_ENTRY_NOTE; + } + + if ( buffer[ pos + 1 ] && buffer[ pos + 1 ] <= 64 ) { + entry->instrument = buffer[ pos + 1 ]; + entry->mask |= IT_ENTRY_INSTRUMENT; + } + + _dumb_it_xm_convert_effect( buffer[ pos + 2 ] & 0x0F, buffer[ pos + 3 ], entry, 1 ); + + if ( entry->mask ) ++entry; + } + pos += 4; + } + IT_SET_END_ROW( entry ); + ++entry; + } + + pattern->n_entries = entry - pattern->entry; + + return 0; +} + + + +static int it_asy_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f ) +{ + int finetune; + +/** + 21 22 Chars Sample 1 name. If the name is not a full + 22 chars in length, it will be null + terminated. + +If +the sample name begins with a '#' character (ASCII $23 (35)) then this is +assumed not to be an instrument name, and is probably a message. +*/ + dumbfile_getnc( sample->name, 22, f ); + sample->name[22] = 0; + + sample->filename[0] = 0; + +/** Each finetune step changes the note 1/8th of a semitone. */ + finetune = ( signed char ) ( dumbfile_getc( f ) << 4 ) >> 4; /* signed nibble */ + sample->default_volume = dumbfile_getc( f ); // Should we be setting global_volume to this instead? + sample->global_volume = 64; + if ( sample->default_volume > 64 ) sample->default_volume = 64; + dumbfile_skip( f, 1 ); /* XXX unknown */ + sample->length = dumbfile_igetl( f ); + sample->loop_start = dumbfile_igetl( f ); + sample->loop_end = sample->loop_start + dumbfile_igetl( f ); + + if ( sample->length <= 0 ) { + sample->flags = 0; + return 0; + } + + sample->flags = IT_SAMPLE_EXISTS; + + sample->default_pan = 0; + sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//( long )( 16726.0 * pow( DUMB_PITCH_BASE, finetune * 32 ) ); + sample->finetune = finetune * 32; + // the above line might be wrong + + if ( ( sample->loop_end - sample->loop_start > 2 ) && ( sample->loop_end <= sample->length ) ) + sample->flags |= IT_SAMPLE_LOOP; + + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = 0; // do we have to set _all_ these? + sample->max_resampling_quality = -1; + + return dumbfile_error(f); +} + + + +static int it_asy_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f ) +{ + long truncated_size; + + /* let's get rid of the sample data coming after the end of the loop */ + if ( ( sample->flags & IT_SAMPLE_LOOP ) && sample->loop_end < sample->length ) { + truncated_size = sample->length - sample->loop_end; + sample->length = sample->loop_end; + } else { + truncated_size = 0; + } + + sample->data = malloc( sample->length ); + + if ( !sample->data ) + return -1; + + if ( sample->length ) + dumbfile_getnc( sample->data, sample->length, f ); + + dumbfile_skip( f, truncated_size ); + + return dumbfile_error( f ); +} + + + +static DUMB_IT_SIGDATA *it_asy_load_sigdata(DUMBFILE *f) +{ + DUMB_IT_SIGDATA *sigdata; + int i; + + static const char sig_part[] = "ASYLUM Music Format"; + static const char sig_rest[] = " V1.0"; /* whee, string space optimization with format type below */ + + char signature [32]; + + if ( dumbfile_getnc( signature, 32, f ) != 32 || + memcmp( signature, sig_part, 19 ) || + memcmp( signature + 19, sig_rest, 5 ) ) { + return NULL; + } + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) { + return NULL; + } + + sigdata->speed = dumbfile_getc( f ); /* XXX seems to fit the files I have */ + sigdata->tempo = dumbfile_getc( f ); /* ditto */ + sigdata->n_samples = dumbfile_getc( f ); /* ditto */ + sigdata->n_patterns = dumbfile_getc( f ); + sigdata->n_orders = dumbfile_getc( f ); + sigdata->restart_position = dumbfile_getc( f ); + + if ( dumbfile_error( f ) || !sigdata->n_samples || sigdata->n_samples > 64 || !sigdata->n_patterns || + !sigdata->n_orders ) { + free( sigdata ); + return NULL; + } + + if ( sigdata->restart_position > sigdata->n_orders ) /* XXX */ + sigdata->restart_position = 0; + + sigdata->order = malloc( sigdata->n_orders ); + if ( !sigdata->order ) { + free( sigdata ); + return NULL; + } + + if ( dumbfile_getnc( sigdata->order, sigdata->n_orders, f ) != sigdata->n_orders || + dumbfile_skip( f, 256 - sigdata->n_orders ) ) { + free( sigdata->order ); + free( sigdata ); + return NULL; + } + + sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) ); + if ( !sigdata->sample ) { + free( sigdata->order ); + free( sigdata ); + return NULL; + } + + sigdata->song_message = NULL; + sigdata->instrument = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->n_instruments = 0; + + for ( i = 0; i < sigdata->n_samples; ++i ) + sigdata->sample[i].data = NULL; + + for ( i = 0; i < sigdata->n_samples; ++i ) { + if ( it_asy_read_sample_header( &sigdata->sample[i], f ) ) { + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + } + + if ( dumbfile_skip( f, 37 * ( 64 - sigdata->n_samples ) ) ) { + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + + sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) ); + if ( !sigdata->pattern ) { + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + for (i = 0; i < sigdata->n_patterns; ++i) + sigdata->pattern[i].entry = NULL; + + /* Read in the patterns */ + { + unsigned char *buffer = malloc( 64 * 8 * 4 ); /* 64 rows * 8 channels * 4 bytes */ + if ( !buffer ) { + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + for ( i = 0; i < sigdata->n_patterns; ++i ) { + if ( it_asy_read_pattern( &sigdata->pattern[i], f, buffer ) != 0 ) { + free( buffer ); + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + } + free( buffer ); + } + + /* And finally, the sample data */ + for ( i = 0; i < sigdata->n_samples; ++i ) { + if ( it_asy_read_sample_data( &sigdata->sample[i], f ) ) { + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + } + + /* Now let's initialise the remaining variables, and we're done! */ + sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO; + + sigdata->global_volume = 128; + sigdata->mixing_volume = 48; + sigdata->pan_separation = 128; + + sigdata->n_pchannels = 8; + + sigdata->name[0] = 0; + + memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); + + for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) { + sigdata->channel_pan[i+0] = 16; + sigdata->channel_pan[i+1] = 48; + sigdata->channel_pan[i+2] = 48; + sigdata->channel_pan[i+3] = 16; + } + + _dumb_it_fix_invalid_orders(sigdata); + + return sigdata; +} + + + +DUH *dumb_read_asy_quick(DUMBFILE *f) +{ + sigdata_t *sigdata; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_asy_load_sigdata(f); + + if (!sigdata) + return NULL; + + { + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = "ASYLUM Music Format"; + return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/readdsmf.c b/plugins/dumb/dumb-kode54/src/it/readdsmf.c index 2a4f23e6..4fa04f0e 100644 --- a/plugins/dumb/dumb-kode54/src/it/readdsmf.c +++ b/plugins/dumb/dumb-kode54/src/it/readdsmf.c @@ -1,373 +1,373 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readam.c - Code to read a RIFF DSMF module / / \ \
- * from a parsed RIFF structure. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-#include "internal/riff.h"
-
-static int it_riff_dsmf_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len )
-{
- int flags;
-
- memcpy( sample->filename, data, 13 );
- sample->filename[ 14 ] = 0;
-
- flags = data[ 13 ] | ( data[ 14 ] << 8 );
- sample->default_volume = data[ 15 ];
- sample->length = data[ 16 ] | ( data[ 17 ] << 8 ) | ( data[ 18 ] << 16 ) | ( data[ 19 ] << 24 );
- sample->loop_start = data[ 20 ] | ( data[ 21 ] << 8 ) | ( data[ 22 ] << 16 ) | ( data[ 23 ] << 24 );
- sample->loop_end = data[ 24 ] | ( data[ 25 ] << 8 ) | ( data[ 26 ] << 16 ) | ( data[ 27 ] << 24 );
- sample->C5_speed = ( data[ 32 ] | ( data[ 33 ] << 8 ) ) * 2;
- memcpy( sample->name, data + 36, 28 );
- sample->name[ 28 ] = 0;
-
- /*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] )
- return -1;*/
-
- if ( ! sample->length ) {
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return 0;
- }
-
- /*if ( flags & ~( 2 | 1 ) )
- return -1;*/
-
- if ( sample->length + 64 > len )
- return -1;
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- sample->default_pan = 0;
- sample->global_volume = 64;
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- if ( flags & 1 )
- {
- if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) &&
- ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end))
- {
- sample->length = sample->loop_end;
- sample->flags |= IT_SAMPLE_LOOP;
- if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
- }
- }
-
- sample->data = malloc( sample->length );
- if ( ! sample->data )
- return -1;
-
- memcpy( sample->data, data + 64, sample->length );
-
- if ( ! ( flags & 2 ) )
- {
- for ( flags = 0; flags < sample->length; ++flags )
- ( ( signed char * ) sample->data ) [ flags ] ^= 0x80;
- }
-
- return 0;
-}
-
-static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, const unsigned char * data, int len )
-{
- int length, row, pos;
- unsigned flags;
- IT_ENTRY * entry;
-
- length = data[ 0 ] | ( data[ 1 ] << 8 );
- if ( length > len ) return -1;
-
- data += 2;
- len = length - 2;
-
- pattern->n_rows = 64;
- pattern->n_entries = 64;
-
- row = 0;
- pos = 0;
-
- while ( (row < 64) && (pos < len) ) {
- if ( ! data[ pos ] ) {
- ++ row;
- ++ pos;
- continue;
- }
-
- flags = data[ pos++ ] & 0xF0;
-
- if (flags) {
- ++ pattern->n_entries;
- if (flags & 0x80) pos ++;
- if (flags & 0x40) pos ++;
- if (flags & 0x20) pos ++;
- if (flags & 0x10) pos += 2;
- }
- }
-
- if ( pattern->n_entries == 64 ) return 0;
-
- pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) );
- if ( ! pattern->entry ) return -1;
-
- entry = pattern->entry;
-
- row = 0;
- pos = 0;
-
- while ( ( row < 64 ) && ( pos < len ) )
- {
- if ( ! data[ pos ] )
- {
- IT_SET_END_ROW( entry );
- ++ entry;
- ++ row;
- ++ pos;
- continue;
- }
-
- flags = data[ pos++ ];
- entry->channel = flags & 0x0F;
- entry->mask = 0;
-
- if ( flags & 0xF0 )
- {
- if ( flags & 0x80 )
- {
- if ( data[ pos ] )
- {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = data[ pos ] - 1;
- }
- ++ pos;
- }
-
- if ( flags & 0x40 )
- {
- if ( data[ pos ] )
- {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = data[ pos ];
- }
- ++ pos;
- }
-
- if ( flags & 0x20 )
- {
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->volpan = data[ pos ];
- ++ pos;
- }
-
- if ( flags & 0x10 )
- {
- _dumb_it_xm_convert_effect( data[ pos ], data[ pos + 1 ], entry, 0 );
- pos += 2;
- }
-
- if (entry->mask) entry++;
- }
- }
-
- while ( row < 64 )
- {
- IT_SET_END_ROW( entry );
- ++ entry;
- ++ row;
- }
-
- pattern->n_entries = entry - pattern->entry;
- if ( ! pattern->n_entries ) return -1;
-
- return 0;
-}
-
-static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( struct riff * stream )
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int n, o, found;
-
- unsigned char * ptr;
-
- if ( ! stream ) goto error;
-
- if ( stream->type != DUMB_ID( 'D', 'S', 'M', 'F' ) ) goto error;
-
- sigdata = malloc(sizeof(*sigdata));
- if ( ! sigdata ) goto error;
-
- sigdata->n_patterns = 0;
- sigdata->n_samples = 0;
- sigdata->name[0] = 0;
-
- found = 0;
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch( c->type )
- {
- case DUMB_ID( 'S' ,'O' ,'N' ,'G' ):
- /* initialization data */
- if ( ( found ) || ( c->size < 192 ) ) goto error_sd;
- found = 1;
- break;
-
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- ++ sigdata->n_patterns;
- break;
-
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- ++ sigdata->n_samples;
- break;
- }
- }
-
- if ( !found || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd;
-
- if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- sigdata->n_instruments = 0;
- sigdata->n_orders = 0;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'S', 'O', 'N', 'G' ):
- ptr = ( unsigned char * ) c->data;
- memcpy( sigdata->name, c->data, 28 );
- sigdata->name[ 28 ] = 0;
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
- sigdata->n_orders = ptr[ 36 ] | ( ptr[ 37 ] << 8 );
- //sigdata->n_samples = ptr[ 38 ] | ( ptr[ 39 ] << 8 ); // whatever
- //sigdata->n_patterns = ptr[ 40 ] | ( ptr[ 41 ] << 8 );
- sigdata->n_pchannels = ptr[ 42 ] | ( ptr[ 43 ] << 8 );
- sigdata->global_volume = ptr[ 44 ];
- sigdata->mixing_volume = ptr[ 45 ];
- sigdata->speed = ptr[ 46 ];
- sigdata->tempo = ptr[ 47 ];
-
- for ( o = 0; o < 16; ++o )
- {
- sigdata->channel_pan[ o ] = ptr[ 48 + o ] / 2;
- }
-
- sigdata->order = malloc( 128 );
- if ( ! sigdata->order ) goto error_usd;
- memcpy( sigdata->order, ptr + 64, 128 );
-
- break;
- }
- }
-
- sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) );
- if ( ! sigdata->pattern ) goto error_usd;
- for ( n = 0; n < sigdata->n_patterns; ++n )
- sigdata->pattern[ n ].entry = NULL;
-
- sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) );
- if ( ! sigdata->sample ) goto error_usd;
- for ( n = 0; n < sigdata->n_samples; ++n )
- {
- IT_SAMPLE * sample = sigdata->sample + n;
- sample->data = NULL;
- }
-
- sigdata->n_samples = 0;
- sigdata->n_patterns = 0;
-
- for ( n = 0; n < stream->chunk_count; ++n )
- {
- struct riff_chunk * c = stream->chunks + n;
- switch ( c->type )
- {
- case DUMB_ID( 'P', 'A', 'T', 'T' ):
- if ( it_riff_dsmf_process_pattern( sigdata->pattern + sigdata->n_patterns, ( unsigned char * ) c->data, c->size ) ) goto error_usd;
- ++ sigdata->n_patterns;
- break;
-
- case DUMB_ID( 'I', 'N', 'S', 'T' ):
- if ( it_riff_dsmf_process_sample( sigdata->sample + sigdata->n_samples, ( unsigned char * ) c->data, c->size ) ) goto error_usd;
- ++ sigdata->n_samples;
- break;
- }
- }
-
- _dumb_it_fix_invalid_orders( sigdata );
-
- return sigdata;
-
-error_usd:
- _dumb_it_unload_sigdata( sigdata );
- goto error;
-error_sd:
- free( sigdata );
-error:
- return NULL;
-}
-
-DUH *dumb_read_riff_dsmf( struct riff * stream )
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_riff_dsmf_load_sigdata( stream );
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "RIFF DSMF";
- return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata );
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readam.c - Code to read a RIFF DSMF module / / \ \ + * from a parsed RIFF structure. | < / \_ + * | \/ /\ / + * By Chris Moeller. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" +#include "internal/it.h" +#include "internal/riff.h" + +static int it_riff_dsmf_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len ) +{ + int flags; + + memcpy( sample->filename, data, 13 ); + sample->filename[ 14 ] = 0; + + flags = data[ 13 ] | ( data[ 14 ] << 8 ); + sample->default_volume = data[ 15 ]; + sample->length = data[ 16 ] | ( data[ 17 ] << 8 ) | ( data[ 18 ] << 16 ) | ( data[ 19 ] << 24 ); + sample->loop_start = data[ 20 ] | ( data[ 21 ] << 8 ) | ( data[ 22 ] << 16 ) | ( data[ 23 ] << 24 ); + sample->loop_end = data[ 24 ] | ( data[ 25 ] << 8 ) | ( data[ 26 ] << 16 ) | ( data[ 27 ] << 24 ); + sample->C5_speed = ( data[ 32 ] | ( data[ 33 ] << 8 ) ) * 2; + memcpy( sample->name, data + 36, 28 ); + sample->name[ 28 ] = 0; + + /*if ( data[ 0x38 ] || data[ 0x39 ] || data[ 0x3A ] || data[ 0x3B ] ) + return -1;*/ + + if ( ! sample->length ) { + sample->flags &= ~IT_SAMPLE_EXISTS; + return 0; + } + + /*if ( flags & ~( 2 | 1 ) ) + return -1;*/ + + if ( sample->length + 64 > len ) + return -1; + + sample->flags = IT_SAMPLE_EXISTS; + + sample->default_pan = 0; + sample->global_volume = 64; + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = IT_VIBRATO_SINE; + sample->finetune = 0; + sample->max_resampling_quality = -1; + + if ( flags & 1 ) + { + if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) && + ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end)) + { + sample->length = sample->loop_end; + sample->flags |= IT_SAMPLE_LOOP; + if ( flags & 0x10 ) sample->flags |= IT_SAMPLE_PINGPONG_LOOP; + } + } + + sample->data = malloc( sample->length ); + if ( ! sample->data ) + return -1; + + memcpy( sample->data, data + 64, sample->length ); + + if ( ! ( flags & 2 ) ) + { + for ( flags = 0; flags < sample->length; ++flags ) + ( ( signed char * ) sample->data ) [ flags ] ^= 0x80; + } + + return 0; +} + +static int it_riff_dsmf_process_pattern( IT_PATTERN * pattern, const unsigned char * data, int len ) +{ + int length, row, pos; + unsigned flags; + IT_ENTRY * entry; + + length = data[ 0 ] | ( data[ 1 ] << 8 ); + if ( length > len ) return -1; + + data += 2; + len = length - 2; + + pattern->n_rows = 64; + pattern->n_entries = 64; + + row = 0; + pos = 0; + + while ( (row < 64) && (pos < len) ) { + if ( ! data[ pos ] ) { + ++ row; + ++ pos; + continue; + } + + flags = data[ pos++ ] & 0xF0; + + if (flags) { + ++ pattern->n_entries; + if (flags & 0x80) pos ++; + if (flags & 0x40) pos ++; + if (flags & 0x20) pos ++; + if (flags & 0x10) pos += 2; + } + } + + if ( pattern->n_entries == 64 ) return 0; + + pattern->entry = malloc( pattern->n_entries * sizeof( * pattern->entry ) ); + if ( ! pattern->entry ) return -1; + + entry = pattern->entry; + + row = 0; + pos = 0; + + while ( ( row < 64 ) && ( pos < len ) ) + { + if ( ! data[ pos ] ) + { + IT_SET_END_ROW( entry ); + ++ entry; + ++ row; + ++ pos; + continue; + } + + flags = data[ pos++ ]; + entry->channel = flags & 0x0F; + entry->mask = 0; + + if ( flags & 0xF0 ) + { + if ( flags & 0x80 ) + { + if ( data[ pos ] ) + { + entry->mask |= IT_ENTRY_NOTE; + entry->note = data[ pos ] - 1; + } + ++ pos; + } + + if ( flags & 0x40 ) + { + if ( data[ pos ] ) + { + entry->mask |= IT_ENTRY_INSTRUMENT; + entry->instrument = data[ pos ]; + } + ++ pos; + } + + if ( flags & 0x20 ) + { + entry->mask |= IT_ENTRY_VOLPAN; + entry->volpan = data[ pos ]; + ++ pos; + } + + if ( flags & 0x10 ) + { + _dumb_it_xm_convert_effect( data[ pos ], data[ pos + 1 ], entry, 0 ); + pos += 2; + } + + if (entry->mask) entry++; + } + } + + while ( row < 64 ) + { + IT_SET_END_ROW( entry ); + ++ entry; + ++ row; + } + + pattern->n_entries = entry - pattern->entry; + if ( ! pattern->n_entries ) return -1; + + return 0; +} + +static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( struct riff * stream ) +{ + DUMB_IT_SIGDATA *sigdata; + + int n, o, found; + + unsigned char * ptr; + + if ( ! stream ) goto error; + + if ( stream->type != DUMB_ID( 'D', 'S', 'M', 'F' ) ) goto error; + + sigdata = malloc(sizeof(*sigdata)); + if ( ! sigdata ) goto error; + + sigdata->n_patterns = 0; + sigdata->n_samples = 0; + sigdata->name[0] = 0; + + found = 0; + + for ( n = 0; n < stream->chunk_count; ++n ) + { + struct riff_chunk * c = stream->chunks + n; + switch( c->type ) + { + case DUMB_ID( 'S' ,'O' ,'N' ,'G' ): + /* initialization data */ + if ( ( found ) || ( c->size < 192 ) ) goto error_sd; + found = 1; + break; + + case DUMB_ID( 'P', 'A', 'T', 'T' ): + ++ sigdata->n_patterns; + break; + + case DUMB_ID( 'I', 'N', 'S', 'T' ): + ++ sigdata->n_samples; + break; + } + } + + if ( !found || !sigdata->n_samples || !sigdata->n_patterns ) goto error_sd; + + if ( sigdata->n_samples > 255 || sigdata->n_patterns > 255 ) goto error_sd; + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->sample = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->mixing_volume = 48; + sigdata->pan_separation = 128; + + sigdata->n_instruments = 0; + sigdata->n_orders = 0; + + memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); + + for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { + sigdata->channel_pan[n ] = 16; + sigdata->channel_pan[n+1] = 48; + sigdata->channel_pan[n+2] = 48; + sigdata->channel_pan[n+3] = 16; + } + + for ( n = 0; n < stream->chunk_count; ++n ) + { + struct riff_chunk * c = stream->chunks + n; + switch ( c->type ) + { + case DUMB_ID( 'S', 'O', 'N', 'G' ): + ptr = ( unsigned char * ) c->data; + memcpy( sigdata->name, c->data, 28 ); + sigdata->name[ 28 ] = 0; + sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX; + sigdata->n_orders = ptr[ 36 ] | ( ptr[ 37 ] << 8 ); + //sigdata->n_samples = ptr[ 38 ] | ( ptr[ 39 ] << 8 ); // whatever + //sigdata->n_patterns = ptr[ 40 ] | ( ptr[ 41 ] << 8 ); + sigdata->n_pchannels = ptr[ 42 ] | ( ptr[ 43 ] << 8 ); + sigdata->global_volume = ptr[ 44 ]; + sigdata->mixing_volume = ptr[ 45 ]; + sigdata->speed = ptr[ 46 ]; + sigdata->tempo = ptr[ 47 ]; + + for ( o = 0; o < 16; ++o ) + { + sigdata->channel_pan[ o ] = ptr[ 48 + o ] / 2; + } + + sigdata->order = malloc( 128 ); + if ( ! sigdata->order ) goto error_usd; + memcpy( sigdata->order, ptr + 64, 128 ); + + break; + } + } + + sigdata->pattern = malloc( sigdata->n_patterns * sizeof( *sigdata->pattern ) ); + if ( ! sigdata->pattern ) goto error_usd; + for ( n = 0; n < sigdata->n_patterns; ++n ) + sigdata->pattern[ n ].entry = NULL; + + sigdata->sample = malloc( sigdata->n_samples * sizeof( *sigdata->sample ) ); + if ( ! sigdata->sample ) goto error_usd; + for ( n = 0; n < sigdata->n_samples; ++n ) + { + IT_SAMPLE * sample = sigdata->sample + n; + sample->data = NULL; + } + + sigdata->n_samples = 0; + sigdata->n_patterns = 0; + + for ( n = 0; n < stream->chunk_count; ++n ) + { + struct riff_chunk * c = stream->chunks + n; + switch ( c->type ) + { + case DUMB_ID( 'P', 'A', 'T', 'T' ): + if ( it_riff_dsmf_process_pattern( sigdata->pattern + sigdata->n_patterns, ( unsigned char * ) c->data, c->size ) ) goto error_usd; + ++ sigdata->n_patterns; + break; + + case DUMB_ID( 'I', 'N', 'S', 'T' ): + if ( it_riff_dsmf_process_sample( sigdata->sample + sigdata->n_samples, ( unsigned char * ) c->data, c->size ) ) goto error_usd; + ++ sigdata->n_samples; + break; + } + } + + _dumb_it_fix_invalid_orders( sigdata ); + + return sigdata; + +error_usd: + _dumb_it_unload_sigdata( sigdata ); + goto error; +error_sd: + free( sigdata ); +error: + return NULL; +} + +DUH *dumb_read_riff_dsmf( struct riff * stream ) +{ + sigdata_t *sigdata; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_riff_dsmf_load_sigdata( stream ); + + if (!sigdata) + return NULL; + + { + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = "RIFF DSMF"; + return make_duh( -1, 2, ( const char * const (*) [ 2 ] ) tag, 1, & descptr, & sigdata ); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/readmod.c b/plugins/dumb/dumb-kode54/src/it/readmod.c index b6b35cbe..a934af40 100644 --- a/plugins/dumb/dumb-kode54/src/it/readmod.c +++ b/plugins/dumb/dumb-kode54/src/it/readmod.c @@ -1,780 +1,782 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readmod.c - Code to read a good old-fashioned / / \ \
- * Amiga module from an open file. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-static int it_mod_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer)
-{
- int pos;
- int channel;
- int row;
- IT_ENTRY *entry;
-
- pattern->n_rows = 64;
-
- if (n_channels == 0) {
- /* Read the first four channels, leaving gaps for the rest. */
- for (pos = 0; pos < 64*8*4; pos += 8*4)
- dumbfile_getnc(buffer + pos, 4*4, f);
- /* Read the other channels into the gaps we left. */
- for (pos = 4*4; pos < 64*8*4; pos += 8*4)
- dumbfile_getnc(buffer + pos, 4*4, f);
-
- n_channels = 8;
- } else
- dumbfile_getnc(buffer, 64 * n_channels * 4, f);
-
- if (dumbfile_error(f))
- return -1;
-
- /* compute number of entries */
- pattern->n_entries = 64; /* Account for the row end markers */
- pos = 0;
- for (row = 0; row < 64; row++) {
- for (channel = 0; channel < n_channels; channel++) {
- if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3])
- pattern->n_entries++;
- pos += 4;
- }
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
- if (!pattern->entry)
- return -1;
-
- entry = pattern->entry;
- pos = 0;
- for (row = 0; row < 64; row++) {
- for (channel = 0; channel < n_channels; channel++) {
- if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3]) {
- unsigned char sample = (buffer[pos+0] & 0xF0) | (buffer[pos+2] >> 4);
- int period = ((int)(buffer[pos+0] & 0x0F) << 8) | buffer[pos+1];
-
- entry->channel = channel;
- entry->mask = 0;
-
- if (period) {
- int note;
- entry->mask |= IT_ENTRY_NOTE;
-
- /* frequency = (AMIGA_DIVISOR / 8) / (period * 2)
- * C-1: period = 214 -> frequency = 16726
- * so, set C5_speed to 16726
- * and period = 214 should translate to C5 aka 60
- * halve the period, go up an octive
- *
- * period = 214 / pow(DUMB_SEMITONE_BASE, note - 60)
- * pow(DUMB_SEMITONE_BASE, note - 60) = 214 / period
- * note - 60 = log(214/period) / log(DUMB_SEMITONE_BASE)
- */
- note = (int)floor(log(214.0/period) / log(DUMB_SEMITONE_BASE) + 60.5);
- entry->note = MID(0, note, 119);
- // or should we preserve the period?
- //entry->note = buffer[pos+0] & 0x0F; /* High nibble */
- //entry->volpan = buffer[pos+1]; /* Low byte */
- // and what about finetune?
- }
-
- if (sample) {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = sample;
- }
-
- _dumb_it_xm_convert_effect(buffer[pos+2] & 0x0F, buffer[pos+3], entry, 1);
-
- entry++;
- }
- pos += 4;
- }
- IT_SET_END_ROW(entry);
- entry++;
- }
-
- return 0;
-}
-
-
-
-static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
-{
- int finetune, loop_start, loop_length;
-
-/**
- 21 22 Chars Sample 1 name. If the name is not a full
- 22 chars in length, it will be null
- terminated.
-
-If
-the sample name begins with a '#' character (ASCII $23 (35)) then this is
-assumed not to be an instrument name, and is probably a message.
-*/
- dumbfile_getnc(sample->name, 22, f);
- sample->name[22] = 0;
-
- sample->filename[0] = 0;
-
- sample->length = dumbfile_mgetw(f) << 1;
- finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
-/** Each finetune step changes the note 1/8th of a semitone. */
- sample->global_volume = 64;
- sample->default_volume = dumbfile_getc(f); // Should we be setting global_volume to this instead?
- loop_start = dumbfile_mgetw(f) << 1;
- loop_length = dumbfile_mgetw(f) << 1;
- if ( loop_length > 2 && loop_start + loop_length > sample->length && loop_start / 2 + loop_length <= sample->length )
- loop_start /= 2;
- sample->loop_start = loop_start;
- sample->loop_end = loop_start + loop_length;
-/**
-Once this sample has been played completely from beginning
-to end, if the repeat length (next field) is greater than two bytes it
-will loop back to this position in the sample and continue playing. Once
-it has played for the repeat length, it continues to loop back to the
-repeat start offset. This means the sample continues playing until it is
-told to stop.
-*/
-
- if (sample->length <= 0) {
- sample->flags = 0;
- return 0;
- }
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- sample->default_pan = 0;
- sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 ); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
- sample->finetune = finetune * 32;
- // the above line might be wrong
-
- if (sample->loop_end > sample->length)
- sample->loop_end = sample->length;
-
- if (sample->loop_end - sample->loop_start > 2)
- sample->flags |= IT_SAMPLE_LOOP;
-
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = 0; // do we have to set _all_ these?
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-
-
-static int it_mod_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f, unsigned long fft)
-{
- long i;
- long truncated_size;
-
- /* let's get rid of the sample data coming after the end of the loop */
- if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
- truncated_size = sample->length - sample->loop_end;
- sample->length = sample->loop_end;
- } else {
- truncated_size = 0;
- }
-
- if (sample->length) {
- sample->data = malloc(sample->length);
-
- if (!sample->data)
- return -1;
-
- /* Sample data are stored in "8-bit two's compliment format" (sic). */
- /*
- for (i = 0; i < sample->length; i++)
- ((signed char *)sample->left)[i] = dumbfile_getc(f);
- */
- /* F U Olivier Lapicque */
- if (sample->length >= 5)
- {
- i = dumbfile_getnc(sample->data, 5, f);
- if (i == 5)
- {
- if (!memcmp(sample->data, "ADPCM", 5))
- {
- if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
- return -1;
-
- return 0;
- }
- else
- {
- i += dumbfile_getnc(((char *)sample->data) + 5, sample->length - 5, f);
- }
- }
- }
- else
- {
- i = dumbfile_getnc(sample->data, sample->length, f);
- }
- if (i < sample->length)
- {
- if (i <= 0)
- {
- sample->flags = 0;
- return 0;
- }
- sample->length = i;
- if (sample->loop_end > i) sample->loop_end = i;
- // holy crap!
- if (sample->loop_start > i) sample->flags &= ~IT_SAMPLE_LOOP;
- }
- else
- {
- /* skip truncated data */
- int feh = dumbfile_error(f);
-
- if (truncated_size) dumbfile_skip(f, truncated_size);
- // Should we be truncating it?
-
- if (feh)
- return -1;
- }
-
- if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) {
- int delta = 0;
- for (i = 0; i < sample->length; i++) {
- delta += ((signed char *)sample->data)[i];
- ((signed char *)sample->data)[i] = delta;
- }
- }
- }
-
- return 0;
-}
-
-
-
-typedef struct BUFFERED_MOD BUFFERED_MOD;
-
-struct BUFFERED_MOD
-{
- unsigned char *buffered;
- long ptr, len;
- DUMBFILE *remaining;
-};
-
-
-
-static int buffer_mod_skip(void *f, long n)
-{
- BUFFERED_MOD *bm = f;
- if (bm->buffered) {
- bm->ptr += n;
- if (bm->ptr >= bm->len) {
- free(bm->buffered);
- bm->buffered = NULL;
- return dumbfile_skip(bm->remaining, bm->ptr - bm->len);
- }
- return 0;
- }
- return dumbfile_skip(bm->remaining, n);
-}
-
-
-
-static int buffer_mod_getc(void *f)
-{
- BUFFERED_MOD *bm = f;
- if (bm->buffered) {
- int rv = bm->buffered[bm->ptr++];
- if (bm->ptr >= bm->len) {
- free(bm->buffered);
- bm->buffered = NULL;
- }
- return rv;
- }
- return dumbfile_getc(bm->remaining);
-}
-
-
-
-static long buffer_mod_getnc(char *ptr, long n, void *f)
-{
- BUFFERED_MOD *bm = f;
- if (bm->buffered) {
- int left = bm->len - bm->ptr;
- if (n >= left) {
- memcpy(ptr, bm->buffered + bm->ptr, left);
- free(bm->buffered);
- bm->buffered = NULL;
- if (n - left) {
- int rv = dumbfile_getnc(ptr + left, n - left, bm->remaining);
- return left + MAX(rv, 0);
- } else {
- return left;
- }
- }
- memcpy(ptr, bm->buffered + bm->ptr, n);
- bm->ptr += n;
- return n;
- }
- return dumbfile_getnc(ptr, n, bm->remaining);
-}
-
-
-
-static void buffer_mod_close(void *f)
-{
- BUFFERED_MOD *bm = f;
- if (bm->buffered) free(bm->buffered);
- /* Do NOT close bm->remaining */
- free(f);
-}
-
-
-
-DUMBFILE_SYSTEM buffer_mod_dfs = {
- NULL,
- &buffer_mod_skip,
- &buffer_mod_getc,
- &buffer_mod_getnc,
- &buffer_mod_close
-};
-
-
-
-#define MOD_FFT_OFFSET (20 + 31*(22+2+1+1+2+2) + 1 + 1 + 128)
-
-static DUMBFILE *dumbfile_buffer_mod(DUMBFILE *f, unsigned long *fft)
-{
- BUFFERED_MOD *bm = malloc(sizeof(*bm));
- if (!bm) return NULL;
-
- bm->buffered = malloc(MOD_FFT_OFFSET + 4);
- if (!bm->buffered) {
- free(bm);
- return NULL;
- }
-
- bm->len = dumbfile_getnc(bm->buffered, MOD_FFT_OFFSET + 4, f);
-
- if (bm->len > 0) {
- if (bm->len >= MOD_FFT_OFFSET + 4)
- *fft = (unsigned long)bm->buffered[MOD_FFT_OFFSET ] << 24
- | (unsigned long)bm->buffered[MOD_FFT_OFFSET+1] << 16
- | (unsigned long)bm->buffered[MOD_FFT_OFFSET+2] << 8
- | (unsigned long)bm->buffered[MOD_FFT_OFFSET+3];
- else
- *fft = 0;
- bm->ptr = 0;
- } else {
- free(bm->buffered);
- bm->buffered = NULL;
- }
-
- bm->remaining = f;
-
- return dumbfile_open_ex(bm, &buffer_mod_dfs);
-}
-
-static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, long *remain)
-{
- long read;
- BUFFERED_MOD *bm = malloc(sizeof(*bm));
- if (!bm) return NULL;
-
- bm->buffered = malloc(32768);
- if (!bm->buffered) {
- free(bm);
- return NULL;
- }
-
- bm->len = 0;
- *remain = 0;
-
- read = dumbfile_getnc(bm->buffered, 32768, f);
-
- if (read >= 0) {
- bm->len += read;
- *remain += read;
-
- while (read >= 32768) {
- bm->buffered = realloc(bm->buffered, *remain + 32768);
- if (!bm->buffered) {
- free(bm);
- return 0;
- }
- read = dumbfile_getnc(bm->buffered + *remain, 32768, f);
- if (read >= 0) {
- bm->len += read;
- *remain += read;
- }
- }
- }
-
- if (*remain) {
- bm->ptr = 0;
- } else {
- free(bm->buffered);
- bm->buffered = NULL;
- }
-
- bm->remaining = f;
-
- return dumbfile_open_ex(bm, &buffer_mod_dfs);
-}
-
-
-static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict)
-{
- DUMB_IT_SIGDATA *sigdata;
- int n_channels;
- int i;
- unsigned long fft = 0;
- DUMBFILE *rem;
-
- f = dumbfile_buffer_mod(f, &fft);
- if (!f)
- return NULL;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) {
- dumbfile_close(f);
- return NULL;
- }
-
- /**
- 1 20 Chars Title of the song. If the title is not a
- full 20 chars in length, it will be null-
- terminated.
- */
- if (dumbfile_getnc(sigdata->name, 20, f) < 20) {
- free(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- sigdata->name[20] = 0;
-
- sigdata->n_samples = 31;
-
- switch (fft) {
- case DUMB_ID('M','.','K','.'):
- case DUMB_ID('M','!','K','!'):
- case DUMB_ID('M','&','K','!'):
- case DUMB_ID('N','.','T','.'):
- case DUMB_ID('N','S','M','S'):
- case DUMB_ID('F','L','T','4'):
- case DUMB_ID('M',0,0,0):
- case DUMB_ID('8',0,0,0):
- n_channels = 4;
- break;
- case DUMB_ID('F','L','T','8'):
- n_channels = 0;
- /* 0 indicates a special case; two four-channel patterns must be
- * combined into one eight-channel pattern. Pattern indexes must
- * be halved. Why oh why do they obfuscate so?
- */
- /*for (i = 0; i < 128; i++)
- sigdata->order[i] >>= 1;*/
- break;
- case DUMB_ID('C','D','8','1'):
- case DUMB_ID('O','C','T','A'):
- case DUMB_ID('O','K','T','A'):
- n_channels = 8;
- break;
- case DUMB_ID('1','6','C','N'):
- n_channels = 16;
- break;
- case DUMB_ID('3','2','C','N'):
- n_channels = 32;
- break;
- default:
- /* If we get an illegal tag, assume 4 channels 15 samples. */
- if ((fft & 0x0000FFFFL) == DUMB_ID(0,0,'C','H')) {
- if (fft >= '1' << 24 && fft < '4' << 24) {
- n_channels = ((fft & 0x00FF0000L) >> 16) - '0';
- if ((unsigned int)n_channels >= 10) {
- /* Rightmost character wasn't a digit. */
- n_channels = 4;
- sigdata->n_samples = 15;
- } else {
- n_channels += (((fft & 0xFF000000L) >> 24) - '0') * 10;
- /* MODs should really only go up to 32 channels, but we're lenient. */
- if ((unsigned int)(n_channels - 1) >= DUMB_IT_N_CHANNELS - 1) {
- /* No channels or too many? Can't be right... */
- n_channels = 4;
- sigdata->n_samples = 15;
- }
- }
- } else {
- n_channels = 4;
- sigdata->n_samples = 15;
- }
- } else if ((fft & 0x00FFFFFFL) == DUMB_ID(0,'C','H','N')) {
- n_channels = (fft >> 24) - '0';
- if ((unsigned int)(n_channels - 1) >= 9) {
- /* Character was '0' or it wasn't a digit */
- n_channels = 4;
- sigdata->n_samples = 15;
- }
- } else if ((fft & 0xFFFFFF00L) == DUMB_ID('T','D','Z',0)) {
- n_channels = (fft & 0x000000FFL) - '0';
- if ((unsigned int)(n_channels - 1) >= 9) {
- /* We've been very lenient, given that it should have
- * been 1, 2 or 3, but this MOD has been very naughty and
- * must be punished.
- */
- n_channels = 4;
- sigdata->n_samples = 15;
- }
- } else {
- n_channels = 4;
- sigdata->n_samples = 15;
- }
- }
-
- // moo
- if ( restrict && sigdata->n_samples == 15 )
- {
- free(sigdata);
- dumbfile_close(f);
- return NULL;
- }
-
- sigdata->n_pchannels = n_channels ? n_channels : 8; /* special case for 0, see above */
-
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- free(sigdata);
- dumbfile_close(f);
- return NULL;
- }
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
-
- for (i = 0; i < sigdata->n_samples; i++)
- sigdata->sample[i].data = NULL;
-
- for (i = 0; i < sigdata->n_samples; i++) {
- if (it_mod_read_sample_header(&sigdata->sample[i], f)) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- }
-
- sigdata->n_orders = dumbfile_getc(f);
- sigdata->restart_position = dumbfile_getc(f);
- // what if this is >= 127? what about with Fast Tracker II?
-
-/* if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }*/
-
- //if (sigdata->restart_position >= sigdata->n_orders)
- //sigdata->restart_position = 0;
-
- sigdata->order = malloc(128); /* We may need to scan the extra ones! */
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- if (dumbfile_getnc(sigdata->order, 128, f) < 128) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
-
- if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right?
- sigdata->n_orders = 128;
- //while (sigdata->n_orders > 1 && !sigdata->order[sigdata->n_orders - 1]) sigdata->n_orders--;
- }
-
- if ( ! n_channels )
- for (i = 0; i < 128; i++)
- sigdata->order[i] >>= 1;
-
- /* "The old NST format contains only 15 samples (instead of 31). Further
- * it doesn't contain a file format tag (id). So Pattern data offset is
- * at 20+15*30+1+1+128."
- * - Then I shall assume the File Format Tag never exists if there are
- * only 15 samples. I hope this isn't a faulty assumption...
- */
- if (sigdata->n_samples == 31)
- dumbfile_skip(f, 4);
-
- /* Work out how many patterns there are. */
- sigdata->n_patterns = -1;
- for (i = 0; i < 128; i++)
- if (sigdata->n_patterns < sigdata->order[i])
- sigdata->n_patterns = sigdata->order[i];
- sigdata->n_patterns++;
-
- /* May as well try to save a tiny bit of memory. */
- if (sigdata->n_orders < 128) {
- unsigned char *order = realloc(sigdata->order, sigdata->n_orders);
- if (order) sigdata->order = order;
- }
-
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++)
- sigdata->pattern[i].entry = NULL;
-
- /* Read in the patterns */
- {
- unsigned char *buffer = malloc(256 * n_channels); /* 64 rows * 4 bytes */
- if (!buffer) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++) {
- if (it_mod_read_pattern(&sigdata->pattern[i], f, n_channels, buffer) != 0) {
- free(buffer);
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- return NULL;
- }
- }
- free(buffer);
- }
-
- rem = NULL;
-
- /* uggly */
- if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) {
- long skip;
- long remain;
- rem = f;
- f = dumbfile_buffer_mod_2(rem, &remain);
- if (!f) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(rem);
- return NULL;
- }
- for (skip = 0, i = 0; i < sigdata->n_samples; i++) {
- if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) {
- skip += sigdata->sample[i].length;
- }
- }
- if (remain - skip) {
- if (dumbfile_skip(f, remain - skip)) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- dumbfile_close(rem);
- return NULL;
- }
- }
- }
-
- /* And finally, the sample data */
- for (i = 0; i < sigdata->n_samples; i++) {
- if (it_mod_read_sample_data(&sigdata->sample[i], f, fft)) {
- _dumb_it_unload_sigdata(sigdata);
- dumbfile_close(f);
- if (rem) dumbfile_close(rem);
- return NULL;
- }
- }
-
- /* w00t! */
- /*if ( n_channels == 4 &&
- ( sigdata->n_samples == 15 ||
- ( ( fft & 240 ) != DUMB_ID( 0, 0, 'C', 0 ) &&
- ( fft & 240 ) != DUMB_ID( 0, 0, 'H', 0 ) &&
- ( fft & 240 ) != 0 ) ) ) {
- for ( i = 0; i < sigdata->n_samples; ++i ) {
- IT_SAMPLE * sample = &sigdata->sample [i];
- if ( sample && ( sample->flags & IT_SAMPLE_EXISTS ) ) {
- int n, o;
- o = sample->length;
- if ( o > 4 ) o = 4;
- for ( n = 0; n < o; ++n )
- ( ( char * ) sample->data ) [n] = 0;
- }
- }
- }*/
-
- dumbfile_close(f); /* Destroy the BUFFERED_MOD DUMBFILE we were using. */
- /* The DUMBFILE originally passed to our function is intact. */
- if (rem) dumbfile_close(rem);
-
- /* Now let's initialise the remaining variables, and we're done! */
- sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO;
-
- sigdata->global_volume = 128;
- sigdata->mixing_volume = 48;
- /* We want 50 ticks per second; 50/6 row advances per second;
- * 50*10=500 row advances per minute; 500/4=125 beats per minute.
- */
- sigdata->speed = 6;
- sigdata->tempo = 125;
- sigdata->pan_separation = 128;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
- sigdata->channel_pan[i+0] = 16;
- sigdata->channel_pan[i+1] = 48;
- sigdata->channel_pan[i+2] = 48;
- sigdata->channel_pan[i+3] = 16;
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-
-
-DUH *dumb_read_mod_quick(DUMBFILE *f, int restrict)
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_mod_load_sigdata(f, restrict);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "MOD";
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readmod.c - Code to read a good old-fashioned / / \ \ + * Amiga module from an open file. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "dumb.h" +#include "internal/it.h" + + + +static int it_mod_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer) +{ + int pos; + int channel; + int row; + IT_ENTRY *entry; + + pattern->n_rows = 64; + + if (n_channels == 0) { + /* Read the first four channels, leaving gaps for the rest. */ + for (pos = 0; pos < 64*8*4; pos += 8*4) + dumbfile_getnc(buffer + pos, 4*4, f); + /* Read the other channels into the gaps we left. */ + for (pos = 4*4; pos < 64*8*4; pos += 8*4) + dumbfile_getnc(buffer + pos, 4*4, f); + + n_channels = 8; + } else + dumbfile_getnc(buffer, 64 * n_channels * 4, f); + + if (dumbfile_error(f)) + return -1; + + /* compute number of entries */ + pattern->n_entries = 64; /* Account for the row end markers */ + pos = 0; + for (row = 0; row < 64; row++) { + for (channel = 0; channel < n_channels; channel++) { + if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3]) + pattern->n_entries++; + pos += 4; + } + } + + pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); + if (!pattern->entry) + return -1; + + entry = pattern->entry; + pos = 0; + for (row = 0; row < 64; row++) { + for (channel = 0; channel < n_channels; channel++) { + if (buffer[pos+0] | buffer[pos+1] | buffer[pos+2] | buffer[pos+3]) { + unsigned char sample = (buffer[pos+0] & 0xF0) | (buffer[pos+2] >> 4); + int period = ((int)(buffer[pos+0] & 0x0F) << 8) | buffer[pos+1]; + + entry->channel = channel; + entry->mask = 0; + + if (period) { + int note; + entry->mask |= IT_ENTRY_NOTE; + + /* frequency = (AMIGA_DIVISOR / 8) / (period * 2) + * C-1: period = 214 -> frequency = 16726 + * so, set C5_speed to 16726 + * and period = 214 should translate to C5 aka 60 + * halve the period, go up an octive + * + * period = 214 / pow(DUMB_SEMITONE_BASE, note - 60) + * pow(DUMB_SEMITONE_BASE, note - 60) = 214 / period + * note - 60 = log(214/period) / log(DUMB_SEMITONE_BASE) + */ + note = (int)floor(log(214.0/period) / log(DUMB_SEMITONE_BASE) + 60.5); + entry->note = MID(0, note, 119); + // or should we preserve the period? + //entry->note = buffer[pos+0] & 0x0F; /* High nibble */ + //entry->volpan = buffer[pos+1]; /* Low byte */ + // and what about finetune? + } + + if (sample) { + entry->mask |= IT_ENTRY_INSTRUMENT; + entry->instrument = sample; + } + + _dumb_it_xm_convert_effect(buffer[pos+2] & 0x0F, buffer[pos+3], entry, 1); + + entry++; + } + pos += 4; + } + IT_SET_END_ROW(entry); + entry++; + } + + return 0; +} + + + +static int it_mod_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) +{ + int finetune, loop_start, loop_length; + +/** + 21 22 Chars Sample 1 name. If the name is not a full + 22 chars in length, it will be null + terminated. + +If +the sample name begins with a '#' character (ASCII $23 (35)) then this is +assumed not to be an instrument name, and is probably a message. +*/ + dumbfile_getnc(sample->name, 22, f); + sample->name[22] = 0; + + sample->filename[0] = 0; + + sample->length = dumbfile_mgetw(f) << 1; + finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */ +/** Each finetune step changes the note 1/8th of a semitone. */ + sample->global_volume = 64; + sample->default_volume = dumbfile_getc(f); // Should we be setting global_volume to this instead? + loop_start = dumbfile_mgetw(f) << 1; + loop_length = dumbfile_mgetw(f) << 1; + if ( loop_length > 2 && loop_start + loop_length > sample->length && loop_start / 2 + loop_length <= sample->length ) + loop_start /= 2; + sample->loop_start = loop_start; + sample->loop_end = loop_start + loop_length; +/** +Once this sample has been played completely from beginning +to end, if the repeat length (next field) is greater than two bytes it +will loop back to this position in the sample and continue playing. Once +it has played for the repeat length, it continues to loop back to the +repeat start offset. This means the sample continues playing until it is +told to stop. +*/ + + if (sample->length <= 0) { + sample->flags = 0; + return 0; + } + + sample->flags = IT_SAMPLE_EXISTS; + + sample->default_pan = 0; + sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 ); //(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32)); + sample->finetune = finetune * 32; + // the above line might be wrong + + if (sample->loop_end > sample->length) + sample->loop_end = sample->length; + + if (sample->loop_end - sample->loop_start > 2) + sample->flags |= IT_SAMPLE_LOOP; + + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = 0; // do we have to set _all_ these? + sample->max_resampling_quality = -1; + + return dumbfile_error(f); +} + + + +static int it_mod_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f, unsigned long fft) +{ + long i; + long truncated_size; + + /* let's get rid of the sample data coming after the end of the loop */ + if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) { + truncated_size = sample->length - sample->loop_end; + sample->length = sample->loop_end; + } else { + truncated_size = 0; + } + if (sample->length) { + sample->data = malloc(sample->length); + if (!sample->data) + return -1; + + /* Sample data are stored in "8-bit two's compliment format" (sic). */ + /* + for (i = 0; i < sample->length; i++) + ((signed char *)sample->left)[i] = dumbfile_getc(f); + */ + /* F U Olivier Lapicque */ + if (sample->length >= 5) + { + i = dumbfile_getnc(sample->data, 5, f); + if (i == 5) + { + if (!memcmp(sample->data, "ADPCM", 5)) + { + if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0) + return -1; + + return 0; + } + else + { + i += dumbfile_getnc(((char *)sample->data) + 5, sample->length - 5, f); + } + } + } + else + { + i = dumbfile_getnc(sample->data, sample->length, f); + } + if (i < sample->length) + { + if (i <= 0) + { + sample->flags = 0; + return 0; + } + sample->length = i; + if (sample->loop_end > i) sample->loop_end = i; + // holy crap! + if (sample->loop_start > i) sample->flags &= ~IT_SAMPLE_LOOP; + } + else + { + /* skip truncated data */ + int feh = dumbfile_error(f); + + if (truncated_size) dumbfile_skip(f, truncated_size); + // Should we be truncating it? + + if (feh) + return -1; + } + + if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) { + int delta = 0; + for (i = 0; i < sample->length; i++) { + delta += ((signed char *)sample->data)[i]; + ((signed char *)sample->data)[i] = delta; + } + } + } + + return 0; +} + + + +typedef struct BUFFERED_MOD BUFFERED_MOD; + +struct BUFFERED_MOD +{ + unsigned char *buffered; + long ptr, len; + DUMBFILE *remaining; +}; + + + +static int buffer_mod_skip(void *f, long n) +{ + BUFFERED_MOD *bm = f; + if (bm->buffered) { + bm->ptr += n; + if (bm->ptr >= bm->len) { + free(bm->buffered); + bm->buffered = NULL; + return dumbfile_skip(bm->remaining, bm->ptr - bm->len); + } + return 0; + } + return dumbfile_skip(bm->remaining, n); +} + + + +static int buffer_mod_getc(void *f) +{ + BUFFERED_MOD *bm = f; + if (bm->buffered) { + int rv = bm->buffered[bm->ptr++]; + if (bm->ptr >= bm->len) { + free(bm->buffered); + bm->buffered = NULL; + } + return rv; + } + return dumbfile_getc(bm->remaining); +} + + + +static long buffer_mod_getnc(char *ptr, long n, void *f) +{ + BUFFERED_MOD *bm = f; + if (bm->buffered) { + int left = bm->len - bm->ptr; + if (n >= left) { + memcpy(ptr, bm->buffered + bm->ptr, left); + free(bm->buffered); + bm->buffered = NULL; + if (n - left) { + int rv = dumbfile_getnc(ptr + left, n - left, bm->remaining); + return left + MAX(rv, 0); + } else { + return left; + } + } + memcpy(ptr, bm->buffered + bm->ptr, n); + bm->ptr += n; + return n; + } + return dumbfile_getnc(ptr, n, bm->remaining); +} + + + +static void buffer_mod_close(void *f) +{ + BUFFERED_MOD *bm = f; + if (bm->buffered) free(bm->buffered); + /* Do NOT close bm->remaining */ + free(f); +} + + + +DUMBFILE_SYSTEM buffer_mod_dfs = { + NULL, + &buffer_mod_skip, + &buffer_mod_getc, + &buffer_mod_getnc, + &buffer_mod_close +}; + + + +#define MOD_FFT_OFFSET (20 + 31*(22+2+1+1+2+2) + 1 + 1 + 128) + +static DUMBFILE *dumbfile_buffer_mod(DUMBFILE *f, unsigned long *fft) +{ + BUFFERED_MOD *bm = malloc(sizeof(*bm)); + if (!bm) return NULL; + + bm->buffered = malloc(MOD_FFT_OFFSET + 4); + if (!bm->buffered) { + free(bm); + return NULL; + } + + bm->len = dumbfile_getnc(bm->buffered, MOD_FFT_OFFSET + 4, f); + + if (bm->len > 0) { + if (bm->len >= MOD_FFT_OFFSET + 4) + *fft = (unsigned long)bm->buffered[MOD_FFT_OFFSET ] << 24 + | (unsigned long)bm->buffered[MOD_FFT_OFFSET+1] << 16 + | (unsigned long)bm->buffered[MOD_FFT_OFFSET+2] << 8 + | (unsigned long)bm->buffered[MOD_FFT_OFFSET+3]; + else + *fft = 0; + bm->ptr = 0; + } else { + free(bm->buffered); + bm->buffered = NULL; + } + + bm->remaining = f; + + return dumbfile_open_ex(bm, &buffer_mod_dfs); +} + +static DUMBFILE *dumbfile_buffer_mod_2(DUMBFILE *f, long *remain) +{ + long read; + BUFFERED_MOD *bm = malloc(sizeof(*bm)); + if (!bm) return NULL; + + bm->buffered = malloc(32768); + if (!bm->buffered) { + free(bm); + return NULL; + } + + bm->len = 0; + *remain = 0; + + read = dumbfile_getnc(bm->buffered, 32768, f); + + if (read >= 0) { + bm->len += read; + *remain += read; + + while (read >= 32768) { + bm->buffered = realloc(bm->buffered, *remain + 32768); + if (!bm->buffered) { + free(bm); + return 0; + } + read = dumbfile_getnc(bm->buffered + *remain, 32768, f); + if (read >= 0) { + bm->len += read; + *remain += read; + } + } + } + + if (*remain) { + bm->ptr = 0; + } else { + free(bm->buffered); + bm->buffered = NULL; + } + + bm->remaining = f; + + return dumbfile_open_ex(bm, &buffer_mod_dfs); +} + + +static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict) +{ + DUMB_IT_SIGDATA *sigdata; + int n_channels; + int i; + unsigned long fft = 0; + DUMBFILE *rem; + + f = dumbfile_buffer_mod(f, &fft); + if (!f) + return NULL; + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) { + dumbfile_close(f); + return NULL; + } + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) { + dumbfile_close(f); + return NULL; + } + + /** + 1 20 Chars Title of the song. If the title is not a + full 20 chars in length, it will be null- + terminated. + */ + if (dumbfile_getnc(sigdata->name, 20, f) < 20) { + free(sigdata); + dumbfile_close(f); + return NULL; + } + sigdata->name[20] = 0; + + sigdata->n_samples = 31; + + switch (fft) { + case DUMB_ID('M','.','K','.'): + case DUMB_ID('M','!','K','!'): + case DUMB_ID('M','&','K','!'): + case DUMB_ID('N','.','T','.'): + case DUMB_ID('N','S','M','S'): + case DUMB_ID('F','L','T','4'): + case DUMB_ID('M',0,0,0): + case DUMB_ID('8',0,0,0): + n_channels = 4; + break; + case DUMB_ID('F','L','T','8'): + n_channels = 0; + /* 0 indicates a special case; two four-channel patterns must be + * combined into one eight-channel pattern. Pattern indexes must + * be halved. Why oh why do they obfuscate so? + */ + /*for (i = 0; i < 128; i++) + sigdata->order[i] >>= 1;*/ + break; + case DUMB_ID('C','D','8','1'): + case DUMB_ID('O','C','T','A'): + case DUMB_ID('O','K','T','A'): + n_channels = 8; + break; + case DUMB_ID('1','6','C','N'): + n_channels = 16; + break; + case DUMB_ID('3','2','C','N'): + n_channels = 32; + break; + default: + /* If we get an illegal tag, assume 4 channels 15 samples. */ + if ((fft & 0x0000FFFFL) == DUMB_ID(0,0,'C','H')) { + if (fft >= '1' << 24 && fft < '4' << 24) { + n_channels = ((fft & 0x00FF0000L) >> 16) - '0'; + if ((unsigned int)n_channels >= 10) { + /* Rightmost character wasn't a digit. */ + n_channels = 4; + sigdata->n_samples = 15; + } else { + n_channels += (((fft & 0xFF000000L) >> 24) - '0') * 10; + /* MODs should really only go up to 32 channels, but we're lenient. */ + if ((unsigned int)(n_channels - 1) >= DUMB_IT_N_CHANNELS - 1) { + /* No channels or too many? Can't be right... */ + n_channels = 4; + sigdata->n_samples = 15; + } + } + } else { + n_channels = 4; + sigdata->n_samples = 15; + } + } else if ((fft & 0x00FFFFFFL) == DUMB_ID(0,'C','H','N')) { + n_channels = (fft >> 24) - '0'; + if ((unsigned int)(n_channels - 1) >= 9) { + /* Character was '0' or it wasn't a digit */ + n_channels = 4; + sigdata->n_samples = 15; + } + } else if ((fft & 0xFFFFFF00L) == DUMB_ID('T','D','Z',0)) { + n_channels = (fft & 0x000000FFL) - '0'; + if ((unsigned int)(n_channels - 1) >= 9) { + /* We've been very lenient, given that it should have + * been 1, 2 or 3, but this MOD has been very naughty and + * must be punished. + */ + n_channels = 4; + sigdata->n_samples = 15; + } + } else { + n_channels = 4; + sigdata->n_samples = 15; + } + } + + // moo + if ( restrict && sigdata->n_samples == 15 ) + { + free(sigdata); + dumbfile_close(f); + return NULL; + } + + sigdata->n_pchannels = n_channels ? n_channels : 8; /* special case for 0, see above */ + + sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); + if (!sigdata->sample) { + free(sigdata); + dumbfile_close(f); + return NULL; + } + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->n_instruments = 0; + + for (i = 0; i < sigdata->n_samples; i++) + sigdata->sample[i].data = NULL; + + for (i = 0; i < sigdata->n_samples; i++) { + if (it_mod_read_sample_header(&sigdata->sample[i], f)) { + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + return NULL; + } + } + + sigdata->n_orders = dumbfile_getc(f); + sigdata->restart_position = dumbfile_getc(f); + // what if this is >= 127? what about with Fast Tracker II? + +/* if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right? + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + return NULL; + }*/ + + //if (sigdata->restart_position >= sigdata->n_orders) + //sigdata->restart_position = 0; + + sigdata->order = malloc(128); /* We may need to scan the extra ones! */ + if (!sigdata->order) { + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + return NULL; + } + if (dumbfile_getnc(sigdata->order, 128, f) < 128) { + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + return NULL; + } + + if (sigdata->n_orders <= 0 || sigdata->n_orders > 128) { // is this right? + sigdata->n_orders = 128; + //while (sigdata->n_orders > 1 && !sigdata->order[sigdata->n_orders - 1]) sigdata->n_orders--; + } + + if ( ! n_channels ) + for (i = 0; i < 128; i++) + sigdata->order[i] >>= 1; + + /* "The old NST format contains only 15 samples (instead of 31). Further + * it doesn't contain a file format tag (id). So Pattern data offset is + * at 20+15*30+1+1+128." + * - Then I shall assume the File Format Tag never exists if there are + * only 15 samples. I hope this isn't a faulty assumption... + */ + if (sigdata->n_samples == 31) + dumbfile_skip(f, 4); + + /* Work out how many patterns there are. */ + sigdata->n_patterns = -1; + for (i = 0; i < 128; i++) + if (sigdata->n_patterns < sigdata->order[i]) + sigdata->n_patterns = sigdata->order[i]; + sigdata->n_patterns++; + + /* May as well try to save a tiny bit of memory. */ + if (sigdata->n_orders < 128) { + unsigned char *order = realloc(sigdata->order, sigdata->n_orders); + if (order) sigdata->order = order; + } + + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) { + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + return NULL; + } + for (i = 0; i < sigdata->n_patterns; i++) + sigdata->pattern[i].entry = NULL; + + /* Read in the patterns */ + { + unsigned char *buffer = malloc(256 * n_channels); /* 64 rows * 4 bytes */ + if (!buffer) { + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + return NULL; + } + for (i = 0; i < sigdata->n_patterns; i++) { + if (it_mod_read_pattern(&sigdata->pattern[i], f, n_channels, buffer) != 0) { + free(buffer); + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + return NULL; + } + } + free(buffer); + } + + rem = NULL; + + /* uggly */ + if (fft == DUMB_ID('M',0,0,0) || fft == DUMB_ID('8',0,0,0)) { + long skip; + long remain; + rem = f; + f = dumbfile_buffer_mod_2(rem, &remain); + if (!f) { + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(rem); + return NULL; + } + for (skip = 0, i = 0; i < sigdata->n_samples; i++) { + if (sigdata->sample[i].flags & IT_SAMPLE_EXISTS) { + skip += sigdata->sample[i].length; + } + } + if (remain - skip) { + if (dumbfile_skip(f, remain - skip)) { + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + dumbfile_close(rem); + return NULL; + } + } + } + + /* And finally, the sample data */ + for (i = 0; i < sigdata->n_samples; i++) { + if (it_mod_read_sample_data(&sigdata->sample[i], f, fft)) { + _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + if (rem) dumbfile_close(rem); + return NULL; + } + } + + /* w00t! */ + /*if ( n_channels == 4 && + ( sigdata->n_samples == 15 || + ( ( fft & 240 ) != DUMB_ID( 0, 0, 'C', 0 ) && + ( fft & 240 ) != DUMB_ID( 0, 0, 'H', 0 ) && + ( fft & 240 ) != 0 ) ) ) { + for ( i = 0; i < sigdata->n_samples; ++i ) { + IT_SAMPLE * sample = &sigdata->sample [i]; + if ( sample && ( sample->flags & IT_SAMPLE_EXISTS ) ) { + int n, o; + o = sample->length; + if ( o > 4 ) o = 4; + for ( n = 0; n < o; ++n ) + ( ( char * ) sample->data ) [n] = 0; + } + } + }*/ + + dumbfile_close(f); /* Destroy the BUFFERED_MOD DUMBFILE we were using. */ + /* The DUMBFILE originally passed to our function is intact. */ + if (rem) dumbfile_close(rem); + + /* Now let's initialise the remaining variables, and we're done! */ + sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO; + + sigdata->global_volume = 128; + sigdata->mixing_volume = 48; + /* We want 50 ticks per second; 50/6 row advances per second; + * 50*10=500 row advances per minute; 500/4=125 beats per minute. + */ + sigdata->speed = 6; + sigdata->tempo = 125; + sigdata->pan_separation = 128; + + memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); + + for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) { + sigdata->channel_pan[i+0] = 16; + sigdata->channel_pan[i+1] = 48; + sigdata->channel_pan[i+2] = 48; + sigdata->channel_pan[i+3] = 16; + } + + _dumb_it_fix_invalid_orders(sigdata); + + return sigdata; +} + +DUH *dumb_read_mod_quick(DUMBFILE *f, int restrict) +{ + sigdata_t *sigdata; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_mod_load_sigdata(f, restrict); + + if (!sigdata) + return NULL; + + { + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = "MOD"; + return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/readmod2.c b/plugins/dumb/dumb-kode54/src/it/readmod2.c index a22548a1..102ead12 100644 --- a/plugins/dumb/dumb-kode54/src/it/readmod2.c +++ b/plugins/dumb/dumb-kode54/src/it/readmod2.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readmod2.c - Function to read a good old- / / \ \
- * fashioned Amiga module from an | < / \_
- * open file and do an initial | \/ /\ /
- * run-through. \_ / > /
- * | \ / /
- * Split off from readmod.c by entheh. | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_read_mod(DUMBFILE *f, int restrict)
-{
- DUH *duh = dumb_read_mod_quick(f, restrict);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readmod2.c - Function to read a good old- / / \ \ + * fashioned Amiga module from an | < / \_ + * open file and do an initial | \/ /\ / + * run-through. \_ / > / + * | \ / / + * Split off from readmod.c by entheh. | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_read_mod(DUMBFILE *f, int restrict) +{ + DUH *duh = dumb_read_mod_quick(f, restrict); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/readmtm.c b/plugins/dumb/dumb-kode54/src/it/readmtm.c index 8f0c2e4c..4e8e5dca 100644 --- a/plugins/dumb/dumb-kode54/src/it/readmtm.c +++ b/plugins/dumb/dumb-kode54/src/it/readmtm.c @@ -1,412 +1,412 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readmtm.c - Code to read a MultiTracker Module / / \ \
- * from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-size_t strlen_max(const char * ptr, size_t max)
-{
- const char * end, * start;
- if (ptr==0) return 0;
- start = ptr;
- end = ptr + max;
- while(*ptr && ptr < end) ptr++;
- return ptr - start;
-}
-
-static int it_mtm_assemble_pattern(IT_PATTERN *pattern, const unsigned char * track, const unsigned short * sequence, int n_rows)
-{
- int n, o, note, sample;
- const unsigned char * t;
- IT_ENTRY * entry;
-
- pattern->n_rows = n_rows;
- pattern->n_entries = n_rows;
-
- for (n = 0; n < 32; n++) {
- if (sequence[n]) {
- t = &track[192 * (sequence[n] - 1)];
- for (o = 0; o < n_rows; o++) {
- if (t[0] || t[1] || t[2]) pattern->n_entries++;
- t += 3;
- }
- }
- }
-
- entry = malloc(pattern->n_entries * sizeof(*entry));
- if (!entry) return -1;
- pattern->entry = entry;
-
- for (n = 0; n < n_rows; n++) {
- for (o = 0; o < 32; o++) {
- if (sequence[o]) {
- t = &track[192 * (sequence[o] - 1) + (n * 3)];
- if (t[0] || t[1] || t[2]) {
- entry->channel = o;
- entry->mask = 0;
- note = t[0] >> 2;
- sample = ((t[0] << 4) | (t[1] >> 4)) & 0x3F;
-
- if (note) {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = note + 24;
- }
-
- if (sample) {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = sample;
- }
-
- _dumb_it_xm_convert_effect(t[1] & 0xF, t[2], entry, 1);
-
- if (entry->mask) entry++;
- }
- }
- }
- IT_SET_END_ROW(entry);
- entry++;
- }
-
- pattern->n_entries = entry - pattern->entry;
-
- return 0;
-}
-
-static int it_mtm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
-{
- int finetune, flags;
-
- dumbfile_getnc(sample->name, 22, f);
- sample->name[22] = 0;
-
- sample->filename[0] = 0;
-
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = dumbfile_igetl(f);
- finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */
- sample->global_volume = 64;
- sample->default_volume = dumbfile_getc(f);
-
- flags = dumbfile_getc(f);
-
- if (sample->length <= 0) {
- sample->flags = 0;
- return 0;
- }
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- if (flags & 1) {
- sample->flags |= IT_SAMPLE_16BIT;
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- }
-
- sample->default_pan = 0;
- sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32));
- sample->finetune = finetune * 32;
- // the above line might be wrong
-
- if (sample->loop_end > sample->length)
- sample->loop_end = sample->length;
-
- if (sample->loop_end - sample->loop_start > 2)
- sample->flags |= IT_SAMPLE_LOOP;
-
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = 0; // do we have to set _all_ these?
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-static int it_mtm_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f)
-{
- long i;
- long truncated_size;
-
- /* let's get rid of the sample data coming after the end of the loop */
- if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) {
- truncated_size = sample->length - sample->loop_end;
- sample->length = sample->loop_end;
- } else {
- truncated_size = 0;
- }
-
- sample->data = malloc(sample->length);
-
- if (!sample->data)
- return -1;
-
- dumbfile_getnc((char *)sample->data, sample->length, f);
- dumbfile_skip(f, truncated_size);
-
- if (dumbfile_error(f))
- return -1;
-
- for (i = 0; i < sample->length; i++)
- ((signed char *)sample->data)[i] ^= 0x80;
-
- return 0;
-}
-
-static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int n, o, n_tracks, l_comment, n_rows, n_channels;
-
- unsigned char * track;
-
- unsigned short * sequence;
-
- char * comment;
-
- if (dumbfile_getc(f) != 'M' ||
- dumbfile_getc(f) != 'T' ||
- dumbfile_getc(f) != 'M') goto error;
-
- *version = dumbfile_getc(f);
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) goto error;
-
- dumbfile_getnc(sigdata->name, 20, f);
- sigdata->name[20] = 0;
-
- n_tracks = dumbfile_igetw(f);
- sigdata->n_patterns = dumbfile_getc(f) + 1;
- sigdata->n_orders = dumbfile_getc(f) + 1;
- l_comment = dumbfile_igetw(f);
- sigdata->n_samples = dumbfile_getc(f);
- //if (dumbfile_getc(f)) goto error_sd;
- dumbfile_getc(f);
- n_rows = dumbfile_getc(f);
- n_channels = dumbfile_getc(f);
-
- if (dumbfile_error(f) ||
- (n_tracks <= 0) ||
- (sigdata->n_samples <= 0) ||
- (n_rows <= 0 || n_rows > 64) ||
- (n_channels <= 0 || n_channels > 32)) goto error_sd;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- if (dumbfile_getnc(sigdata->channel_pan, 32, f) < 32) goto error_sd;
-
- for (n = 0; n < 32; n++) {
- if (sigdata->channel_pan[n] <= 15) {
- sigdata->channel_pan[n] -= (sigdata->channel_pan[n] & 8) >> 3;
- sigdata->channel_pan[n] = (sigdata->channel_pan[n] * 32) / 7;
- } else {
- sigdata->channel_volume[n] = 0;
- sigdata->channel_pan[n] = 7;
- }
- }
-
- for (n = 32; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) goto error_sd;
-
- sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
-
- sigdata->global_volume = 128;
- sigdata->mixing_volume = 48;
- sigdata->speed = 6;
- sigdata->tempo = 125;
- sigdata->pan_separation = 128;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
-
- sigdata->restart_position = 0;
- sigdata->n_pchannels = n_channels;
-
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
-
- for (n = 0; n < sigdata->n_samples; n++) {
- if (it_mtm_read_sample_header(&sigdata->sample[n], f)) goto error_usd;
- }
-
- sigdata->order = malloc(sigdata->n_orders);
- if (!sigdata->order) goto error_usd;
-
- if (dumbfile_getnc(sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_usd;
- if (sigdata->n_orders < 128)
- if (dumbfile_skip(f, 128 - sigdata->n_orders)) goto error_usd;
-
- track = malloc(192 * n_tracks);
- if (!track) goto error_usd;
-
- if (dumbfile_getnc(track, 192 * n_tracks, f) < 192 * n_tracks) goto error_ft;
-
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) goto error_ft;
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
-
- sequence = malloc(sigdata->n_patterns * 32 * sizeof(*sequence));
- if (!sequence) goto error_ft;
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- for (o = 0; o < 32; o++) {
- sequence[(n * 32) + o] = dumbfile_igetw(f);
- if (sequence[(n * 32) + o] > n_tracks)
- {
- //goto error_fs;
- // illegal track number, silence instead of rejecting the file
- sequence[(n * 32) + o] = 0;
- }
- }
- }
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- if (it_mtm_assemble_pattern(&sigdata->pattern[n], track, &sequence[n * 32], n_rows)) goto error_fs;
- }
-
- if (l_comment) {
- comment = malloc(l_comment);
- if (!comment) goto error_fs;
- if (dumbfile_getnc(comment, l_comment, f) < l_comment) goto error_fc;
-
- /* Time for annoying "logic", yes. We want each line which has text,
- * and each blank line in between all the valid lines.
- */
-
- /* Find last actual line. */
- for (o = -1, n = 0; n < l_comment; n += 40) {
- if (comment[n]) o = n;
- }
-
- if (o >= 0) {
-
- int l, m;
-
- for (l = 0, n = 0; n <= o; n += 40) {
- l += strlen_max(&comment[n], 40) + 2;
- }
-
- l -= 1;
-
- sigdata->song_message = malloc(l);
- if (!sigdata->song_message) goto error_fc;
-
- for (m = 0, n = 0; n <= o; n += 40) {
- int p = strlen_max(&comment[n], 40);
- if (p) {
- memcpy(sigdata->song_message + m, &comment[n], p);
- m += p;
- }
- if (l - m > 1) {
- sigdata->song_message[m++] = 13;
- sigdata->song_message[m++] = 10;
- }
- }
-
- sigdata->song_message[m] = 0;
- }
-
- free(comment);
- }
-
- for (n = 0; n < sigdata->n_samples; n++) {
- if (it_mtm_read_sample_data(&sigdata->sample[n], f)) goto error_fs;
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- free(sequence);
- free(track);
-
- return sigdata;
-
-error_fc:
- free(comment);
-error_fs:
- free(sequence);
-error_ft:
- free(track);
-error_usd:
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
-
-error_sd:
- free(sigdata);
-error:
- return NULL;
-}
-
-static char hexdigit(int in)
-{
- if (in < 10) return in + '0';
- else return in + 'A' - 10;
-}
-
-DUH *dumb_read_mtm_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
- int ver;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_mtm_load_sigdata(f, &ver);
-
- if (!sigdata)
- return NULL;
-
- {
- char version[16];
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- version[0] = 'M';
- version[1] = 'T';
- version[2] = 'M';
- version[3] = ' ';
- version[4] = 'v';
- version[5] = hexdigit(ver >> 4);
- version[6] = '.';
- version[7] = hexdigit(ver & 15);
- version[8] = 0;
- tag[1][1] = (const char *) &version;
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readmtm.c - Code to read a MultiTracker Module / / \ \ + * from an open file. | < / \_ + * | \/ /\ / + * By Chris Moeller. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "dumb.h" +#include "internal/it.h" + +size_t strlen_max(const char * ptr, size_t max) +{ + const char * end, * start; + if (ptr==0) return 0; + start = ptr; + end = ptr + max; + while(*ptr && ptr < end) ptr++; + return ptr - start; +} + +static int it_mtm_assemble_pattern(IT_PATTERN *pattern, const unsigned char * track, const unsigned short * sequence, int n_rows) +{ + int n, o, note, sample; + const unsigned char * t; + IT_ENTRY * entry; + + pattern->n_rows = n_rows; + pattern->n_entries = n_rows; + + for (n = 0; n < 32; n++) { + if (sequence[n]) { + t = &track[192 * (sequence[n] - 1)]; + for (o = 0; o < n_rows; o++) { + if (t[0] || t[1] || t[2]) pattern->n_entries++; + t += 3; + } + } + } + + entry = malloc(pattern->n_entries * sizeof(*entry)); + if (!entry) return -1; + pattern->entry = entry; + + for (n = 0; n < n_rows; n++) { + for (o = 0; o < 32; o++) { + if (sequence[o]) { + t = &track[192 * (sequence[o] - 1) + (n * 3)]; + if (t[0] || t[1] || t[2]) { + entry->channel = o; + entry->mask = 0; + note = t[0] >> 2; + sample = ((t[0] << 4) | (t[1] >> 4)) & 0x3F; + + if (note) { + entry->mask |= IT_ENTRY_NOTE; + entry->note = note + 24; + } + + if (sample) { + entry->mask |= IT_ENTRY_INSTRUMENT; + entry->instrument = sample; + } + + _dumb_it_xm_convert_effect(t[1] & 0xF, t[2], entry, 1); + + if (entry->mask) entry++; + } + } + } + IT_SET_END_ROW(entry); + entry++; + } + + pattern->n_entries = entry - pattern->entry; + + return 0; +} + +static int it_mtm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) +{ + int finetune, flags; + + dumbfile_getnc(sample->name, 22, f); + sample->name[22] = 0; + + sample->filename[0] = 0; + + sample->length = dumbfile_igetl(f); + sample->loop_start = dumbfile_igetl(f); + sample->loop_end = dumbfile_igetl(f); + finetune = (signed char)(dumbfile_getc(f) << 4) >> 4; /* signed nibble */ + sample->global_volume = 64; + sample->default_volume = dumbfile_getc(f); + + flags = dumbfile_getc(f); + + if (sample->length <= 0) { + sample->flags = 0; + return 0; + } + + sample->flags = IT_SAMPLE_EXISTS; + + if (flags & 1) { + sample->flags |= IT_SAMPLE_16BIT; + sample->length >>= 1; + sample->loop_start >>= 1; + sample->loop_end >>= 1; + } + + sample->default_pan = 0; + sample->C5_speed = (int)( AMIGA_CLOCK / 214.0 );//(long)(16726.0*pow(DUMB_PITCH_BASE, finetune*32)); + sample->finetune = finetune * 32; + // the above line might be wrong + + if (sample->loop_end > sample->length) + sample->loop_end = sample->length; + + if (sample->loop_end - sample->loop_start > 2) + sample->flags |= IT_SAMPLE_LOOP; + + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = 0; // do we have to set _all_ these? + sample->max_resampling_quality = -1; + + return dumbfile_error(f); +} + +static int it_mtm_read_sample_data(IT_SAMPLE *sample, DUMBFILE *f) +{ + long i; + long truncated_size; + + /* let's get rid of the sample data coming after the end of the loop */ + if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length) { + truncated_size = sample->length - sample->loop_end; + sample->length = sample->loop_end; + } else { + truncated_size = 0; + } + + sample->data = malloc(sample->length); + + if (!sample->data) + return -1; + + dumbfile_getnc((char *)sample->data, sample->length, f); + dumbfile_skip(f, truncated_size); + + if (dumbfile_error(f)) + return -1; + + for (i = 0; i < sample->length; i++) + ((signed char *)sample->data)[i] ^= 0x80; + + return 0; +} + +static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version) +{ + DUMB_IT_SIGDATA *sigdata; + + int n, o, n_tracks, l_comment, n_rows, n_channels; + + unsigned char * track; + + unsigned short * sequence; + + char * comment; + + if (dumbfile_getc(f) != 'M' || + dumbfile_getc(f) != 'T' || + dumbfile_getc(f) != 'M') goto error; + + *version = dumbfile_getc(f); + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) goto error; + + dumbfile_getnc(sigdata->name, 20, f); + sigdata->name[20] = 0; + + n_tracks = dumbfile_igetw(f); + sigdata->n_patterns = dumbfile_getc(f) + 1; + sigdata->n_orders = dumbfile_getc(f) + 1; + l_comment = dumbfile_igetw(f); + sigdata->n_samples = dumbfile_getc(f); + //if (dumbfile_getc(f)) goto error_sd; + dumbfile_getc(f); + n_rows = dumbfile_getc(f); + n_channels = dumbfile_getc(f); + + if (dumbfile_error(f) || + (n_tracks <= 0) || + (sigdata->n_samples <= 0) || + (n_rows <= 0 || n_rows > 64) || + (n_channels <= 0 || n_channels > 32)) goto error_sd; + + memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); + + if (dumbfile_getnc(sigdata->channel_pan, 32, f) < 32) goto error_sd; + + for (n = 0; n < 32; n++) { + if (sigdata->channel_pan[n] <= 15) { + sigdata->channel_pan[n] -= (sigdata->channel_pan[n] & 8) >> 3; + sigdata->channel_pan[n] = (sigdata->channel_pan[n] * 32) / 7; + } else { + sigdata->channel_volume[n] = 0; + sigdata->channel_pan[n] = 7; + } + } + + for (n = 32; n < DUMB_IT_N_CHANNELS; n += 4) { + sigdata->channel_pan[n ] = 16; + sigdata->channel_pan[n+1] = 48; + sigdata->channel_pan[n+2] = 48; + sigdata->channel_pan[n+3] = 16; + } + + sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); + if (!sigdata->sample) goto error_sd; + + sigdata->flags = IT_WAS_AN_XM | IT_WAS_A_MOD | IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX; + + sigdata->global_volume = 128; + sigdata->mixing_volume = 48; + sigdata->speed = 6; + sigdata->tempo = 125; + sigdata->pan_separation = 128; + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->n_instruments = 0; + + sigdata->restart_position = 0; + sigdata->n_pchannels = n_channels; + + for (n = 0; n < sigdata->n_samples; n++) + sigdata->sample[n].data = NULL; + + for (n = 0; n < sigdata->n_samples; n++) { + if (it_mtm_read_sample_header(&sigdata->sample[n], f)) goto error_usd; + } + + sigdata->order = malloc(sigdata->n_orders); + if (!sigdata->order) goto error_usd; + + if (dumbfile_getnc(sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_usd; + if (sigdata->n_orders < 128) + if (dumbfile_skip(f, 128 - sigdata->n_orders)) goto error_usd; + + track = malloc(192 * n_tracks); + if (!track) goto error_usd; + + if (dumbfile_getnc(track, 192 * n_tracks, f) < 192 * n_tracks) goto error_ft; + + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) goto error_ft; + for (n = 0; n < sigdata->n_patterns; n++) + sigdata->pattern[n].entry = NULL; + + sequence = malloc(sigdata->n_patterns * 32 * sizeof(*sequence)); + if (!sequence) goto error_ft; + + for (n = 0; n < sigdata->n_patterns; n++) { + for (o = 0; o < 32; o++) { + sequence[(n * 32) + o] = dumbfile_igetw(f); + if (sequence[(n * 32) + o] > n_tracks) + { + //goto error_fs; + // illegal track number, silence instead of rejecting the file + sequence[(n * 32) + o] = 0; + } + } + } + + for (n = 0; n < sigdata->n_patterns; n++) { + if (it_mtm_assemble_pattern(&sigdata->pattern[n], track, &sequence[n * 32], n_rows)) goto error_fs; + } + + if (l_comment) { + comment = malloc(l_comment); + if (!comment) goto error_fs; + if (dumbfile_getnc(comment, l_comment, f) < l_comment) goto error_fc; + + /* Time for annoying "logic", yes. We want each line which has text, + * and each blank line in between all the valid lines. + */ + + /* Find last actual line. */ + for (o = -1, n = 0; n < l_comment; n += 40) { + if (comment[n]) o = n; + } + + if (o >= 0) { + + int l, m; + + for (l = 0, n = 0; n <= o; n += 40) { + l += strlen_max(&comment[n], 40) + 2; + } + + l -= 1; + + sigdata->song_message = malloc(l); + if (!sigdata->song_message) goto error_fc; + + for (m = 0, n = 0; n <= o; n += 40) { + int p = strlen_max(&comment[n], 40); + if (p) { + memcpy(sigdata->song_message + m, &comment[n], p); + m += p; + } + if (l - m > 1) { + sigdata->song_message[m++] = 13; + sigdata->song_message[m++] = 10; + } + } + + sigdata->song_message[m] = 0; + } + + free(comment); + } + + for (n = 0; n < sigdata->n_samples; n++) { + if (it_mtm_read_sample_data(&sigdata->sample[n], f)) goto error_fs; + } + + _dumb_it_fix_invalid_orders(sigdata); + + free(sequence); + free(track); + + return sigdata; + +error_fc: + free(comment); +error_fs: + free(sequence); +error_ft: + free(track); +error_usd: + _dumb_it_unload_sigdata(sigdata); + return NULL; + +error_sd: + free(sigdata); +error: + return NULL; +} + +static char hexdigit(int in) +{ + if (in < 10) return in + '0'; + else return in + 'A' - 10; +} + +DUH *dumb_read_mtm_quick(DUMBFILE *f) +{ + sigdata_t *sigdata; + int ver; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_mtm_load_sigdata(f, &ver); + + if (!sigdata) + return NULL; + + { + char version[16]; + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + version[0] = 'M'; + version[1] = 'T'; + version[2] = 'M'; + version[3] = ' '; + version[4] = 'v'; + version[5] = hexdigit(ver >> 4); + version[6] = '.'; + version[7] = hexdigit(ver & 15); + version[8] = 0; + tag[1][1] = (const char *) &version; + return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/readoldpsm.c b/plugins/dumb/dumb-kode54/src/it/readoldpsm.c index e7830f2a..1b60187e 100644 --- a/plugins/dumb/dumb-kode54/src/it/readoldpsm.c +++ b/plugins/dumb/dumb-kode54/src/it/readoldpsm.c @@ -1,727 +1,727 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readpsm.c - Code to read an old Protracker / / \ \
- * Studio module from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-static int psm_sample_compare(const void *e1, const void *e2)
-{
- const unsigned char * pa = e1;
- const unsigned char * pb = e2;
- int a = pa[37] | (pa[38] << 8) | (pa[39] << 16) | (pa[40] << 24);
- int b = pb[37] | (pb[38] << 8) | (pb[39] << 16) | (pb[40] << 24);
- return a - b;
-}
-
-static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num, const unsigned char * prebuffer, long data_pos, long data_size)
-{
- int n, o, pos, count = *num, true_num, snum, offset, flags, finetune, delta;
-
- unsigned char * buffer, * sbuffer = 0;
- const unsigned char * sdata;
-
- buffer = malloc(count * 64);
- if (!buffer) goto error;
-
- if (dumbfile_getnc(buffer, count * 64, f) < count * 64) goto error_fb;
-
- pos = dumbfile_pos(f);
-
- true_num = 0;
-
- for (n = 0; n < count; n++) {
- snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8);
- if ((snum < 1) || (snum > 255)) goto error_fb;
- if (true_num < snum) true_num = snum;
- }
-
- if (true_num > count) {
- IT_SAMPLE * meh = realloc(*sample, true_num * sizeof(*meh));
- if (!meh) goto error_fb;
- for (n = count; n < true_num; n++) {
- meh[n].data = NULL;
- }
- *sample = meh;
- *num = true_num;
- }
-
- qsort(buffer, count, 64, &psm_sample_compare);
-
- for (n = 0; n < true_num; n++) {
- (*sample)[n].flags = 0;
- }
-
- for (n = 0; n < count; n++) {
- IT_SAMPLE * s;
- snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8);
- s = &((*sample)[snum - 1]);
- memcpy(s->filename, buffer + (n * 64), 13);
- s->filename[13] = 0;
- memcpy(s->name, buffer + (n * 64) + 13, 24);
- s->name[24] = 0;
- offset = buffer[(n * 64) + 37] | (buffer[(n * 64) + 38] << 8) |
- (buffer[(n * 64) + 39] << 16) | (buffer[(n * 64) + 40] << 24);
- flags = buffer[(n * 64) + 47];
- s->length = buffer[(n * 64) + 48] | (buffer[(n * 64) + 49] << 8) |
- (buffer[(n * 64) + 50] << 16) | (buffer[(n * 64) + 51] << 24);
- s->loop_start = buffer[(n * 64) + 52] | (buffer[(n * 64) + 53] << 8) |
- (buffer[(n * 64) + 54] << 16) | (buffer[(n * 64) + 55] << 24);
- s->loop_end = buffer[(n * 64) + 56] | (buffer[(n * 64) + 57] << 8) |
- (buffer[(n * 64) + 58] << 16) | (buffer[(n * 64) + 59] << 24);
-
- if (s->length <= 0) continue;
-
- finetune = buffer[(n * 64) + 60];
- s->default_volume = buffer[(n * 64) + 61];
- s->C5_speed = buffer[(n * 64) + 62] | (buffer[(n * 64) + 63] << 8);
- if (finetune < 16) {
- if (finetune >= 8) finetune -= 16;
- //s->C5_speed = (long)((double)s->C5_speed * pow(DUMB_PITCH_BASE, finetune*32));
- s->finetune = finetune * 32;
- }
- else s->finetune = 0;
-
- s->flags |= IT_SAMPLE_EXISTS;
- if (flags & 0x41) {
- s->flags &= ~IT_SAMPLE_EXISTS;
- continue;
- }
- if (flags & 0x20) s->flags |= IT_SAMPLE_PINGPONG_LOOP;
- if (flags & 4) s->flags |= IT_SAMPLE_16BIT;
-
- if (flags & 0x80) {
- s->flags |= IT_SAMPLE_LOOP;
- if ((unsigned int)s->loop_end > (unsigned int)s->length)
- s->loop_end = s->length;
- else if ((unsigned int)s->loop_start >= (unsigned int)s->loop_end)
- s->flags &= ~IT_SAMPLE_LOOP;
- else
- s->length = s->loop_end;
- }
-
- s->global_volume = 64;
-
- s->vibrato_speed = 0;
- s->vibrato_depth = 0;
- s->vibrato_rate = 0;
- s->vibrato_waveform = IT_VIBRATO_SINE;
- s->max_resampling_quality = -1;
-
- s->data = malloc(s->length * ((flags & 4) ? 2 : 1));
- if (!s->data) goto error_fb;
-
- if ((offset >= data_pos) &&
- ((offset + s->length * ((flags & 4) ? 2 : 1)) <= (data_pos + data_size))) {
- sdata = prebuffer + offset - data_pos;
- } else if (offset >= pos) {
- if (dumbfile_skip(f, offset - pos)) goto error_fb;
- pos = offset;
- offset = s->length * ((flags & 4) ? 2 : 1);
- sbuffer = malloc(offset);
- if (!sbuffer) goto error_fb;
- if (dumbfile_getnc(sbuffer, offset, f) < offset) goto error_fsb;
- sdata = sbuffer;
- } else
- goto error_fb;
-
- if (flags & 0x10) {
- if (flags & 8) {
- if (flags & 4) {
- for (o = 0; o < s->length; o++)
- ((short *)s->data)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000;
- } else {
- for (o = 0; o < s->length; o++)
- ((signed char *)s->data)[o] = sdata[o] ^ 0x80;
- }
- } else {
- if (flags & 4) {
- for (o = 0; o < s->length; o++)
- ((short *)s->data)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8);
- } else {
- memcpy(s->data, sdata, s->length);
- }
- }
- } else {
- delta = 0;
- if (flags & 8) {
- /* unsigned delta? mehhh, does anything even use this? */
- if (flags & 4) {
- for (o = 0; o < s->length; o++) {
- delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8));
- ((short *)s->data)[o] = delta ^ 0x8000;
- }
- } else {
- for (o = 0; o < s->length; o++) {
- delta += (signed char)sdata[o];
- ((signed char *)s->data)[o] = delta ^ 0x80;
- }
- }
- } else {
- if (flags & 4) {
- for (o = 0; o < s->length; o++) {
- delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8));
- ((short *)s->data)[o] = delta;
- }
- } else {
- for (o = 0; o < s->length; o++) {
- delta += (signed char)sdata[o];
- ((signed char *)s->data)[o] = delta;
- }
- }
- }
- }
-
- if (sbuffer) {
- free(sbuffer);
- sbuffer = 0;
- }
- }
-
- free(buffer);
-
- return 0;
-
-error_fsb:
- if (sbuffer) free(sbuffer);
-error_fb:
- free(buffer);
-error:
- return -1;
-}
-
-static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num, int size, int pchans, int sflags)
-{
- int n, offset, psize, rows, chans, row, flags, channel;
-
- unsigned char * buffer, * ptr, * end;
-
- IT_ENTRY * entry;
-
- buffer = malloc(size);
- if (!buffer) goto error;
-
- if (dumbfile_getnc(buffer, size, f) < size) goto error_fb;
-
- offset = 0;
-
- for (n = 0; n < num; n++) {
- IT_PATTERN * p = &pattern[n];
-
- if (offset >= size) goto error_fb;
-
- ptr = buffer + offset;
- psize = ptr[0] | (ptr[1] << 8);
- rows = ptr[2];
- chans = ptr[3];
-
- if (!rows || !chans) {
- p->n_rows = 1;
- p->n_entries = 0;
- continue;
- }
-
- psize = (psize + 15) & ~15;
-
- end = ptr + psize;
- ptr += 4;
-
- p->n_rows = rows;
- p->n_entries = rows;
- row = 0;
-
- while ((row < rows) && (ptr < end)) {
- flags = *ptr++;
- if (!flags) {
- row++;
- continue;
- }
- if (flags & 0xE0) {
- p->n_entries++;
- if (flags & 0x80) ptr += 2;
- if (flags & 0x40) ptr++;
- if (flags & 0x20) {
- ptr++;
- if (*ptr == 40) ptr += 3;
- else ptr++;
- }
- }
- }
-
- entry = malloc(p->n_entries * sizeof(*p->entry));
- if (!entry) goto error_fb;
-
- p->entry = entry;
-
- ptr = buffer + offset + 4;
- row = 0;
-
- while ((row < rows) && (ptr < end)) {
- flags = *ptr++;
- if (!flags) {
- IT_SET_END_ROW(entry);
- entry++;
- row++;
- continue;
- }
- if (flags & 0xE0) {
- entry->mask = 0;
- entry->channel = channel = flags & 0x1F;
- if (channel >= chans)
- {
- //channel = 0;
- goto error_fb;
- }
- if (flags & 0x80) {
- if ((*ptr < 60) && (channel < pchans)) {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = *ptr + 36;
- }
- ptr++;
- if (*ptr) {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = *ptr;
- }
- ptr++;
- }
- if (flags & 0x40) {
- if (*ptr <= 64) {
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->volpan = *ptr;
- }
- ptr++;
- }
- if (flags & 0x20) {
- entry->mask |= IT_ENTRY_EFFECT;
-
- switch (*ptr) {
- case 1:
- entry->effect = IT_XM_FINE_VOLSLIDE_UP;
- entry->effectvalue = ptr[1];
- break;
-
- case 2:
- entry->effect = IT_VOLUME_SLIDE;
- entry->effectvalue = (ptr[1] << 4) & 0xF0;
- break;
-
- case 3:
- entry->effect = IT_XM_FINE_VOLSLIDE_DOWN;
- entry->effectvalue = ptr[1];
- break;
-
- case 4:
- entry->effect = IT_VOLUME_SLIDE;
- entry->effectvalue = ptr[1] & 0xF;
- break;
-
- case 10:
- entry->effect = IT_PORTAMENTO_UP;
- entry->effectvalue = EFFECT_VALUE(0xF, ptr[1]);
- break;
-
- case 11:
- entry->effect = IT_PORTAMENTO_UP;
- entry->effectvalue = ptr[1];
- break;
-
- case 12:
- entry->effect = IT_PORTAMENTO_DOWN;
- entry->effectvalue = EFFECT_VALUE(ptr[1], 0xF);
- break;
-
- case 13:
- entry->effect = IT_PORTAMENTO_DOWN;
- entry->effectvalue = ptr[1];
- break;
-
- case 14:
- entry->effect = IT_TONE_PORTAMENTO;
- entry->effectvalue = ptr[1];
- break;
-
- case 15:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_SET_GLISSANDO_CONTROL, ptr[1] & 15);
- break;
-
- case 16:
- entry->effect = IT_VOLSLIDE_TONEPORTA;
- entry->effectvalue = ptr[1] << 4;
- break;
-
- case 17:
- entry->effect = IT_VOLSLIDE_TONEPORTA;
- entry->effectvalue = ptr[1] & 0xF;
- break;
-
- case 20:
- entry->effect = IT_VIBRATO;
- entry->effectvalue = ptr[1];
- break;
-
- case 21:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_SET_VIBRATO_WAVEFORM, ptr[1] & 11);
- break;
-
- case 22:
- entry->effect = IT_VOLSLIDE_VIBRATO;
- entry->effectvalue = ptr[1] << 4;
- break;
-
- case 23:
- entry->effect = IT_VOLSLIDE_VIBRATO;
- entry->effectvalue = ptr[1] & 0xF;
- break;
-
- case 30:
- entry->effect = IT_TREMOLO;
- entry->effectvalue = ptr[1];
- break;
-
- case 31:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_SET_TREMOLO_WAVEFORM, ptr[1] & 11);
- break;
-
- case 40:
- entry->effect = IT_SET_SAMPLE_OFFSET;
- entry->effectvalue = ptr[2];
- ptr += 2;
- break;
-
- case 41:
- entry->effect = IT_XM_RETRIGGER_NOTE;
- entry->effectvalue = ptr[1];
- break;
-
- case 42:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_DELAYED_NOTE_CUT, ptr[1] & 0xF);
- break;
-
- case 43:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_NOTE_DELAY, ptr[1] & 0xF);
- break;
-
- case 50:
- entry->effect = IT_JUMP_TO_ORDER;
- entry->effectvalue = ptr[1];
- break;
-
- case 51:
- entry->effect = IT_BREAK_TO_ROW;
- entry->effectvalue = ptr[1];
- break;
-
- case 52:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_LOOP, ptr[1] & 0xF);
- break;
-
- case 53:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_DELAY, ptr[1] & 0xF);
- break;
-
- case 60:
- entry->effect = IT_SET_SPEED;
- entry->effectvalue = ptr[1];
- break;
-
- case 61:
- entry->effect = IT_SET_SONG_TEMPO;
- entry->effectvalue = ptr[1];
- break;
-
- case 70:
- entry->effect = IT_ARPEGGIO;
- entry->effectvalue = ptr[1];
- break;
-
- case 71:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_FINETUNE, ptr[1] & 0xF);
- break;
-
- case 72:
- /* "balance" ... panning? */
- entry->effect = IT_SET_PANNING;
- entry->effectvalue = ((ptr[1] - ((ptr[1] & 8) >> 3)) << 5) / 7;
- break;
-
- default:
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
-
- ptr += 2;
- }
- if (entry->mask) entry++;
- }
- }
-
- p->n_entries = entry - p->entry;
- offset += psize;
- }
-
- free(buffer);
-
- return 0;
-
-error_fb:
- free(buffer);
-error:
- return -1;
-}
-
-#define PSM_COMPONENT_ORDERS 0
-#define PSM_COMPONENT_PANPOS 1
-#define PSM_COMPONENT_PATTERNS 2
-#define PSM_COMPONENT_SAMPLE_HEADERS 3
-#define PSM_COMPONENT_COMMENTS 4
-
-typedef struct PSM_COMPONENT
-{
- unsigned char type;
- long offset;
-}
-PSM_COMPONENT;
-
-static int psm_component_compare(const void *e1, const void *e2)
-{
- return ((const PSM_COMPONENT *)e1)->offset -
- ((const PSM_COMPONENT *)e2)->offset;
-}
-
-static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- unsigned char * ptr = 0;
-
- PSM_COMPONENT *component;
- int n_components = 0;
-
- int n, flags, version, pver, n_orders, n_channels, total_pattern_size;
-
- if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',254)) goto error;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) goto error;
-
- if (dumbfile_getnc(sigdata->name, 60, f) < 60 ||
- sigdata->name[59] != 0x1A) goto error_sd;
- sigdata->name[59] = 0;
-
- flags = dumbfile_getc(f);
- version = dumbfile_getc(f);
- pver = dumbfile_getc(f);
- sigdata->speed = dumbfile_getc(f);
- sigdata->tempo = dumbfile_getc(f);
- sigdata->mixing_volume = dumbfile_getc(f);
- sigdata->n_orders = dumbfile_igetw(f);
- n_orders = dumbfile_igetw(f);
- sigdata->n_patterns = dumbfile_igetw(f);
- sigdata->n_samples = dumbfile_igetw(f);
- sigdata->n_pchannels = dumbfile_igetw(f);
- n_channels = dumbfile_igetw(f);
-
- if (dumbfile_error(f) ||
- (flags & 1) ||
- (version != 1 && version != 0x10) ||
- (pver) ||
- (sigdata->n_orders <= 0) ||
- (sigdata->n_orders > 255) ||
- (n_orders > 255) ||
- (n_orders < sigdata->n_orders) ||
- (sigdata->n_patterns > 255) ||
- (sigdata->n_samples > 255) ||
- (sigdata->n_pchannels > DUMB_IT_N_CHANNELS) ||
- (sigdata->n_pchannels > n_channels) ||
- (n_channels > DUMB_IT_N_CHANNELS))
- goto error_sd;
-
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
-
- sigdata->global_volume = 128;
- sigdata->pan_separation = 128;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
-
- sigdata->restart_position = 0;
-
- sigdata->order = malloc(sigdata->n_orders);
- if (!sigdata->order) goto error_usd;
-
- if (sigdata->n_samples) {
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) goto error_usd;
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
- }
-
- if (sigdata->n_patterns) {
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) goto error_usd;
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
- }
-
- component = malloc(5 * sizeof(*component));
- if (!component) goto error_usd;
-
- for (n = 0; n < 5; n++) {
- component[n_components].offset = dumbfile_igetl(f);
- if (component[n_components].offset) {
- component[n_components].type = n;
- n_components++;
- }
- }
-
- if (!n_components) goto error_fc;
-
- total_pattern_size = dumbfile_igetl(f);
- if (!total_pattern_size) goto error_fc;
-
- qsort(component, n_components, sizeof(PSM_COMPONENT), &psm_component_compare);
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- for (n = 0; n < n_components; n++)
- {
- int o;
- long data_pos, data_size;
-
- /* Whee, sample data may be before the sample headers */
-
- data_pos = dumbfile_pos(f);
- if (data_pos > component[n].offset) goto error_fc;
-
- data_size = component[n].offset - data_pos;
-
- if (data_size) {
- ptr = malloc(data_size);
- if (!ptr) goto error_fc;
-
- if (dumbfile_getnc(ptr, data_size, f) < data_size) goto error_fp;
- }
-
- switch (component[n].type) {
-
- case PSM_COMPONENT_ORDERS:
- if (dumbfile_getnc(sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_fp;
- if (n_orders > sigdata->n_orders)
- if (dumbfile_skip(f, n_orders - sigdata->n_orders))
- goto error_fp;
- if (dumbfile_igetw(f)) goto error_fp;
- break;
-
- case PSM_COMPONENT_PANPOS:
- if (dumbfile_getnc(sigdata->channel_pan, sigdata->n_pchannels, f) < sigdata->n_pchannels) goto error_fp;
- for (o = 0; o < sigdata->n_pchannels; o++) {
- sigdata->channel_pan[o] -= (sigdata->channel_pan[o] & 8) >> 3;
- sigdata->channel_pan[o] = ((int)sigdata->channel_pan[o] << 5) / 7;
- }
- break;
-
- case PSM_COMPONENT_PATTERNS:
- if (it_old_psm_read_patterns(sigdata->pattern, f, sigdata->n_patterns, total_pattern_size, sigdata->n_pchannels, flags)) goto error_fp;
- break;
-
- case PSM_COMPONENT_SAMPLE_HEADERS:
- if (it_old_psm_read_samples(&sigdata->sample, f, &sigdata->n_samples, ptr, data_pos, data_size)) goto error_fp;
- break;
-
- case PSM_COMPONENT_COMMENTS:
- if (dumbfile_mgetl(f) == DUMB_ID('T','E','X','T')) {
- o = dumbfile_igetw(f);
- if (o > 0) {
- sigdata->song_message = malloc(o + 1);
- if (dumbfile_getnc(sigdata->song_message, o, f) < o) goto error_fp;
- sigdata->song_message[o] = 0;
- }
- }
- break;
- }
-
- if (ptr) {
- free(ptr);
- ptr = 0;
- }
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- free(component);
-
- return sigdata;
-
-error_fp:
- if (ptr) free(ptr);
-error_fc:
- free(component);
-error_usd:
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
-error_sd:
- free(sigdata);
-error:
- return NULL;
-}
-
-DUH *dumb_read_old_psm_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_old_psm_load_sigdata(f);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "PSM (old)";
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readpsm.c - Code to read an old Protracker / / \ \ + * Studio module from an open file. | < / \_ + * | \/ /\ / + * By Chris Moeller. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "dumb.h" +#include "internal/it.h" + +static int psm_sample_compare(const void *e1, const void *e2) +{ + const unsigned char * pa = e1; + const unsigned char * pb = e2; + int a = pa[37] | (pa[38] << 8) | (pa[39] << 16) | (pa[40] << 24); + int b = pb[37] | (pb[38] << 8) | (pb[39] << 16) | (pb[40] << 24); + return a - b; +} + +static int it_old_psm_read_samples(IT_SAMPLE ** sample, DUMBFILE * f, int * num, const unsigned char * prebuffer, long data_pos, long data_size) +{ + int n, o, pos, count = *num, true_num, snum, offset, flags, finetune, delta; + + unsigned char * buffer, * sbuffer = 0; + const unsigned char * sdata; + + buffer = malloc(count * 64); + if (!buffer) goto error; + + if (dumbfile_getnc(buffer, count * 64, f) < count * 64) goto error_fb; + + pos = dumbfile_pos(f); + + true_num = 0; + + for (n = 0; n < count; n++) { + snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8); + if ((snum < 1) || (snum > 255)) goto error_fb; + if (true_num < snum) true_num = snum; + } + + if (true_num > count) { + IT_SAMPLE * meh = realloc(*sample, true_num * sizeof(*meh)); + if (!meh) goto error_fb; + for (n = count; n < true_num; n++) { + meh[n].data = NULL; + } + *sample = meh; + *num = true_num; + } + + qsort(buffer, count, 64, &psm_sample_compare); + + for (n = 0; n < true_num; n++) { + (*sample)[n].flags = 0; + } + + for (n = 0; n < count; n++) { + IT_SAMPLE * s; + snum = buffer[(n * 64) + 45] | (buffer[(n * 64) + 46] << 8); + s = &((*sample)[snum - 1]); + memcpy(s->filename, buffer + (n * 64), 13); + s->filename[13] = 0; + memcpy(s->name, buffer + (n * 64) + 13, 24); + s->name[24] = 0; + offset = buffer[(n * 64) + 37] | (buffer[(n * 64) + 38] << 8) | + (buffer[(n * 64) + 39] << 16) | (buffer[(n * 64) + 40] << 24); + flags = buffer[(n * 64) + 47]; + s->length = buffer[(n * 64) + 48] | (buffer[(n * 64) + 49] << 8) | + (buffer[(n * 64) + 50] << 16) | (buffer[(n * 64) + 51] << 24); + s->loop_start = buffer[(n * 64) + 52] | (buffer[(n * 64) + 53] << 8) | + (buffer[(n * 64) + 54] << 16) | (buffer[(n * 64) + 55] << 24); + s->loop_end = buffer[(n * 64) + 56] | (buffer[(n * 64) + 57] << 8) | + (buffer[(n * 64) + 58] << 16) | (buffer[(n * 64) + 59] << 24); + + if (s->length <= 0) continue; + + finetune = buffer[(n * 64) + 60]; + s->default_volume = buffer[(n * 64) + 61]; + s->C5_speed = buffer[(n * 64) + 62] | (buffer[(n * 64) + 63] << 8); + if (finetune < 16) { + if (finetune >= 8) finetune -= 16; + //s->C5_speed = (long)((double)s->C5_speed * pow(DUMB_PITCH_BASE, finetune*32)); + s->finetune = finetune * 32; + } + else s->finetune = 0; + + s->flags |= IT_SAMPLE_EXISTS; + if (flags & 0x41) { + s->flags &= ~IT_SAMPLE_EXISTS; + continue; + } + if (flags & 0x20) s->flags |= IT_SAMPLE_PINGPONG_LOOP; + if (flags & 4) s->flags |= IT_SAMPLE_16BIT; + + if (flags & 0x80) { + s->flags |= IT_SAMPLE_LOOP; + if ((unsigned int)s->loop_end > (unsigned int)s->length) + s->loop_end = s->length; + else if ((unsigned int)s->loop_start >= (unsigned int)s->loop_end) + s->flags &= ~IT_SAMPLE_LOOP; + else + s->length = s->loop_end; + } + + s->global_volume = 64; + + s->vibrato_speed = 0; + s->vibrato_depth = 0; + s->vibrato_rate = 0; + s->vibrato_waveform = IT_VIBRATO_SINE; + s->max_resampling_quality = -1; + + s->data = malloc(s->length * ((flags & 4) ? 2 : 1)); + if (!s->data) goto error_fb; + + if ((offset >= data_pos) && + ((offset + s->length * ((flags & 4) ? 2 : 1)) <= (data_pos + data_size))) { + sdata = prebuffer + offset - data_pos; + } else if (offset >= pos) { + if (dumbfile_skip(f, offset - pos)) goto error_fb; + pos = offset; + offset = s->length * ((flags & 4) ? 2 : 1); + sbuffer = malloc(offset); + if (!sbuffer) goto error_fb; + if (dumbfile_getnc(sbuffer, offset, f) < offset) goto error_fsb; + sdata = sbuffer; + } else + goto error_fb; + + if (flags & 0x10) { + if (flags & 8) { + if (flags & 4) { + for (o = 0; o < s->length; o++) + ((short *)s->data)[o] = (sdata[o * 2] | (sdata[(o * 2) + 1] << 8)) ^ 0x8000; + } else { + for (o = 0; o < s->length; o++) + ((signed char *)s->data)[o] = sdata[o] ^ 0x80; + } + } else { + if (flags & 4) { + for (o = 0; o < s->length; o++) + ((short *)s->data)[o] = sdata[o * 2] | (sdata[(o * 2) + 1] << 8); + } else { + memcpy(s->data, sdata, s->length); + } + } + } else { + delta = 0; + if (flags & 8) { + /* unsigned delta? mehhh, does anything even use this? */ + if (flags & 4) { + for (o = 0; o < s->length; o++) { + delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); + ((short *)s->data)[o] = delta ^ 0x8000; + } + } else { + for (o = 0; o < s->length; o++) { + delta += (signed char)sdata[o]; + ((signed char *)s->data)[o] = delta ^ 0x80; + } + } + } else { + if (flags & 4) { + for (o = 0; o < s->length; o++) { + delta += (short)(sdata[o * 2] | (sdata[(o * 2) + 1] << 8)); + ((short *)s->data)[o] = delta; + } + } else { + for (o = 0; o < s->length; o++) { + delta += (signed char)sdata[o]; + ((signed char *)s->data)[o] = delta; + } + } + } + } + + if (sbuffer) { + free(sbuffer); + sbuffer = 0; + } + } + + free(buffer); + + return 0; + +error_fsb: + if (sbuffer) free(sbuffer); +error_fb: + free(buffer); +error: + return -1; +} + +static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num, int size, int pchans, int sflags) +{ + int n, offset, psize, rows, chans, row, flags, channel; + + unsigned char * buffer, * ptr, * end; + + IT_ENTRY * entry; + + buffer = malloc(size); + if (!buffer) goto error; + + if (dumbfile_getnc(buffer, size, f) < size) goto error_fb; + + offset = 0; + + for (n = 0; n < num; n++) { + IT_PATTERN * p = &pattern[n]; + + if (offset >= size) goto error_fb; + + ptr = buffer + offset; + psize = ptr[0] | (ptr[1] << 8); + rows = ptr[2]; + chans = ptr[3]; + + if (!rows || !chans) { + p->n_rows = 1; + p->n_entries = 0; + continue; + } + + psize = (psize + 15) & ~15; + + end = ptr + psize; + ptr += 4; + + p->n_rows = rows; + p->n_entries = rows; + row = 0; + + while ((row < rows) && (ptr < end)) { + flags = *ptr++; + if (!flags) { + row++; + continue; + } + if (flags & 0xE0) { + p->n_entries++; + if (flags & 0x80) ptr += 2; + if (flags & 0x40) ptr++; + if (flags & 0x20) { + ptr++; + if (*ptr == 40) ptr += 3; + else ptr++; + } + } + } + + entry = malloc(p->n_entries * sizeof(*p->entry)); + if (!entry) goto error_fb; + + p->entry = entry; + + ptr = buffer + offset + 4; + row = 0; + + while ((row < rows) && (ptr < end)) { + flags = *ptr++; + if (!flags) { + IT_SET_END_ROW(entry); + entry++; + row++; + continue; + } + if (flags & 0xE0) { + entry->mask = 0; + entry->channel = channel = flags & 0x1F; + if (channel >= chans) + { + //channel = 0; + goto error_fb; + } + if (flags & 0x80) { + if ((*ptr < 60) && (channel < pchans)) { + entry->mask |= IT_ENTRY_NOTE; + entry->note = *ptr + 36; + } + ptr++; + if (*ptr) { + entry->mask |= IT_ENTRY_INSTRUMENT; + entry->instrument = *ptr; + } + ptr++; + } + if (flags & 0x40) { + if (*ptr <= 64) { + entry->mask |= IT_ENTRY_VOLPAN; + entry->volpan = *ptr; + } + ptr++; + } + if (flags & 0x20) { + entry->mask |= IT_ENTRY_EFFECT; + + switch (*ptr) { + case 1: + entry->effect = IT_XM_FINE_VOLSLIDE_UP; + entry->effectvalue = ptr[1]; + break; + + case 2: + entry->effect = IT_VOLUME_SLIDE; + entry->effectvalue = (ptr[1] << 4) & 0xF0; + break; + + case 3: + entry->effect = IT_XM_FINE_VOLSLIDE_DOWN; + entry->effectvalue = ptr[1]; + break; + + case 4: + entry->effect = IT_VOLUME_SLIDE; + entry->effectvalue = ptr[1] & 0xF; + break; + + case 10: + entry->effect = IT_PORTAMENTO_UP; + entry->effectvalue = EFFECT_VALUE(0xF, ptr[1]); + break; + + case 11: + entry->effect = IT_PORTAMENTO_UP; + entry->effectvalue = ptr[1]; + break; + + case 12: + entry->effect = IT_PORTAMENTO_DOWN; + entry->effectvalue = EFFECT_VALUE(ptr[1], 0xF); + break; + + case 13: + entry->effect = IT_PORTAMENTO_DOWN; + entry->effectvalue = ptr[1]; + break; + + case 14: + entry->effect = IT_TONE_PORTAMENTO; + entry->effectvalue = ptr[1]; + break; + + case 15: + entry->effect = IT_S; + entry->effectvalue = EFFECT_VALUE(IT_S_SET_GLISSANDO_CONTROL, ptr[1] & 15); + break; + + case 16: + entry->effect = IT_VOLSLIDE_TONEPORTA; + entry->effectvalue = ptr[1] << 4; + break; + + case 17: + entry->effect = IT_VOLSLIDE_TONEPORTA; + entry->effectvalue = ptr[1] & 0xF; + break; + + case 20: + entry->effect = IT_VIBRATO; + entry->effectvalue = ptr[1]; + break; + + case 21: + entry->effect = IT_S; + entry->effectvalue = EFFECT_VALUE(IT_S_SET_VIBRATO_WAVEFORM, ptr[1] & 11); + break; + + case 22: + entry->effect = IT_VOLSLIDE_VIBRATO; + entry->effectvalue = ptr[1] << 4; + break; + + case 23: + entry->effect = IT_VOLSLIDE_VIBRATO; + entry->effectvalue = ptr[1] & 0xF; + break; + + case 30: + entry->effect = IT_TREMOLO; + entry->effectvalue = ptr[1]; + break; + + case 31: + entry->effect = IT_S; + entry->effectvalue = EFFECT_VALUE(IT_S_SET_TREMOLO_WAVEFORM, ptr[1] & 11); + break; + + case 40: + entry->effect = IT_SET_SAMPLE_OFFSET; + entry->effectvalue = ptr[2]; + ptr += 2; + break; + + case 41: + entry->effect = IT_XM_RETRIGGER_NOTE; + entry->effectvalue = ptr[1]; + break; + + case 42: + entry->effect = IT_S; + entry->effectvalue = EFFECT_VALUE(IT_S_DELAYED_NOTE_CUT, ptr[1] & 0xF); + break; + + case 43: + entry->effect = IT_S; + entry->effectvalue = EFFECT_VALUE(IT_S_NOTE_DELAY, ptr[1] & 0xF); + break; + + case 50: + entry->effect = IT_JUMP_TO_ORDER; + entry->effectvalue = ptr[1]; + break; + + case 51: + entry->effect = IT_BREAK_TO_ROW; + entry->effectvalue = ptr[1]; + break; + + case 52: + entry->effect = IT_S; + entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_LOOP, ptr[1] & 0xF); + break; + + case 53: + entry->effect = IT_S; + entry->effectvalue = EFFECT_VALUE(IT_S_PATTERN_DELAY, ptr[1] & 0xF); + break; + + case 60: + entry->effect = IT_SET_SPEED; + entry->effectvalue = ptr[1]; + break; + + case 61: + entry->effect = IT_SET_SONG_TEMPO; + entry->effectvalue = ptr[1]; + break; + + case 70: + entry->effect = IT_ARPEGGIO; + entry->effectvalue = ptr[1]; + break; + + case 71: + entry->effect = IT_S; + entry->effectvalue = EFFECT_VALUE(IT_S_FINETUNE, ptr[1] & 0xF); + break; + + case 72: + /* "balance" ... panning? */ + entry->effect = IT_SET_PANNING; + entry->effectvalue = ((ptr[1] - ((ptr[1] & 8) >> 3)) << 5) / 7; + break; + + default: + entry->mask &= ~IT_ENTRY_EFFECT; + } + + ptr += 2; + } + if (entry->mask) entry++; + } + } + + p->n_entries = entry - p->entry; + offset += psize; + } + + free(buffer); + + return 0; + +error_fb: + free(buffer); +error: + return -1; +} + +#define PSM_COMPONENT_ORDERS 0 +#define PSM_COMPONENT_PANPOS 1 +#define PSM_COMPONENT_PATTERNS 2 +#define PSM_COMPONENT_SAMPLE_HEADERS 3 +#define PSM_COMPONENT_COMMENTS 4 + +typedef struct PSM_COMPONENT +{ + unsigned char type; + long offset; +} +PSM_COMPONENT; + +static int psm_component_compare(const void *e1, const void *e2) +{ + return ((const PSM_COMPONENT *)e1)->offset - + ((const PSM_COMPONENT *)e2)->offset; +} + +static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f) +{ + DUMB_IT_SIGDATA *sigdata; + + unsigned char * ptr = 0; + + PSM_COMPONENT *component; + int n_components = 0; + + int n, flags, version, pver, n_orders, n_channels, total_pattern_size; + + if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',254)) goto error; + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) goto error; + + if (dumbfile_getnc(sigdata->name, 60, f) < 60 || + sigdata->name[59] != 0x1A) goto error_sd; + sigdata->name[59] = 0; + + flags = dumbfile_getc(f); + version = dumbfile_getc(f); + pver = dumbfile_getc(f); + sigdata->speed = dumbfile_getc(f); + sigdata->tempo = dumbfile_getc(f); + sigdata->mixing_volume = dumbfile_getc(f); + sigdata->n_orders = dumbfile_igetw(f); + n_orders = dumbfile_igetw(f); + sigdata->n_patterns = dumbfile_igetw(f); + sigdata->n_samples = dumbfile_igetw(f); + sigdata->n_pchannels = dumbfile_igetw(f); + n_channels = dumbfile_igetw(f); + + if (dumbfile_error(f) || + (flags & 1) || + (version != 1 && version != 0x10) || + (pver) || + (sigdata->n_orders <= 0) || + (sigdata->n_orders > 255) || + (n_orders > 255) || + (n_orders < sigdata->n_orders) || + (sigdata->n_patterns > 255) || + (sigdata->n_samples > 255) || + (sigdata->n_pchannels > DUMB_IT_N_CHANNELS) || + (sigdata->n_pchannels > n_channels) || + (n_channels > DUMB_IT_N_CHANNELS)) + goto error_sd; + + sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX; + + sigdata->global_volume = 128; + sigdata->pan_separation = 128; + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->sample = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->n_instruments = 0; + + sigdata->restart_position = 0; + + sigdata->order = malloc(sigdata->n_orders); + if (!sigdata->order) goto error_usd; + + if (sigdata->n_samples) { + sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); + if (!sigdata->sample) goto error_usd; + for (n = 0; n < sigdata->n_samples; n++) + sigdata->sample[n].data = NULL; + } + + if (sigdata->n_patterns) { + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) goto error_usd; + for (n = 0; n < sigdata->n_patterns; n++) + sigdata->pattern[n].entry = NULL; + } + + component = malloc(5 * sizeof(*component)); + if (!component) goto error_usd; + + for (n = 0; n < 5; n++) { + component[n_components].offset = dumbfile_igetl(f); + if (component[n_components].offset) { + component[n_components].type = n; + n_components++; + } + } + + if (!n_components) goto error_fc; + + total_pattern_size = dumbfile_igetl(f); + if (!total_pattern_size) goto error_fc; + + qsort(component, n_components, sizeof(PSM_COMPONENT), &psm_component_compare); + + memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); + + for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { + sigdata->channel_pan[n ] = 16; + sigdata->channel_pan[n+1] = 48; + sigdata->channel_pan[n+2] = 48; + sigdata->channel_pan[n+3] = 16; + } + + for (n = 0; n < n_components; n++) + { + int o; + long data_pos, data_size; + + /* Whee, sample data may be before the sample headers */ + + data_pos = dumbfile_pos(f); + if (data_pos > component[n].offset) goto error_fc; + + data_size = component[n].offset - data_pos; + + if (data_size) { + ptr = malloc(data_size); + if (!ptr) goto error_fc; + + if (dumbfile_getnc(ptr, data_size, f) < data_size) goto error_fp; + } + + switch (component[n].type) { + + case PSM_COMPONENT_ORDERS: + if (dumbfile_getnc(sigdata->order, sigdata->n_orders, f) < sigdata->n_orders) goto error_fp; + if (n_orders > sigdata->n_orders) + if (dumbfile_skip(f, n_orders - sigdata->n_orders)) + goto error_fp; + if (dumbfile_igetw(f)) goto error_fp; + break; + + case PSM_COMPONENT_PANPOS: + if (dumbfile_getnc(sigdata->channel_pan, sigdata->n_pchannels, f) < sigdata->n_pchannels) goto error_fp; + for (o = 0; o < sigdata->n_pchannels; o++) { + sigdata->channel_pan[o] -= (sigdata->channel_pan[o] & 8) >> 3; + sigdata->channel_pan[o] = ((int)sigdata->channel_pan[o] << 5) / 7; + } + break; + + case PSM_COMPONENT_PATTERNS: + if (it_old_psm_read_patterns(sigdata->pattern, f, sigdata->n_patterns, total_pattern_size, sigdata->n_pchannels, flags)) goto error_fp; + break; + + case PSM_COMPONENT_SAMPLE_HEADERS: + if (it_old_psm_read_samples(&sigdata->sample, f, &sigdata->n_samples, ptr, data_pos, data_size)) goto error_fp; + break; + + case PSM_COMPONENT_COMMENTS: + if (dumbfile_mgetl(f) == DUMB_ID('T','E','X','T')) { + o = dumbfile_igetw(f); + if (o > 0) { + sigdata->song_message = malloc(o + 1); + if (dumbfile_getnc(sigdata->song_message, o, f) < o) goto error_fp; + sigdata->song_message[o] = 0; + } + } + break; + } + + if (ptr) { + free(ptr); + ptr = 0; + } + } + + _dumb_it_fix_invalid_orders(sigdata); + + free(component); + + return sigdata; + +error_fp: + if (ptr) free(ptr); +error_fc: + free(component); +error_usd: + _dumb_it_unload_sigdata(sigdata); + return NULL; +error_sd: + free(sigdata); +error: + return NULL; +} + +DUH *dumb_read_old_psm_quick(DUMBFILE *f) +{ + sigdata_t *sigdata; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_old_psm_load_sigdata(f); + + if (!sigdata) + return NULL; + + { + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = "PSM (old)"; + return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/readpsm.c b/plugins/dumb/dumb-kode54/src/it/readpsm.c index 07b33613..ec2bf909 100644 --- a/plugins/dumb/dumb-kode54/src/it/readpsm.c +++ b/plugins/dumb/dumb-kode54/src/it/readpsm.c @@ -1,1273 +1,1273 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readpsm.c - Code to read a Protracker Studio / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-#define PSMV_OLD 940730
-#define PSMV_NEW 940902
-
-typedef struct _PSMCHUNK
-{
- int id;
- int len;
- unsigned char * data;
-} PSMCHUNK;
-
-typedef struct _PSMEVENT
-{
- int type;
- unsigned char data[8];
-} PSMEVENT;
-
-#define PSM_EVENT_END 0
-#define PSM_EVENT_PLAY_PATTERN 1
-#define PSM_EVENT_JUMP_TO_LINE 4
-#define PSM_EVENT_SET_SPEED 7
-#define PSM_EVENT_SET_BPM 8
-#define PSM_EVENT_SAMPLE_MAP_TABLE 12
-#define PSM_EVENT_CHANGE_PAN 13
-#define PSM_EVENT_CHANGE_VOL 14
-
-static int it_psm_process_sample(IT_SAMPLE * sample, const unsigned char * data, int len, int id, int version) {
- int flags;
- int insno;
- int length;
- int loopstart;
- int loopend;
- int panpos;
- int defvol;
- int samplerate;
-
- if (len < 0x60) return -1;
-
- flags = data[0];
-
- if (version == PSMV_OLD) {
- memcpy(sample->name, data + 0x0D, 34);
- sample->name[34] = 0;
-
- insno = data[0x34] | (data[0x35] << 8);
- length = data[0x36] | (data[0x37] << 8) | (data[0x38] << 16) | (data[0x39] << 24);
- loopstart = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24);
- loopend = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24);
- panpos = data[0x43];
- defvol = data[0x44];
- samplerate = data[0x49] | (data[0x4A] << 8) | (data[0x4B] << 16) | (data[0x4C] << 24);
- } else if (version == PSMV_NEW) {
- memcpy(sample->name, data + 0x11, 34);
- sample->name[34] = 0;
-
- insno = data[0x38] | (data[0x39] << 8);
- length = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24);
- loopstart = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24);
- loopend = data[0x42] | (data[0x43] << 8) | (data[0x44] << 16) | (data[0x45] << 24);
- panpos = data[0x48];
- defvol = data[0x49];
- samplerate = data[0x4E] | (data[0x4F] << 8) | (data[0x50] << 16) | (data[0x51] << 24);
- }
-
- if (insno != id) return -1;
-
- if (!length) {
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return 0;
- }
-
- if ((length > len - 0x60) || ((flags & 0x7F) != 0)) return -1;
-
- sample->flags = IT_SAMPLE_EXISTS;
- sample->length = length;
- sample->loop_start = loopstart;
- sample->loop_end = loopend;
- sample->C5_speed = samplerate;
- sample->default_volume = defvol >> 1;
- sample->default_pan = 0;
- sample->filename[0] = 0;
- sample->global_volume = 64;
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- if (flags & 0x80) {
- if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) &&
- ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end)) {
- sample->length = sample->loop_end;
- sample->flags |= IT_SAMPLE_LOOP;
- }
- }
-
- sample->data = malloc(sample->length);
- if (!sample->data)
- return -1;
-
- flags = 0;
- data += 0x60;
-
- for (insno = 0; insno < sample->length; insno++) {
- flags += (signed char)(*data++);
- ((signed char *)sample->data)[insno] = flags;
- }
-
- return 0;
-}
-
-static int it_psm_process_pattern(IT_PATTERN * pattern, const unsigned char * data, int len, int speed, int bpm, const unsigned char * pan, const int * vol, int version) {
- int length, nrows, row, rowlen, pos;
- unsigned flags, chan;
- IT_ENTRY * entry;
-
- length = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
- if (len > length) len = length;
-
- if (version == PSMV_OLD) {
- if (len < 10) return -1;
- data += 8;
- len -= 8;
- } else if (version == PSMV_NEW) {
- if (len < 14) return -1;
- data += 12;
- len -= 12;
- }
-
- nrows = data[0] | (data[1] << 8);
-
- if (!nrows) return 0;
-
- pattern->n_rows = nrows;
-
- data += 2;
- len -= 2;
-
- pattern->n_entries = 0;
-
- row = 0;
- pos = 2;
- rowlen = data[0] | (data[1] << 8);
-
- while ((row < nrows) && (pos < len)) {
- if (pos >= rowlen) {
- row++;
- rowlen += data[pos] | (data[pos+1] << 8);
- pos += 2;
- continue;
- }
-
- flags = data[pos++];
- chan = data[pos++];
-
- if (chan > 63) return -1;
-
- if (flags & 0xF0) {
- pattern->n_entries++;
- if (flags & 0x80) pos++;
- if (flags & 0x40) pos++;
- if (flags & 0x20) pos++;
- if (flags & 0x10) {
- switch (data[pos]) {
- case 0x29:
- pos++;
- case 0x33:
- pos++;
- default:
- pos += 2;
- }
- }
- }
- }
-
- if (!pattern->n_entries) return 0;
-
- pattern->n_entries += nrows;
- if (speed) pattern->n_entries++;
- if (bpm >= 0x20) pattern->n_entries++;
-
- for (pos = 0; pos < 32; pos++) {
- if (!(pan[pos*2+1] & 0xF9)) pattern->n_entries++;
- if (vol[pos] != -1) pattern->n_entries++;
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
- if (!pattern->entry) return -1;
-
- entry = pattern->entry;
-
- if (speed) {
- entry->channel = 0;
- entry->mask = IT_ENTRY_EFFECT;
- entry->effect = IT_SET_SPEED;
- entry->effectvalue = speed;
- entry++;
- }
-
- if (bpm >= 0x20) {
- entry->channel = 0;
- entry->mask = IT_ENTRY_EFFECT;
- entry->effect = IT_SET_SONG_TEMPO;
- entry->effectvalue = bpm;
- entry++;
- }
-
- for (pos = 0; pos < 32; pos++) {
- if (!(pan[pos*2+1] & 0xF9)) {
- entry->channel = pos;
- entry->mask = IT_ENTRY_EFFECT;
- switch (pan[pos*2+1]) {
- case 0:
- entry->effect = IT_SET_PANNING;
- entry->effectvalue = pan[pos*2] ^ 128;
- break;
- case 2:
- entry->effect = IT_S;
- entry->effectvalue = EFFECT_VALUE(IT_S_SET_SURROUND_SOUND,1);
- break;
- case 4:
- entry->effect = IT_SET_PANNING;
- entry->effectvalue = 128;
- break;
- }
- entry++;
- }
- if (vol[pos] != -1) {
- entry->channel = pos;
- entry->mask = IT_ENTRY_EFFECT;
- entry->effect = IT_SET_CHANNEL_VOLUME;
- entry->effectvalue = (vol[pos] + 2) >> 2;
- entry++;
- }
- }
-
- row = 0;
- pos = 2;
- rowlen = data[0] | (data[1] << 8);
-
- while ((row < nrows) && (pos < len)) {
- if (pos >= rowlen) {
- IT_SET_END_ROW(entry);
- entry++;
- row++;
- rowlen += data[pos] | (data[pos+1] << 8);
- pos += 2;
- continue;
- }
-
- flags = data[pos++];
- entry->channel = data[pos++];
- entry->mask = 0;
-
- if (flags & 0xF0) {
- if (flags & 0x80) {
- entry->mask |= IT_ENTRY_NOTE;
- if (version == PSMV_OLD) {
- if ((data[pos] < 0x80)) entry->note = (data[pos]>>4)*12+(data[pos]&0x0f)+12;
- else entry->mask &= ~IT_ENTRY_NOTE;
- } else if (version == PSMV_NEW) {
- if ((data[pos]) && (data[pos] < 84)) entry->note = data[pos] + 35;
- else entry->mask &= ~IT_ENTRY_NOTE;
- }
- pos++;
- }
-
- if (flags & 0x40) {
- entry->mask |= IT_ENTRY_INSTRUMENT;
- entry->instrument = data[pos++] + 1;
- }
-
- if (flags & 0x20) {
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->volpan = (data[pos++] + 1) >> 1;
- }
-
- if (flags & 0x10) {
- entry->mask |= IT_ENTRY_EFFECT;
- length = data[pos+1];
- switch (data[pos]) {
- case 1:
- entry->effect = IT_VOLUME_SLIDE;
- if (version == PSMV_OLD) entry->effectvalue = ((length&0x1e)<<3) | 0xF;
- else if (version == PSMV_NEW) entry->effectvalue = (length<<4) | 0xF;
- break;
-
- case 2:
- entry->effect = IT_VOLUME_SLIDE;
- if (version == PSMV_OLD) entry->effectvalue = (length << 3) & 0xF0;
- else if (version == PSMV_NEW) entry->effectvalue = (length << 4) & 0xF0;
- break;
-
- case 3:
- entry->effect = IT_VOLUME_SLIDE;
- if (version == PSMV_OLD) entry->effectvalue = (length >> 1) | 0xF0;
- else if (version == PSMV_NEW) entry->effectvalue = length | 0xF0;
- break;
-
- case 4:
- entry->effect = IT_VOLUME_SLIDE;
- if (version == PSMV_OLD) entry->effectvalue = (length >> 1) & 0xF;
- else if (version == PSMV_NEW) entry->effectvalue = length & 0xF;
- break;
-
- case 12:
- entry->effect = IT_PORTAMENTO_UP;
- if (version == PSMV_OLD) {
- if (length < 4) entry->effectvalue = length | 0xF0;
- else entry->effectvalue = length >> 2;
- } else if (version == PSMV_NEW) {
- entry->effectvalue = length;
- }
- break;
-
- case 14:
- entry->effect = IT_PORTAMENTO_DOWN;
- if (version == PSMV_OLD) {
- if (length < 4) entry->effectvalue = length | 0xF0;
- else entry->effectvalue = length >> 2;
- } else if (version == PSMV_NEW) {
- entry->effectvalue = length;
- }
- break;
-
- case 15:
- entry->effect = IT_TONE_PORTAMENTO;
- if (version == PSMV_OLD) entry->effectvalue = length >> 2;
- else if (version == PSMV_NEW) entry->effectvalue = length;
- break;
-
- case 0x15:
- entry->effect = IT_VIBRATO;
- entry->effectvalue = length;
- break;
-
- case 0x18:
- entry->effect = IT_VOLSLIDE_VIBRATO;
- entry->effectvalue = length;
- break;
-
- case 0x29:
- entry->effect = IT_SET_SAMPLE_OFFSET;
- entry->effectvalue = data[pos+2];
- pos += 2;
- break;
-
- case 0x2A:
- entry->effect = IT_RETRIGGER_NOTE;
- entry->effectvalue = length;
- break;
-
- case 0x33:
-#if 0
- entry->effect = IT_POSITION_JUMP;
- entry->effectvalue = data[pos+2];
-#else
- entry->mask &= ~IT_ENTRY_EFFECT;
-#endif
- pos++;
- break;
-
- case 0x34:
- entry->effect = IT_BREAK_TO_ROW;
- entry->effectvalue = length;
- break;
-
- case 0x3D:
- entry->effect = IT_SET_SPEED;
- entry->effectvalue = length;
- break;
-
- case 0x3E:
- if (length >= 0x20) {
- entry->effect = IT_SET_SONG_TEMPO;
- entry->effectvalue = length;
- } else {
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
- break;
-
- case 0x47:
- entry->effect = IT_ARPEGGIO;
- entry->effectvalue = length;
- break;
-
- default:
- return -1;
- }
- pos += 2;
- }
- if (entry->mask) entry++;
- }
- }
-
- while (row < nrows) {
- IT_SET_END_ROW(entry);
- entry++;
- row++;
- }
-
- pattern->n_entries = entry - pattern->entry;
- if (!pattern->n_entries) return -1;
-
- return 0;
-}
-
-
-static void free_chunks(PSMCHUNK * chunk, int count) {
- int n;
-
- for (n = 0; n < count; n++) {
- if (chunk[n].data)
- free(chunk[n].data);
- }
-
- free(chunk);
-}
-
-static void dumb_it_optimize_orders(DUMB_IT_SIGDATA * sigdata);
-
-static int pattcmp( const unsigned char *, const unsigned char *, size_t );
-
-static DUMB_IT_SIGDATA *it_psm_load_sigdata(DUMBFILE *f, int * ver, int subsong)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- PSMCHUNK *chunk;
- int n_chunks = 0;
-
- PSMCHUNK *songchunk;
- int n_song_chunks = 0;
-
- PSMEVENT *event = NULL;
- int n_events = 0;
-
- unsigned char * ptr;
-
- int n, length, o;
-
- int found;
-
- int n_patterns = 0;
-
- int first_pattern_line = -1;
- int first_pattern;
-
- int speed, bpm;
- unsigned char pan[64];
- int vol[32];
-
- if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',' ')) goto error;
-
- length = dumbfile_igetl(f);
-
- if (dumbfile_mgetl(f) != DUMB_ID('F','I','L','E')) goto error;
-
- chunk = calloc(768, sizeof(*chunk));
-
- while (length >= 8) {
- chunk[n_chunks].id = dumbfile_mgetl(f);
- n = dumbfile_igetl(f);
- length -= 8;
- if (n < 0 || n > length)
- goto error_fc;
- chunk[n_chunks].len = n;
- if (n) {
- ptr = malloc(n);
- if (!ptr) goto error_fc;
- if (dumbfile_getnc(ptr, n, f) < n)
- {
- free(ptr);
- goto error_fc;
- }
- chunk[n_chunks].data = ptr;
- }
- n_chunks++;
- length -= n;
- }
-
- if (!n_chunks) goto error_fc;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) goto error_fc;
-
- sigdata->n_patterns = 0;
- sigdata->n_samples = 0;
- sigdata->name[0] = 0;
-
- found = 0;
-
- for (n = 0; n < n_chunks; n++) {
- PSMCHUNK * c = &chunk[n];
- switch(c->id) {
- case DUMB_ID('S','D','F','T'):
- /* song data format? */
- if ((found & 1) || (c->len != 8) || memcmp(c->data, "MAINSONG", 8)) goto error_sd;
- found |= 1;
- break;
-
- case DUMB_ID('S','O','N','G'):
- if (/*(found & 2) ||*/ (c->len < 11) /*|| memcmp(c->data, "MAINSONG", 8)*/) goto error_sd;
- found |= 2;
- break;
-
- case DUMB_ID('D','S','M','P'):
- sigdata->n_samples++;
- break;
-
- case DUMB_ID('T','I','T','L'):
- length = min(sizeof(sigdata->name) - 1, c->len);
- memcpy(sigdata->name, c->data, length);
- sigdata->name[length] = 0;
- }
- }
-
- if (found != 3 || !sigdata->n_samples) goto error_sd;
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
- sigdata->n_orders = 0;
-
- for (n = 0; n < n_chunks; n++) {
- PSMCHUNK * c = &chunk[n];
- if (c->id == DUMB_ID('S','O','N','G')) {
- if (subsong == 0) break;
- subsong--;
- }
- }
-
- if (n == n_chunks) return NULL;
- subsong = n;
-
- /*for (n = 0; n < n_chunks; n++) {
- PSMCHUNK * c = &chunk[n];
- if (c->id == DUMB_ID('S','O','N','G')) {*/
- {
- PSMCHUNK * c = &chunk[subsong];
- {
- ptr = c->data;
- if (ptr[10] > 32) goto error_usd;
- sigdata->n_pchannels = ptr[10];
- length = c->len - 11;
- ptr += 11;
- songchunk = 0;
- if (length >= 8) {
- songchunk = malloc(128 * sizeof(*songchunk));
- if (!songchunk) goto error_usd;
- while (length >= 8) {
- songchunk[n_song_chunks].id = DUMB_ID(ptr[0], ptr[1], ptr[2], ptr[3]);
- n = ptr[4] | (ptr[5] << 8) | (ptr[6] << 16) | (ptr[7] << 24);
- length -= 8;
- if (n > length) goto error_sc;
- songchunk[n_song_chunks].len = n;
- songchunk[n_song_chunks].data = ptr + 8;
- n_song_chunks++;
- length -= n;
- ptr += 8 + n;
- }
- }
- /*break;*/
- }
- }
-
- if (!n_song_chunks) goto error_sc;
-
- found = 0;
-
- for (n = 0; n < n_song_chunks; n++) {
- PSMCHUNK * c = &songchunk[n];
-
- if (c->id == DUMB_ID('D','A','T','E')) {
- /* date of the library build / format spec */
- if (c->len == 6) {
- length = c->len;
- ptr = c->data;
- while (length > 0) {
- if (*ptr >= '0' && *ptr <= '9') {
- found = (found * 10) + (*ptr - '0');
- } else {
- found = 0;
- break;
- }
- ptr++;
- length--;
- }
- }
- break;
- }
- }
-
- /*
- if (found != 940506 &&
- found != 940509 &&
- found != 940510 &&
- found != 940530 &&
- found != 940629 &&
- found != PSMV_OLD &&
- found != 941011 &&
- found != PSMV_NEW &&
- found != 940906 &&
- found != 940903 &&
- found != 940914 &&
- found != 941213 &&
- found != 800211) /* WTF?
- goto error_sc;
- */
-
- *ver = found;
-
- if (found == 800211 ||
- found == PSMV_NEW ||
- found == 940903 ||
- found == 940906 ||
- found == 940914 ||
- found == 941213) found = PSMV_NEW;
- else found = PSMV_OLD;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
-
- for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
- sigdata->channel_pan[n ] = 16;
- sigdata->channel_pan[n+1] = 48;
- sigdata->channel_pan[n+2] = 48;
- sigdata->channel_pan[n+3] = 16;
- }
-
- for (n = 0; n < n_song_chunks; n++) {
- PSMCHUNK * c = &songchunk[n];
-
- switch (c->id) {
- case DUMB_ID('O','P','L','H'):
- if (c->len < 2) goto error_sc;
- ptr = c->data;
- o = ptr[0] | (ptr[1] << 8);
- if (!o) goto error_sc;
- event = malloc(o * sizeof(*event));
- if (!event) goto error_sc;
- length = c->len - 2;
- ptr += 2;
- while ((length > 0) && (n_events < o)) {
- event[n_events].type = *ptr;
- switch (*ptr) {
- case PSM_EVENT_END:
- ptr++;
- length--;
- break;
-
- case PSM_EVENT_PLAY_PATTERN:
- if (found == PSMV_OLD) {
- if (length < 5) goto error_ev;
- memcpy(event[n_events].data, ptr + 1, 4);
- ptr += 5;
- length -= 5;
- } else if (found == PSMV_NEW) {
- if (length < 9) goto error_ev;
- memcpy(event[n_events].data, ptr + 1, 8);
- ptr += 9;
- length -= 9;
- }
- break;
-
- case PSM_EVENT_SET_SPEED:
- case PSM_EVENT_SET_BPM:
- if (length < 2) goto error_ev;
- event[n_events].data[0] = ptr[1];
- ptr += 2;
- length -= 2;
- break;
-
- case PSM_EVENT_JUMP_TO_LINE:
- case PSM_EVENT_CHANGE_VOL:
- if (length < 3) goto error_ev;
- memcpy(event[n_events].data, ptr + 1, 2);
- ptr += 3;
- length -= 3;
- break;
-
- case PSM_EVENT_SAMPLE_MAP_TABLE:
- if (length < 7) goto error_ev;
- memcpy(event[n_events].data, ptr + 1, 6);
- ptr += 7;
- length -= 7;
- break;
-
- case PSM_EVENT_CHANGE_PAN:
- if (length < 4) goto error_ev;
- memcpy(event[n_events].data, ptr + 1, 3);
- ptr += 4;
- length -= 4;
- break;
-
- default:
- goto error_ev;
- }
- n_events++;
- }
- break;
-
- case DUMB_ID('P','P','A','N'):
- length = c->len;
- if (length & 1) goto error_ev;
- ptr = c->data;
- o = 0;
- while (length > 0) {
- switch (ptr[0]) {
- case 0:
- sigdata->channel_pan[o] = ((((int)(signed char)ptr[1]) * 32) / 127) + 32;
- break;
- case 2:
- sigdata->channel_pan[o] = IT_SURROUND;
- break;
- case 4:
- sigdata->channel_pan[o] = 32;
- break;
- }
- ptr += 2;
- length -= 2;
- if (++o >= DUMB_IT_N_CHANNELS) break;
- }
- break;
-
- /*
- case DUMB_ID('P','A','T','T'):
- case DUMB_ID('D','S','A','M'):
- */
- }
- }
-
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX;
-
- sigdata->global_volume = 128;
- sigdata->speed = 6;
- sigdata->tempo = 125;
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- speed = 0;
- bpm = 0;
- memset(pan, 255, sizeof(pan));
- memset(vol, 255, sizeof(vol));
-
- sigdata->n_patterns = n_events;
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) goto error_ev;
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
-
- for (n = 0; n < n_events; n++) {
- PSMEVENT * e = &event[n];
- switch (e->type) {
- case PSM_EVENT_END:
- n = n_events;
- break;
-
- case PSM_EVENT_PLAY_PATTERN:
- for (o = 0; o < n_chunks; o++) {
- PSMCHUNK * c = &chunk[o];
- if (c->id == DUMB_ID('P','B','O','D')) {
- ptr = c->data;
- length = c->len;
- if (found == PSMV_OLD) {
- if (length < 8) goto error_ev;
- if (!pattcmp(ptr + 4, e->data, 4)) {
- if (it_psm_process_pattern(&sigdata->pattern[n_patterns], ptr, length, speed, bpm, pan, vol, found)) goto error_ev;
- if (first_pattern_line < 0) {
- first_pattern_line = n;
- first_pattern = o;
- }
- e->data[0] = n_patterns;
- e->data[1] = n_patterns >> 8;
- n_patterns++;
- break;
- }
- } else if (found == PSMV_NEW) {
- if (length < 12) goto error_ev;
- if (!pattcmp(ptr + 4, e->data, 8)) {
- if (it_psm_process_pattern(&sigdata->pattern[n_patterns], ptr, length, speed, bpm, pan, vol, found)) goto error_ev;
- if (first_pattern_line < 0) {
- first_pattern_line = n;
- first_pattern = o;
- }
- e->data[0] = n_patterns;
- e->data[1] = n_patterns >> 8;
- n_patterns++;
- break;
- }
- }
- }
- }
- if (o == n_chunks) goto error_ev;
-
- speed = 0;
- bpm = 0;
- memset(pan, 255, sizeof(pan));
- memset(vol, 255, sizeof(vol));
-
- e->type = PSM_EVENT_END;
- break;
-
- case PSM_EVENT_JUMP_TO_LINE:
- o = e->data[0] | (e->data[1] << 8);
- if (o >= n_events) goto error_ev;
- if (o == 0) {
- /* whew! easy case! */
- sigdata->restart_position = 0;
- n = n_events;
- } else if (o == n) {
- /* freeze */
- n = n_events;
- } else if (o > n) {
- /* jump ahead, setting played event numbers to zero will prevent endless looping */
- n = o - 1;
- } else if (o >= first_pattern_line) {
- /* another semi-easy case */
- sigdata->restart_position = event[o].data[0] | (event[o].data[1] << 8);
- n = n_events;
- } else {
- /* crud, try to simulate rerunning all of the commands from the indicated
- * line up to the first pattern, then dupe the first pattern again.
- */
- /*
- PSMCHUNK * c = &chunk[first_pattern];
-
- for (; o < first_pattern_line; o++) {
- PSMEVENT * ev = &event[o];
- switch (ev->type) {
- case PSM_EVENT_SET_SPEED:
- speed = ev->data[0];
- break;
- case PSM_EVENT_SET_BPM:
- bpm = ev->data[0];
- break;
- case PSM_EVENT_CHANGE_PAN:
- if (ev->data[0] > 31) goto error_ev;
- pan[ev->data[0] * 2] = ev->data[1];
- pan[ev->data[0] * 2 + 1] = ev->data[2];
- break;
- case PSM_EVENT_CHANGE_VOL:
- if (ev->data[0] > 31) goto error_ev;
- vol[ev->data[0]] = ev->data[1];
- break;
- }
- }
-
- if (it_psm_process_pattern(&sigdata->pattern[n_patterns], c->data, c->len, speed, bpm, pan, vol, found)) goto error_ev;
- n_patterns++;
- sigdata->restart_position = 1;
- n = n_events;
-
- Eh, what the hell? PSM has no panning commands anyway.
- */
- sigdata->restart_position = 0;
- n = n_events;
- }
- e->type = PSM_EVENT_END;
- break;
-
- case PSM_EVENT_SET_SPEED:
- speed = e->data[0];
- break;
-
- case PSM_EVENT_SET_BPM:
- bpm = e->data[0];
- break;
-
- case PSM_EVENT_CHANGE_PAN:
- o = e->data[0];
- if (o > 31) goto error_ev;
- pan[o * 2] = e->data[1];
- pan[o * 2 + 1] = e->data[2];
- break;
-
- case PSM_EVENT_CHANGE_VOL:
- o = e->data[0];
- if (o > 31) goto error_ev;
- vol[o] = e->data[1];
- break;
-
- case PSM_EVENT_SAMPLE_MAP_TABLE:
- if (e->data[0] != 0 || e->data[1] != 0xFF ||
- e->data[2] != 0 || e->data[3] != 0 ||
- e->data[4] != 1 || e->data[5] != 0)
- goto error_ev;
- break;
- }
- }
-
- if (n_patterns > 256) goto error_ev;
-
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) goto error_ev;
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
-
- o = 0;
- for (n = 0; n < n_chunks; n++) {
- PSMCHUNK * c = &chunk[n];
- if (c->id == DUMB_ID('D','S','M','P')) {
- if (it_psm_process_sample(&sigdata->sample[o], c->data, c->len, o, found)) goto error_ev;
- o++;
- }
- }
-
- sigdata->n_orders = n_patterns;
- sigdata->n_patterns = n_patterns;
-
- sigdata->order = malloc(n_patterns);
-
- for (n = 0; n < n_patterns; n++) {
- sigdata->order[n] = n;
- }
-
- free(event);
- free(songchunk);
- free_chunks(chunk, n_chunks);
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- dumb_it_optimize_orders(sigdata);
-
- return sigdata;
-
-error_ev:
- free(event);
-error_sc:
- if (songchunk) free(songchunk);
-error_usd:
- _dumb_it_unload_sigdata(sigdata);
- goto error_fc;
-error_sd:
- free(sigdata);
-error_fc:
- free_chunks(chunk, n_chunks);
-error:
- return NULL;
-}
-
-static int it_order_compare(const void *e1, const void *e2) {
- if (*((const char *)e1) < *((const char *)e2))
- return -1;
-
- if (*((const char *)e1) > *((const char *)e2))
- return 1;
-
- return 0;
-}
-
-static int it_optimize_compare(const void *e1, const void *e2) {
- if (((const IT_ENTRY *)e1)->channel < ((const IT_ENTRY *)e2)->channel)
- return -1;
-
- if (((const IT_ENTRY *)e1)->channel > ((const IT_ENTRY *)e2)->channel)
- return 1;
-
- return 0;
-}
-
-static int it_entry_compare(const IT_ENTRY * e1, const IT_ENTRY * e2) {
- if (IT_IS_END_ROW(e1) && IT_IS_END_ROW(e2)) return 1;
- if (e1->channel != e2->channel) return 0;
- if (e1->mask != e2->mask) return 0;
- if ((e1->mask & IT_ENTRY_NOTE) && (e1->note != e2->note)) return 0;
- if ((e1->mask & IT_ENTRY_INSTRUMENT) && (e1->instrument != e2->instrument)) return 0;
- if ((e1->mask & IT_ENTRY_VOLPAN) && (e1->volpan != e2->volpan)) return 0;
- if ((e1->mask & IT_ENTRY_EFFECT) && ((e1->effect != e2->effect) || (e1->effectvalue != e2->effectvalue))) return 0;
- return 1;
-}
-
-/*
-static void dumb_it_optimize_pattern(IT_PATTERN * pattern) {
- IT_ENTRY * entry, * end;
- IT_ENTRY * rowstart, * rowend;
- IT_ENTRY * current;
-
- if (!pattern->n_entries || !pattern->entry) return;
-
- current = entry = pattern->entry;
- end = entry + pattern->n_entries;
-
- while (entry < end) {
- rowstart = entry;
- while (!IT_IS_END_ROW(entry)) entry++;
- rowend = entry;
- if (rowend > rowstart + 1)
- qsort(rowstart, rowend - rowstart, sizeof(IT_ENTRY), &it_optimize_compare);
- entry = rowstart;
- while (entry < rowend) {
- if (!(entry->mask)) {}
- else if (it_entry_compare(entry, current)) {}
- else if (!(current->mask) ||
- ((entry->channel == current->channel) &&
- ((entry->mask | current->mask) == (entry->mask ^ current->mask)))) {
- current->mask |= entry->mask;
- if (entry->mask & IT_ENTRY_NOTE) current->note = entry->note;
- if (entry->mask & IT_ENTRY_INSTRUMENT) current->instrument = entry->instrument;
- if (entry->mask & IT_ENTRY_VOLPAN) current->volpan = entry->volpan;
- if (entry->mask & IT_ENTRY_EFFECT) {
- current->effect = entry->effect;
- current->effectvalue = entry->effectvalue;
- }
- } else {
- if (++current < entry) *current = *entry;
- }
- entry++;
- }
- if (++current < entry) *current = *entry;
- entry++;
- }
-
- current++;
-
- if (current < end) {
- IT_ENTRY * opt;
- pattern->n_entries = current - pattern->entry;
- opt = realloc(pattern->entry, pattern->n_entries * sizeof(*pattern->entry));
- if (opt) pattern->entry = opt;
- }
-}
-*/
-
-static int it_pattern_compare(const IT_PATTERN * p1, const IT_PATTERN * p2) {
- IT_ENTRY * e1, * end;
- IT_ENTRY * e2;
-
- if (p1 == p2) return 1;
- if (p1->n_entries != p2->n_entries) return 0;
-
- e1 = p1->entry; end = e1 + p1->n_entries;
- e2 = p2->entry;
-
- while (e1 < end) {
- if (!it_entry_compare(e1, e2)) return 0;
- e1++; e2++;
- }
-
- return 1;
-}
-
-static void dumb_it_optimize_orders(DUMB_IT_SIGDATA * sigdata) {
- int n, o, p;
-
- int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253;
-
- unsigned char * order_list;
- int n_patterns;
-
- IT_PATTERN * pattern;
-
- if (!sigdata->n_orders || !sigdata->n_patterns) return;
-
- n_patterns = 0;
- order_list = malloc(sigdata->n_orders);
-
- if (!order_list) return;
-
- for (n = 0; n < sigdata->n_orders; n++) {
- if (sigdata->order[n] < sigdata->n_patterns) {
- for (o = 0; o < n_patterns; o++) {
- if (sigdata->order[n] == order_list[o]) break;
- }
- if (o == n_patterns) {
- order_list[n_patterns++] = sigdata->order[n];
- }
- }
- }
-
- if (!n_patterns) {
- free(order_list);
- return;
- }
-
- /*for (n = 0; n < n_patterns; n++) {
- dumb_it_optimize_pattern(&sigdata->pattern[order_list[n]]);
- }*/
-
- for (n = 0; n < n_patterns; n++) {
- for (o = n + 1; o < n_patterns; o++) {
- if ((order_list[n] != order_list[o]) &&
- it_pattern_compare(&sigdata->pattern[order_list[n]], &sigdata->pattern[order_list[o]])) {
- for (p = 0; p < sigdata->n_orders; p++) {
- if (sigdata->order[p] == order_list[o]) {
- sigdata->order[p] = order_list[n];
- }
- }
- for (p = o + 1; p < n_patterns; p++) {
- if (order_list[p] == order_list[o]) {
- order_list[p] = order_list[n];
- }
- }
- order_list[o] = order_list[n];
- }
- }
- }
-
- qsort(order_list, n_patterns, sizeof(*order_list), &it_order_compare);
-
- for (n = 0, o = 0; n < n_patterns; n++) {
- if (order_list[n] != order_list[o]) {
- if (++o < n) order_list[o] = order_list[n];
- }
- }
-
- n_patterns = o + 1;
-
- pattern = malloc(n_patterns * sizeof(*pattern));
- if (!pattern) {
- free(order_list);
- return;
- }
-
- for (n = 0; n < n_patterns; n++) {
- pattern[n] = sigdata->pattern[order_list[n]];
- }
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- for (o = 0; o < n_patterns; o++) {
- if (order_list[o] == n) break;
- }
- if (o == n_patterns) {
- if (sigdata->pattern[n].entry)
- free(sigdata->pattern[n].entry);
- }
- }
-
- free(sigdata->pattern);
- sigdata->pattern = pattern;
- sigdata->n_patterns = n_patterns;
-
- for (n = 0; n < sigdata->n_orders; n++) {
- for (o = 0; o < n_patterns; o++) {
- if (sigdata->order[n] == order_list[o]) {
- sigdata->order[n] = o;
- break;
- }
- }
- }
-
- free(order_list);
-}
-
-int dumb_get_psm_subsong_count(DUMBFILE *f) {
- int length, subsongs;
- long l;
-
- if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',' ')) return 0;
-
- length = dumbfile_igetl(f);
-
- if (dumbfile_mgetl(f) != DUMB_ID('F','I','L','E')) return 0;
-
- subsongs = 0;
-
- while (length >= 8 && !dumbfile_error(f)) {
- if (dumbfile_mgetl(f) == DUMB_ID('S','O','N','G')) subsongs++;
- l = dumbfile_igetl(f);
- dumbfile_skip(f, l);
- length -= l + 8;
- }
-
- if (dumbfile_error(f)) return 0;
-
- return subsongs;
-}
-
-
-
-/* Eww */
-int pattcmp( const unsigned char * a, const unsigned char * b, size_t l )
-{
- int i, j, na, nb;
- char * p;
-
- i = memcmp( a, b, l );
- if ( !i ) return i;
-
- /* damnit */
-
- for ( i = 0; i < l; ++i )
- {
- if ( a [i] >= '0' && a [i] <= '9' ) break;
- }
-
- if ( i < l )
- {
- na = strtoul( a + i, &p, 10 );
- if ( (const unsigned char *)p == a + i ) return 1;
- }
-
- for ( j = 0; j < l; ++j )
- {
- if ( b [j] >= '0' && b [j] <= '9' ) break;
- }
-
- if ( j < l )
- {
- nb = strtoul( b + j, &p, 10 );
- if ( (const unsigned char *)p == b + j ) return -1;
- }
-
- if ( i < j ) return -1;
- else if ( j > i ) return 1;
-
- i = memcmp( a, b, j );
- if ( i ) return i;
-
- return na - nb;
-}
-
-
-
-DUH *dumb_read_psm_quick(DUMBFILE *f, int subsong)
-{
- sigdata_t *sigdata;
- int ver;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_psm_load_sigdata(f, &ver, subsong);
-
- if (!sigdata)
- return NULL;
-
- {
- int n_tags = 2;
- char version[16];
- const char *tag[3][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "PSM";
- if ( ver )
- {
- tag[2][0] = "FORMATVERSION";
- snprintf (version, 10, "%d", ver);
- tag[2][1] = (const char *) &version;
- ++n_tags;
- }
- return make_duh(-1, n_tags, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readpsm.c - Code to read a Protracker Studio / / \ \ + * module from an open file. | < / \_ + * | \/ /\ / + * By Chris Moeller. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" +#include "internal/it.h" + +#define PSMV_OLD 940730 +#define PSMV_NEW 940902 + +typedef struct _PSMCHUNK +{ + int id; + int len; + unsigned char * data; +} PSMCHUNK; + +typedef struct _PSMEVENT +{ + int type; + unsigned char data[8]; +} PSMEVENT; + +#define PSM_EVENT_END 0 +#define PSM_EVENT_PLAY_PATTERN 1 +#define PSM_EVENT_JUMP_TO_LINE 4 +#define PSM_EVENT_SET_SPEED 7 +#define PSM_EVENT_SET_BPM 8 +#define PSM_EVENT_SAMPLE_MAP_TABLE 12 +#define PSM_EVENT_CHANGE_PAN 13 +#define PSM_EVENT_CHANGE_VOL 14 + +static int it_psm_process_sample(IT_SAMPLE * sample, const unsigned char * data, int len, int id, int version) { + int flags; + int insno; + int length; + int loopstart; + int loopend; + int panpos; + int defvol; + int samplerate; + + if (len < 0x60) return -1; + + flags = data[0]; + + if (version == PSMV_OLD) { + memcpy(sample->name, data + 0x0D, 34); + sample->name[34] = 0; + + insno = data[0x34] | (data[0x35] << 8); + length = data[0x36] | (data[0x37] << 8) | (data[0x38] << 16) | (data[0x39] << 24); + loopstart = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24); + loopend = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24); + panpos = data[0x43]; + defvol = data[0x44]; + samplerate = data[0x49] | (data[0x4A] << 8) | (data[0x4B] << 16) | (data[0x4C] << 24); + } else if (version == PSMV_NEW) { + memcpy(sample->name, data + 0x11, 34); + sample->name[34] = 0; + + insno = data[0x38] | (data[0x39] << 8); + length = data[0x3A] | (data[0x3B] << 8) | (data[0x3C] << 16) | (data[0x3D] << 24); + loopstart = data[0x3E] | (data[0x3F] << 8) | (data[0x40] << 16) | (data[0x41] << 24); + loopend = data[0x42] | (data[0x43] << 8) | (data[0x44] << 16) | (data[0x45] << 24); + panpos = data[0x48]; + defvol = data[0x49]; + samplerate = data[0x4E] | (data[0x4F] << 8) | (data[0x50] << 16) | (data[0x51] << 24); + } + + if (insno != id) return -1; + + if (!length) { + sample->flags &= ~IT_SAMPLE_EXISTS; + return 0; + } + + if ((length > len - 0x60) || ((flags & 0x7F) != 0)) return -1; + + sample->flags = IT_SAMPLE_EXISTS; + sample->length = length; + sample->loop_start = loopstart; + sample->loop_end = loopend; + sample->C5_speed = samplerate; + sample->default_volume = defvol >> 1; + sample->default_pan = 0; + sample->filename[0] = 0; + sample->global_volume = 64; + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = IT_VIBRATO_SINE; + sample->finetune = 0; + sample->max_resampling_quality = -1; + + if (flags & 0x80) { + if (((unsigned int)sample->loop_end <= (unsigned int)sample->length) && + ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end)) { + sample->length = sample->loop_end; + sample->flags |= IT_SAMPLE_LOOP; + } + } + + sample->data = malloc(sample->length); + if (!sample->data) + return -1; + + flags = 0; + data += 0x60; + + for (insno = 0; insno < sample->length; insno++) { + flags += (signed char)(*data++); + ((signed char *)sample->data)[insno] = flags; + } + + return 0; +} + +static int it_psm_process_pattern(IT_PATTERN * pattern, const unsigned char * data, int len, int speed, int bpm, const unsigned char * pan, const int * vol, int version) { + int length, nrows, row, rowlen, pos; + unsigned flags, chan; + IT_ENTRY * entry; + + length = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + if (len > length) len = length; + + if (version == PSMV_OLD) { + if (len < 10) return -1; + data += 8; + len -= 8; + } else if (version == PSMV_NEW) { + if (len < 14) return -1; + data += 12; + len -= 12; + } + + nrows = data[0] | (data[1] << 8); + + if (!nrows) return 0; + + pattern->n_rows = nrows; + + data += 2; + len -= 2; + + pattern->n_entries = 0; + + row = 0; + pos = 2; + rowlen = data[0] | (data[1] << 8); + + while ((row < nrows) && (pos < len)) { + if (pos >= rowlen) { + row++; + rowlen += data[pos] | (data[pos+1] << 8); + pos += 2; + continue; + } + + flags = data[pos++]; + chan = data[pos++]; + + if (chan > 63) return -1; + + if (flags & 0xF0) { + pattern->n_entries++; + if (flags & 0x80) pos++; + if (flags & 0x40) pos++; + if (flags & 0x20) pos++; + if (flags & 0x10) { + switch (data[pos]) { + case 0x29: + pos++; + case 0x33: + pos++; + default: + pos += 2; + } + } + } + } + + if (!pattern->n_entries) return 0; + + pattern->n_entries += nrows; + if (speed) pattern->n_entries++; + if (bpm >= 0x20) pattern->n_entries++; + + for (pos = 0; pos < 32; pos++) { + if (!(pan[pos*2+1] & 0xF9)) pattern->n_entries++; + if (vol[pos] != -1) pattern->n_entries++; + } + + pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); + if (!pattern->entry) return -1; + + entry = pattern->entry; + + if (speed) { + entry->channel = 0; + entry->mask = IT_ENTRY_EFFECT; + entry->effect = IT_SET_SPEED; + entry->effectvalue = speed; + entry++; + } + + if (bpm >= 0x20) { + entry->channel = 0; + entry->mask = IT_ENTRY_EFFECT; + entry->effect = IT_SET_SONG_TEMPO; + entry->effectvalue = bpm; + entry++; + } + + for (pos = 0; pos < 32; pos++) { + if (!(pan[pos*2+1] & 0xF9)) { + entry->channel = pos; + entry->mask = IT_ENTRY_EFFECT; + switch (pan[pos*2+1]) { + case 0: + entry->effect = IT_SET_PANNING; + entry->effectvalue = pan[pos*2] ^ 128; + break; + case 2: + entry->effect = IT_S; + entry->effectvalue = EFFECT_VALUE(IT_S_SET_SURROUND_SOUND,1); + break; + case 4: + entry->effect = IT_SET_PANNING; + entry->effectvalue = 128; + break; + } + entry++; + } + if (vol[pos] != -1) { + entry->channel = pos; + entry->mask = IT_ENTRY_EFFECT; + entry->effect = IT_SET_CHANNEL_VOLUME; + entry->effectvalue = (vol[pos] + 2) >> 2; + entry++; + } + } + + row = 0; + pos = 2; + rowlen = data[0] | (data[1] << 8); + + while ((row < nrows) && (pos < len)) { + if (pos >= rowlen) { + IT_SET_END_ROW(entry); + entry++; + row++; + rowlen += data[pos] | (data[pos+1] << 8); + pos += 2; + continue; + } + + flags = data[pos++]; + entry->channel = data[pos++]; + entry->mask = 0; + + if (flags & 0xF0) { + if (flags & 0x80) { + entry->mask |= IT_ENTRY_NOTE; + if (version == PSMV_OLD) { + if ((data[pos] < 0x80)) entry->note = (data[pos]>>4)*12+(data[pos]&0x0f)+12; + else entry->mask &= ~IT_ENTRY_NOTE; + } else if (version == PSMV_NEW) { + if ((data[pos]) && (data[pos] < 84)) entry->note = data[pos] + 35; + else entry->mask &= ~IT_ENTRY_NOTE; + } + pos++; + } + + if (flags & 0x40) { + entry->mask |= IT_ENTRY_INSTRUMENT; + entry->instrument = data[pos++] + 1; + } + + if (flags & 0x20) { + entry->mask |= IT_ENTRY_VOLPAN; + entry->volpan = (data[pos++] + 1) >> 1; + } + + if (flags & 0x10) { + entry->mask |= IT_ENTRY_EFFECT; + length = data[pos+1]; + switch (data[pos]) { + case 1: + entry->effect = IT_VOLUME_SLIDE; + if (version == PSMV_OLD) entry->effectvalue = ((length&0x1e)<<3) | 0xF; + else if (version == PSMV_NEW) entry->effectvalue = (length<<4) | 0xF; + break; + + case 2: + entry->effect = IT_VOLUME_SLIDE; + if (version == PSMV_OLD) entry->effectvalue = (length << 3) & 0xF0; + else if (version == PSMV_NEW) entry->effectvalue = (length << 4) & 0xF0; + break; + + case 3: + entry->effect = IT_VOLUME_SLIDE; + if (version == PSMV_OLD) entry->effectvalue = (length >> 1) | 0xF0; + else if (version == PSMV_NEW) entry->effectvalue = length | 0xF0; + break; + + case 4: + entry->effect = IT_VOLUME_SLIDE; + if (version == PSMV_OLD) entry->effectvalue = (length >> 1) & 0xF; + else if (version == PSMV_NEW) entry->effectvalue = length & 0xF; + break; + + case 12: + entry->effect = IT_PORTAMENTO_UP; + if (version == PSMV_OLD) { + if (length < 4) entry->effectvalue = length | 0xF0; + else entry->effectvalue = length >> 2; + } else if (version == PSMV_NEW) { + entry->effectvalue = length; + } + break; + + case 14: + entry->effect = IT_PORTAMENTO_DOWN; + if (version == PSMV_OLD) { + if (length < 4) entry->effectvalue = length | 0xF0; + else entry->effectvalue = length >> 2; + } else if (version == PSMV_NEW) { + entry->effectvalue = length; + } + break; + + case 15: + entry->effect = IT_TONE_PORTAMENTO; + if (version == PSMV_OLD) entry->effectvalue = length >> 2; + else if (version == PSMV_NEW) entry->effectvalue = length; + break; + + case 0x15: + entry->effect = IT_VIBRATO; + entry->effectvalue = length; + break; + + case 0x18: + entry->effect = IT_VOLSLIDE_VIBRATO; + entry->effectvalue = length; + break; + + case 0x29: + entry->effect = IT_SET_SAMPLE_OFFSET; + entry->effectvalue = data[pos+2]; + pos += 2; + break; + + case 0x2A: + entry->effect = IT_RETRIGGER_NOTE; + entry->effectvalue = length; + break; + + case 0x33: +#if 0 + entry->effect = IT_POSITION_JUMP; + entry->effectvalue = data[pos+2]; +#else + entry->mask &= ~IT_ENTRY_EFFECT; +#endif + pos++; + break; + + case 0x34: + entry->effect = IT_BREAK_TO_ROW; + entry->effectvalue = length; + break; + + case 0x3D: + entry->effect = IT_SET_SPEED; + entry->effectvalue = length; + break; + + case 0x3E: + if (length >= 0x20) { + entry->effect = IT_SET_SONG_TEMPO; + entry->effectvalue = length; + } else { + entry->mask &= ~IT_ENTRY_EFFECT; + } + break; + + case 0x47: + entry->effect = IT_ARPEGGIO; + entry->effectvalue = length; + break; + + default: + return -1; + } + pos += 2; + } + if (entry->mask) entry++; + } + } + + while (row < nrows) { + IT_SET_END_ROW(entry); + entry++; + row++; + } + + pattern->n_entries = entry - pattern->entry; + if (!pattern->n_entries) return -1; + + return 0; +} + + +static void free_chunks(PSMCHUNK * chunk, int count) { + int n; + + for (n = 0; n < count; n++) { + if (chunk[n].data) + free(chunk[n].data); + } + + free(chunk); +} + +static void dumb_it_optimize_orders(DUMB_IT_SIGDATA * sigdata); + +static int pattcmp( const unsigned char *, const unsigned char *, size_t ); + +static DUMB_IT_SIGDATA *it_psm_load_sigdata(DUMBFILE *f, int * ver, int subsong) +{ + DUMB_IT_SIGDATA *sigdata; + + PSMCHUNK *chunk; + int n_chunks = 0; + + PSMCHUNK *songchunk; + int n_song_chunks = 0; + + PSMEVENT *event = NULL; + int n_events = 0; + + unsigned char * ptr; + + int n, length, o; + + int found; + + int n_patterns = 0; + + int first_pattern_line = -1; + int first_pattern; + + int speed, bpm; + unsigned char pan[64]; + int vol[32]; + + if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',' ')) goto error; + + length = dumbfile_igetl(f); + + if (dumbfile_mgetl(f) != DUMB_ID('F','I','L','E')) goto error; + + chunk = calloc(768, sizeof(*chunk)); + + while (length >= 8) { + chunk[n_chunks].id = dumbfile_mgetl(f); + n = dumbfile_igetl(f); + length -= 8; + if (n < 0 || n > length) + goto error_fc; + chunk[n_chunks].len = n; + if (n) { + ptr = malloc(n); + if (!ptr) goto error_fc; + if (dumbfile_getnc(ptr, n, f) < n) + { + free(ptr); + goto error_fc; + } + chunk[n_chunks].data = ptr; + } + n_chunks++; + length -= n; + } + + if (!n_chunks) goto error_fc; + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) goto error_fc; + + sigdata->n_patterns = 0; + sigdata->n_samples = 0; + sigdata->name[0] = 0; + + found = 0; + + for (n = 0; n < n_chunks; n++) { + PSMCHUNK * c = &chunk[n]; + switch(c->id) { + case DUMB_ID('S','D','F','T'): + /* song data format? */ + if ((found & 1) || (c->len != 8) || memcmp(c->data, "MAINSONG", 8)) goto error_sd; + found |= 1; + break; + + case DUMB_ID('S','O','N','G'): + if (/*(found & 2) ||*/ (c->len < 11) /*|| memcmp(c->data, "MAINSONG", 8)*/) goto error_sd; + found |= 2; + break; + + case DUMB_ID('D','S','M','P'): + sigdata->n_samples++; + break; + + case DUMB_ID('T','I','T','L'): + length = min(sizeof(sigdata->name) - 1, c->len); + memcpy(sigdata->name, c->data, length); + sigdata->name[length] = 0; + } + } + + if (found != 3 || !sigdata->n_samples) goto error_sd; + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->sample = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->n_instruments = 0; + sigdata->n_orders = 0; + + for (n = 0; n < n_chunks; n++) { + PSMCHUNK * c = &chunk[n]; + if (c->id == DUMB_ID('S','O','N','G')) { + if (subsong == 0) break; + subsong--; + } + } + + if (n == n_chunks) return NULL; + subsong = n; + + /*for (n = 0; n < n_chunks; n++) { + PSMCHUNK * c = &chunk[n]; + if (c->id == DUMB_ID('S','O','N','G')) {*/ + { + PSMCHUNK * c = &chunk[subsong]; + { + ptr = c->data; + if (ptr[10] > 32) goto error_usd; + sigdata->n_pchannels = ptr[10]; + length = c->len - 11; + ptr += 11; + songchunk = 0; + if (length >= 8) { + songchunk = malloc(128 * sizeof(*songchunk)); + if (!songchunk) goto error_usd; + while (length >= 8) { + songchunk[n_song_chunks].id = DUMB_ID(ptr[0], ptr[1], ptr[2], ptr[3]); + n = ptr[4] | (ptr[5] << 8) | (ptr[6] << 16) | (ptr[7] << 24); + length -= 8; + if (n > length) goto error_sc; + songchunk[n_song_chunks].len = n; + songchunk[n_song_chunks].data = ptr + 8; + n_song_chunks++; + length -= n; + ptr += 8 + n; + } + } + /*break;*/ + } + } + + if (!n_song_chunks) goto error_sc; + + found = 0; + + for (n = 0; n < n_song_chunks; n++) { + PSMCHUNK * c = &songchunk[n]; + + if (c->id == DUMB_ID('D','A','T','E')) { + /* date of the library build / format spec */ + if (c->len == 6) { + length = c->len; + ptr = c->data; + while (length > 0) { + if (*ptr >= '0' && *ptr <= '9') { + found = (found * 10) + (*ptr - '0'); + } else { + found = 0; + break; + } + ptr++; + length--; + } + } + break; + } + } + + /* + if (found != 940506 && + found != 940509 && + found != 940510 && + found != 940530 && + found != 940629 && + found != PSMV_OLD && + found != 941011 && + found != PSMV_NEW && + found != 940906 && + found != 940903 && + found != 940914 && + found != 941213 && + found != 800211) /* WTF? + goto error_sc; + */ + + *ver = found; + + if (found == 800211 || + found == PSMV_NEW || + found == 940903 || + found == 940906 || + found == 940914 || + found == 941213) found = PSMV_NEW; + else found = PSMV_OLD; + + memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); + + for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) { + sigdata->channel_pan[n ] = 16; + sigdata->channel_pan[n+1] = 48; + sigdata->channel_pan[n+2] = 48; + sigdata->channel_pan[n+3] = 16; + } + + for (n = 0; n < n_song_chunks; n++) { + PSMCHUNK * c = &songchunk[n]; + + switch (c->id) { + case DUMB_ID('O','P','L','H'): + if (c->len < 2) goto error_sc; + ptr = c->data; + o = ptr[0] | (ptr[1] << 8); + if (!o) goto error_sc; + event = malloc(o * sizeof(*event)); + if (!event) goto error_sc; + length = c->len - 2; + ptr += 2; + while ((length > 0) && (n_events < o)) { + event[n_events].type = *ptr; + switch (*ptr) { + case PSM_EVENT_END: + ptr++; + length--; + break; + + case PSM_EVENT_PLAY_PATTERN: + if (found == PSMV_OLD) { + if (length < 5) goto error_ev; + memcpy(event[n_events].data, ptr + 1, 4); + ptr += 5; + length -= 5; + } else if (found == PSMV_NEW) { + if (length < 9) goto error_ev; + memcpy(event[n_events].data, ptr + 1, 8); + ptr += 9; + length -= 9; + } + break; + + case PSM_EVENT_SET_SPEED: + case PSM_EVENT_SET_BPM: + if (length < 2) goto error_ev; + event[n_events].data[0] = ptr[1]; + ptr += 2; + length -= 2; + break; + + case PSM_EVENT_JUMP_TO_LINE: + case PSM_EVENT_CHANGE_VOL: + if (length < 3) goto error_ev; + memcpy(event[n_events].data, ptr + 1, 2); + ptr += 3; + length -= 3; + break; + + case PSM_EVENT_SAMPLE_MAP_TABLE: + if (length < 7) goto error_ev; + memcpy(event[n_events].data, ptr + 1, 6); + ptr += 7; + length -= 7; + break; + + case PSM_EVENT_CHANGE_PAN: + if (length < 4) goto error_ev; + memcpy(event[n_events].data, ptr + 1, 3); + ptr += 4; + length -= 4; + break; + + default: + goto error_ev; + } + n_events++; + } + break; + + case DUMB_ID('P','P','A','N'): + length = c->len; + if (length & 1) goto error_ev; + ptr = c->data; + o = 0; + while (length > 0) { + switch (ptr[0]) { + case 0: + sigdata->channel_pan[o] = ((((int)(signed char)ptr[1]) * 32) / 127) + 32; + break; + case 2: + sigdata->channel_pan[o] = IT_SURROUND; + break; + case 4: + sigdata->channel_pan[o] = 32; + break; + } + ptr += 2; + length -= 2; + if (++o >= DUMB_IT_N_CHANNELS) break; + } + break; + + /* + case DUMB_ID('P','A','T','T'): + case DUMB_ID('D','S','A','M'): + */ + } + } + + sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX; + + sigdata->global_volume = 128; + sigdata->speed = 6; + sigdata->tempo = 125; + sigdata->mixing_volume = 48; + sigdata->pan_separation = 128; + + speed = 0; + bpm = 0; + memset(pan, 255, sizeof(pan)); + memset(vol, 255, sizeof(vol)); + + sigdata->n_patterns = n_events; + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) goto error_ev; + for (n = 0; n < sigdata->n_patterns; n++) + sigdata->pattern[n].entry = NULL; + + for (n = 0; n < n_events; n++) { + PSMEVENT * e = &event[n]; + switch (e->type) { + case PSM_EVENT_END: + n = n_events; + break; + + case PSM_EVENT_PLAY_PATTERN: + for (o = 0; o < n_chunks; o++) { + PSMCHUNK * c = &chunk[o]; + if (c->id == DUMB_ID('P','B','O','D')) { + ptr = c->data; + length = c->len; + if (found == PSMV_OLD) { + if (length < 8) goto error_ev; + if (!pattcmp(ptr + 4, e->data, 4)) { + if (it_psm_process_pattern(&sigdata->pattern[n_patterns], ptr, length, speed, bpm, pan, vol, found)) goto error_ev; + if (first_pattern_line < 0) { + first_pattern_line = n; + first_pattern = o; + } + e->data[0] = n_patterns; + e->data[1] = n_patterns >> 8; + n_patterns++; + break; + } + } else if (found == PSMV_NEW) { + if (length < 12) goto error_ev; + if (!pattcmp(ptr + 4, e->data, 8)) { + if (it_psm_process_pattern(&sigdata->pattern[n_patterns], ptr, length, speed, bpm, pan, vol, found)) goto error_ev; + if (first_pattern_line < 0) { + first_pattern_line = n; + first_pattern = o; + } + e->data[0] = n_patterns; + e->data[1] = n_patterns >> 8; + n_patterns++; + break; + } + } + } + } + if (o == n_chunks) goto error_ev; + + speed = 0; + bpm = 0; + memset(pan, 255, sizeof(pan)); + memset(vol, 255, sizeof(vol)); + + e->type = PSM_EVENT_END; + break; + + case PSM_EVENT_JUMP_TO_LINE: + o = e->data[0] | (e->data[1] << 8); + if (o >= n_events) goto error_ev; + if (o == 0) { + /* whew! easy case! */ + sigdata->restart_position = 0; + n = n_events; + } else if (o == n) { + /* freeze */ + n = n_events; + } else if (o > n) { + /* jump ahead, setting played event numbers to zero will prevent endless looping */ + n = o - 1; + } else if (o >= first_pattern_line) { + /* another semi-easy case */ + sigdata->restart_position = event[o].data[0] | (event[o].data[1] << 8); + n = n_events; + } else { + /* crud, try to simulate rerunning all of the commands from the indicated + * line up to the first pattern, then dupe the first pattern again. + */ + /* + PSMCHUNK * c = &chunk[first_pattern]; + + for (; o < first_pattern_line; o++) { + PSMEVENT * ev = &event[o]; + switch (ev->type) { + case PSM_EVENT_SET_SPEED: + speed = ev->data[0]; + break; + case PSM_EVENT_SET_BPM: + bpm = ev->data[0]; + break; + case PSM_EVENT_CHANGE_PAN: + if (ev->data[0] > 31) goto error_ev; + pan[ev->data[0] * 2] = ev->data[1]; + pan[ev->data[0] * 2 + 1] = ev->data[2]; + break; + case PSM_EVENT_CHANGE_VOL: + if (ev->data[0] > 31) goto error_ev; + vol[ev->data[0]] = ev->data[1]; + break; + } + } + + if (it_psm_process_pattern(&sigdata->pattern[n_patterns], c->data, c->len, speed, bpm, pan, vol, found)) goto error_ev; + n_patterns++; + sigdata->restart_position = 1; + n = n_events; + + Eh, what the hell? PSM has no panning commands anyway. + */ + sigdata->restart_position = 0; + n = n_events; + } + e->type = PSM_EVENT_END; + break; + + case PSM_EVENT_SET_SPEED: + speed = e->data[0]; + break; + + case PSM_EVENT_SET_BPM: + bpm = e->data[0]; + break; + + case PSM_EVENT_CHANGE_PAN: + o = e->data[0]; + if (o > 31) goto error_ev; + pan[o * 2] = e->data[1]; + pan[o * 2 + 1] = e->data[2]; + break; + + case PSM_EVENT_CHANGE_VOL: + o = e->data[0]; + if (o > 31) goto error_ev; + vol[o] = e->data[1]; + break; + + case PSM_EVENT_SAMPLE_MAP_TABLE: + if (e->data[0] != 0 || e->data[1] != 0xFF || + e->data[2] != 0 || e->data[3] != 0 || + e->data[4] != 1 || e->data[5] != 0) + goto error_ev; + break; + } + } + + if (n_patterns > 256) goto error_ev; + + sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); + if (!sigdata->sample) goto error_ev; + for (n = 0; n < sigdata->n_samples; n++) + sigdata->sample[n].data = NULL; + + o = 0; + for (n = 0; n < n_chunks; n++) { + PSMCHUNK * c = &chunk[n]; + if (c->id == DUMB_ID('D','S','M','P')) { + if (it_psm_process_sample(&sigdata->sample[o], c->data, c->len, o, found)) goto error_ev; + o++; + } + } + + sigdata->n_orders = n_patterns; + sigdata->n_patterns = n_patterns; + + sigdata->order = malloc(n_patterns); + + for (n = 0; n < n_patterns; n++) { + sigdata->order[n] = n; + } + + free(event); + free(songchunk); + free_chunks(chunk, n_chunks); + + _dumb_it_fix_invalid_orders(sigdata); + + dumb_it_optimize_orders(sigdata); + + return sigdata; + +error_ev: + free(event); +error_sc: + if (songchunk) free(songchunk); +error_usd: + _dumb_it_unload_sigdata(sigdata); + goto error_fc; +error_sd: + free(sigdata); +error_fc: + free_chunks(chunk, n_chunks); +error: + return NULL; +} + +static int it_order_compare(const void *e1, const void *e2) { + if (*((const char *)e1) < *((const char *)e2)) + return -1; + + if (*((const char *)e1) > *((const char *)e2)) + return 1; + + return 0; +} + +static int it_optimize_compare(const void *e1, const void *e2) { + if (((const IT_ENTRY *)e1)->channel < ((const IT_ENTRY *)e2)->channel) + return -1; + + if (((const IT_ENTRY *)e1)->channel > ((const IT_ENTRY *)e2)->channel) + return 1; + + return 0; +} + +static int it_entry_compare(const IT_ENTRY * e1, const IT_ENTRY * e2) { + if (IT_IS_END_ROW(e1) && IT_IS_END_ROW(e2)) return 1; + if (e1->channel != e2->channel) return 0; + if (e1->mask != e2->mask) return 0; + if ((e1->mask & IT_ENTRY_NOTE) && (e1->note != e2->note)) return 0; + if ((e1->mask & IT_ENTRY_INSTRUMENT) && (e1->instrument != e2->instrument)) return 0; + if ((e1->mask & IT_ENTRY_VOLPAN) && (e1->volpan != e2->volpan)) return 0; + if ((e1->mask & IT_ENTRY_EFFECT) && ((e1->effect != e2->effect) || (e1->effectvalue != e2->effectvalue))) return 0; + return 1; +} + +/* +static void dumb_it_optimize_pattern(IT_PATTERN * pattern) { + IT_ENTRY * entry, * end; + IT_ENTRY * rowstart, * rowend; + IT_ENTRY * current; + + if (!pattern->n_entries || !pattern->entry) return; + + current = entry = pattern->entry; + end = entry + pattern->n_entries; + + while (entry < end) { + rowstart = entry; + while (!IT_IS_END_ROW(entry)) entry++; + rowend = entry; + if (rowend > rowstart + 1) + qsort(rowstart, rowend - rowstart, sizeof(IT_ENTRY), &it_optimize_compare); + entry = rowstart; + while (entry < rowend) { + if (!(entry->mask)) {} + else if (it_entry_compare(entry, current)) {} + else if (!(current->mask) || + ((entry->channel == current->channel) && + ((entry->mask | current->mask) == (entry->mask ^ current->mask)))) { + current->mask |= entry->mask; + if (entry->mask & IT_ENTRY_NOTE) current->note = entry->note; + if (entry->mask & IT_ENTRY_INSTRUMENT) current->instrument = entry->instrument; + if (entry->mask & IT_ENTRY_VOLPAN) current->volpan = entry->volpan; + if (entry->mask & IT_ENTRY_EFFECT) { + current->effect = entry->effect; + current->effectvalue = entry->effectvalue; + } + } else { + if (++current < entry) *current = *entry; + } + entry++; + } + if (++current < entry) *current = *entry; + entry++; + } + + current++; + + if (current < end) { + IT_ENTRY * opt; + pattern->n_entries = current - pattern->entry; + opt = realloc(pattern->entry, pattern->n_entries * sizeof(*pattern->entry)); + if (opt) pattern->entry = opt; + } +} +*/ + +static int it_pattern_compare(const IT_PATTERN * p1, const IT_PATTERN * p2) { + IT_ENTRY * e1, * end; + IT_ENTRY * e2; + + if (p1 == p2) return 1; + if (p1->n_entries != p2->n_entries) return 0; + + e1 = p1->entry; end = e1 + p1->n_entries; + e2 = p2->entry; + + while (e1 < end) { + if (!it_entry_compare(e1, e2)) return 0; + e1++; e2++; + } + + return 1; +} + +static void dumb_it_optimize_orders(DUMB_IT_SIGDATA * sigdata) { + int n, o, p; + + int last_invalid = (sigdata->flags & IT_WAS_AN_XM) ? 255 : 253; + + unsigned char * order_list; + int n_patterns; + + IT_PATTERN * pattern; + + if (!sigdata->n_orders || !sigdata->n_patterns) return; + + n_patterns = 0; + order_list = malloc(sigdata->n_orders); + + if (!order_list) return; + + for (n = 0; n < sigdata->n_orders; n++) { + if (sigdata->order[n] < sigdata->n_patterns) { + for (o = 0; o < n_patterns; o++) { + if (sigdata->order[n] == order_list[o]) break; + } + if (o == n_patterns) { + order_list[n_patterns++] = sigdata->order[n]; + } + } + } + + if (!n_patterns) { + free(order_list); + return; + } + + /*for (n = 0; n < n_patterns; n++) { + dumb_it_optimize_pattern(&sigdata->pattern[order_list[n]]); + }*/ + + for (n = 0; n < n_patterns; n++) { + for (o = n + 1; o < n_patterns; o++) { + if ((order_list[n] != order_list[o]) && + it_pattern_compare(&sigdata->pattern[order_list[n]], &sigdata->pattern[order_list[o]])) { + for (p = 0; p < sigdata->n_orders; p++) { + if (sigdata->order[p] == order_list[o]) { + sigdata->order[p] = order_list[n]; + } + } + for (p = o + 1; p < n_patterns; p++) { + if (order_list[p] == order_list[o]) { + order_list[p] = order_list[n]; + } + } + order_list[o] = order_list[n]; + } + } + } + + qsort(order_list, n_patterns, sizeof(*order_list), &it_order_compare); + + for (n = 0, o = 0; n < n_patterns; n++) { + if (order_list[n] != order_list[o]) { + if (++o < n) order_list[o] = order_list[n]; + } + } + + n_patterns = o + 1; + + pattern = malloc(n_patterns * sizeof(*pattern)); + if (!pattern) { + free(order_list); + return; + } + + for (n = 0; n < n_patterns; n++) { + pattern[n] = sigdata->pattern[order_list[n]]; + } + + for (n = 0; n < sigdata->n_patterns; n++) { + for (o = 0; o < n_patterns; o++) { + if (order_list[o] == n) break; + } + if (o == n_patterns) { + if (sigdata->pattern[n].entry) + free(sigdata->pattern[n].entry); + } + } + + free(sigdata->pattern); + sigdata->pattern = pattern; + sigdata->n_patterns = n_patterns; + + for (n = 0; n < sigdata->n_orders; n++) { + for (o = 0; o < n_patterns; o++) { + if (sigdata->order[n] == order_list[o]) { + sigdata->order[n] = o; + break; + } + } + } + + free(order_list); +} + +int dumb_get_psm_subsong_count(DUMBFILE *f) { + int length, subsongs; + long l; + + if (dumbfile_mgetl(f) != DUMB_ID('P','S','M',' ')) return 0; + + length = dumbfile_igetl(f); + + if (dumbfile_mgetl(f) != DUMB_ID('F','I','L','E')) return 0; + + subsongs = 0; + + while (length >= 8 && !dumbfile_error(f)) { + if (dumbfile_mgetl(f) == DUMB_ID('S','O','N','G')) subsongs++; + l = dumbfile_igetl(f); + dumbfile_skip(f, l); + length -= l + 8; + } + + if (dumbfile_error(f)) return 0; + + return subsongs; +} + + + +/* Eww */ +int pattcmp( const unsigned char * a, const unsigned char * b, size_t l ) +{ + int i, j, na, nb; + char * p; + + i = memcmp( a, b, l ); + if ( !i ) return i; + + /* damnit */ + + for ( i = 0; i < l; ++i ) + { + if ( a [i] >= '0' && a [i] <= '9' ) break; + } + + if ( i < l ) + { + na = strtoul( a + i, &p, 10 ); + if ( (const unsigned char *)p == a + i ) return 1; + } + + for ( j = 0; j < l; ++j ) + { + if ( b [j] >= '0' && b [j] <= '9' ) break; + } + + if ( j < l ) + { + nb = strtoul( b + j, &p, 10 ); + if ( (const unsigned char *)p == b + j ) return -1; + } + + if ( i < j ) return -1; + else if ( j > i ) return 1; + + i = memcmp( a, b, j ); + if ( i ) return i; + + return na - nb; +} + + + +DUH *dumb_read_psm_quick(DUMBFILE *f, int subsong) +{ + sigdata_t *sigdata; + int ver; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_psm_load_sigdata(f, &ver, subsong); + + if (!sigdata) + return NULL; + + { + int n_tags = 2; + char version[16]; + const char *tag[3][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = "PSM"; + if ( ver ) + { + tag[2][0] = "FORMATVERSION"; + snprintf (version, 10, "%d", ver); + tag[2][1] = (const char *) &version; + ++n_tags; + } + return make_duh(-1, n_tags, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/readptm.c b/plugins/dumb/dumb-kode54/src/it/readptm.c index d8c77297..cae73edf 100644 --- a/plugins/dumb/dumb-kode54/src/it/readptm.c +++ b/plugins/dumb/dumb-kode54/src/it/readptm.c @@ -1,574 +1,574 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readptm.c - Code to read a Poly Tracker v2.03 / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. Based on reads3m.c \_ / > /
- * by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-// IT_STEREO... :o
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/** WARNING: this is duplicated in itread.c */
-static int it_seek(DUMBFILE *f, long offset)
-{
- long pos = dumbfile_pos(f);
-
- if (pos > offset)
- return -1;
-
- if (pos < offset)
- if (dumbfile_skip(f, offset - pos))
- return -1;
-
- return 0;
-}
-
-
-
-static int it_ptm_read_sample_header(IT_SAMPLE *sample, long *offset, DUMBFILE *f)
-{
- int flags;
-
- flags = dumbfile_getc(f);
-
- dumbfile_getnc(sample->filename, 12, f);
- sample->filename[12] = 0;
-
- sample->default_volume = dumbfile_getc(f);
-
- sample->C5_speed = dumbfile_igetw(f) << 1;
-
- dumbfile_skip(f, 2); /* segment */
-
- *offset = dumbfile_igetl(f);
-
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = dumbfile_igetl(f);
-
- /* GUSBegin, GUSLStart, GUSLEnd, GUSLoop, reserverd */
- dumbfile_skip(f, 4+4+4+1+1);
-
- dumbfile_getnc(sample->name, 28, f);
- sample->name[28] = 0;
-
- /*
- if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','S'))
- return -1;
- */
-
- /* BLAH! Shit likes to have broken or missing sample IDs */
- dumbfile_skip(f, 4);
-
- if ((flags & 3) == 0) {
- /* Looks like no sample */
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return dumbfile_error(f);
- }
-
- sample->global_volume = 64;
-
- sample->flags = IT_SAMPLE_EXISTS;
- if (flags & 4) sample->flags |= IT_SAMPLE_LOOP;
- if (flags & 8) sample->flags |= IT_SAMPLE_PINGPONG_LOOP;
-
- if (flags & 16) {
- sample->flags |= IT_SAMPLE_16BIT;
-
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- }
-
- if (sample->loop_end) sample->loop_end--;
-
- sample->default_pan = 0; // 0 = don't use, or 160 = centre?
-
- if (sample->length <= 0)
- sample->flags &= ~IT_SAMPLE_EXISTS;
- else if (sample->flags & IT_SAMPLE_LOOP) {
- if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else
- sample->length = sample->loop_end;
- }
-
-
- //Do we need to set all these?
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-
-static int it_ptm_read_byte(DUMBFILE *f)
-{
- int meh = dumbfile_getc(f);
- if (meh < 0) return 0;
- return meh;
-}
-
-static int it_ptm_read_sample_data(IT_SAMPLE *sample, int last, DUMBFILE *f)
-{
- long n;
- int s;
-
- sample->data = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
- if (!sample->data)
- return -1;
-
- s = 0;
-
- if (sample->flags & IT_SAMPLE_16BIT) {
- unsigned char a, b;
- for (n = 0; n < sample->length; n++) {
- a = s += (signed char) it_ptm_read_byte(f);
- b = s += (signed char) it_ptm_read_byte(f);
- ((short *)sample->data)[n] = a | (b << 8);
- }
- } else {
- for (n = 0; n < sample->length; n++) {
- s += (signed char) it_ptm_read_byte(f);
- ((signed char *)sample->data)[n] = s;
- }
- }
-
- if (dumbfile_error(f) && !last)
- return -1;
-
- return 0;
-}
-
-
-
-static int it_ptm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int length)
-{
- int buflen = 0;
- int bufpos = 0;
- int effect, effectvalue;
-
- IT_ENTRY *entry;
-
- unsigned char channel;
-
- if (!length)
- return -1;
-
- pattern->n_rows = 0;
- pattern->n_entries = 0;
-
- /* Read in the pattern data, little by little, and work out how many
- * entries we need room for. Sorry, but this is just so funny...
- */
- for (;;) {
- unsigned char b = buffer[buflen++] = dumbfile_getc(f);
-
-#if 1
- static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
- channel = b & 31;
- b >>= 5;
- pattern->n_entries++;
- if (b) {
- if (buflen + used[b] >= 65536) return -1;
- dumbfile_getnc(buffer + buflen, used[b], f);
- buflen += used[b];
- } else {
- /* End of row */
- if (++pattern->n_rows == 64) break;
- if (buflen >= 65536) return -1;
- }
-#else
- if (b == 0) {
- /* End of row */
- pattern->n_entries++;
- if (++pattern->n_rows == 64) break;
- if (buflen >= 65536) return -1;
- } else {
- static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5};
- channel = b & 31;
- b >>= 5;
- if (b) {
- pattern->n_entries++;
- if (buflen + used[b] >= 65536) return -1;
- dumbfile_getnc(buffer + buflen, used[b], f);
- buflen += used[b];
- }
- }
-#endif
-
- /* We have ensured that buflen < 65536 at this point, so it is safe
- * to iterate and read at least one more byte without checking.
- * However, now would be a good time to check for errors reading from
- * the file.
- */
-
- if (dumbfile_error(f))
- return -1;
-
- /* Great. We ran out of data, but there should be data for more rows.
- * Fill the rest with null data...
- */
- if (buflen >= length && pattern->n_rows < 64)
- {
- while (pattern->n_rows < 64)
- {
- if (buflen >= 65536) return -1;
- buffer[buflen++] = 0;
- pattern->n_entries++;
- pattern->n_rows++;
- }
- break;
- }
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
-
- if (!pattern->entry)
- return -1;
-
- entry = pattern->entry;
-
- while (bufpos < buflen) {
- unsigned char b = buffer[bufpos++];
-
- if (b == 0)
- {
- /* End of row */
- IT_SET_END_ROW(entry);
- entry++;
- continue;
- }
-
- channel = b & 31;
-
- if (b & 224) {
- entry->mask = 0;
- entry->channel = channel;
-
- if (b & 32) {
- unsigned char n = buffer[bufpos++];
- if (n == 254 || (n >= 1 && n <= 120)) {
- if (n == 254)
- entry->note = IT_NOTE_CUT;
- else
- entry->note = n - 1;
- entry->mask |= IT_ENTRY_NOTE;
- }
-
- entry->instrument = buffer[bufpos++];
- if (entry->instrument)
- entry->mask |= IT_ENTRY_INSTRUMENT;
- }
-
- if (b & 64) {
- effect = buffer[bufpos++];
- effectvalue = buffer[bufpos++];
- _dumb_it_ptm_convert_effect(effect, effectvalue, entry);
- }
-
- if (b & 128) {
- entry->volpan = buffer[bufpos++];
- if (entry->volpan <= 64)
- entry->mask |= IT_ENTRY_VOLPAN;
- }
-
- entry++;
- }
- }
-
- ASSERT(entry == pattern->entry + pattern->n_entries);
-
- return 0;
-}
-
-
-
-/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */
-/* Currently we assume the sample data are stored after the sample headers in
- * module files. This assumption may be unjustified; let me know if you have
- * trouble.
- */
-
-#define PTM_COMPONENT_INSTRUMENT 1
-#define PTM_COMPONENT_PATTERN 2
-#define PTM_COMPONENT_SAMPLE 3
-
-typedef struct PTM_COMPONENT
-{
- unsigned char type;
- unsigned char n;
- long offset;
-}
-PTM_COMPONENT;
-
-
-
-static int ptm_component_compare(const void *e1, const void *e2)
-{
- return ((const PTM_COMPONENT *)e1)->offset -
- ((const PTM_COMPONENT *)e2)->offset;
-}
-
-
-
-static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- PTM_COMPONENT *component;
- int n_components = 0;
-
- int n;
-
- unsigned char *buffer;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) return NULL;
-
- /* Skip song name. */
- dumbfile_getnc(sigdata->name, 28, f);
- sigdata->name[28] = 0;
-
- if (dumbfile_getc(f) != 0x1A || dumbfile_igetw(f) != 0x203) {
- free(sigdata);
- return NULL;
- }
-
- dumbfile_skip(f, 1);
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_orders = dumbfile_igetw(f);
- sigdata->n_instruments = 0;
- sigdata->n_samples = dumbfile_igetw(f);
- sigdata->n_patterns = dumbfile_igetw(f);
-
- if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 255 || sigdata->n_patterns > 128) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->n_pchannels = dumbfile_igetw(f);
-
- if (dumbfile_igetw(f) != 0) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- dumbfile_skip(f, 2);
-
- if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','F')) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- dumbfile_skip(f, 16);
-
- sigdata->order = malloc(sigdata->n_orders);
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (sigdata->n_samples) {
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
- }
-
- if (sigdata->n_patterns) {
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
- }
-
- /** WARNING: which ones? */
- sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_A_PTM;
-
- sigdata->global_volume = 128;
- sigdata->speed = 6;
- sigdata->tempo = 125;
- sigdata->mixing_volume = 48;
-
- /* Panning positions for 32 channels */
- {
- int i;
- for (i = 0; i < 32; i++) {
- int c = dumbfile_getc(f);
- if (c <= 15) {
- sigdata->channel_volume[i] = 64;
- sigdata->channel_pan[i] = c;
- } else {
- /** WARNING: this could be improved if we support channel muting... */
- sigdata->channel_volume[i] = 0;
- sigdata->channel_pan[i] = 7;
- }
- }
- }
-
- /* Orders, byte each, length = sigdata->n_orders (should be even) */
- dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
- sigdata->restart_position = 0;
-
- component = malloc(768*sizeof(*component));
- if (!component) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (it_seek(f, 352)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- component[n_components].type = PTM_COMPONENT_PATTERN;
- component[n_components].n = n;
- component[n_components].offset = dumbfile_igetw(f) << 4;
- n_components++;
- }
-
- if (it_seek(f, 608)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < sigdata->n_samples; n++) {
- if (it_ptm_read_sample_header(&sigdata->sample[n], &component[n_components].offset, f)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- if (!(sigdata->sample[n].flags & IT_SAMPLE_EXISTS)) continue;
- component[n_components].type = PTM_COMPONENT_SAMPLE;
- component[n_components].n = n;
- n_components++;
- }
-
- qsort(component, n_components, sizeof(PTM_COMPONENT), &ptm_component_compare);
-
- {
- int i;
- for (i = 0; i < 32; i++) {
- sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3;
- sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7;
- if (sigdata->channel_pan[i] > 64) sigdata->channel_pan[i] = 64;
- }
- }
-
- sigdata->pan_separation = 128;
-
- if (dumbfile_error(f)) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- buffer = malloc(65536);
- if (!buffer) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < n_components; n++) {
- if (it_seek(f, component[n].offset)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- switch (component[n].type) {
-
- case PTM_COMPONENT_PATTERN:
- if (it_ptm_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- break;
-
- case PTM_COMPONENT_SAMPLE:
- if (it_ptm_read_sample_data(&sigdata->sample[component[n].n], (n + 1 == n_components), f)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- }
-
- free(buffer);
- free(component);
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-static char hexdigit(int in)
-{
- if (in < 10) return in + '0';
- else return in + 'A' - 10;
-}
-
-DUH *dumb_read_ptm_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_ptm_load_sigdata(f);
-
- if (!sigdata)
- return NULL;
-
- {
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "PTM";
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readptm.c - Code to read a Poly Tracker v2.03 / / \ \ + * module from an open file. | < / \_ + * | \/ /\ / + * By Chris Moeller. Based on reads3m.c \_ / > / + * by entheh. | \ / / + * | ' / + * \__/ + */ + +// IT_STEREO... :o +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" +#include "internal/it.h" + + + +/** WARNING: this is duplicated in itread.c */ +static int it_seek(DUMBFILE *f, long offset) +{ + long pos = dumbfile_pos(f); + + if (pos > offset) + return -1; + + if (pos < offset) + if (dumbfile_skip(f, offset - pos)) + return -1; + + return 0; +} + + + +static int it_ptm_read_sample_header(IT_SAMPLE *sample, long *offset, DUMBFILE *f) +{ + int flags; + + flags = dumbfile_getc(f); + + dumbfile_getnc(sample->filename, 12, f); + sample->filename[12] = 0; + + sample->default_volume = dumbfile_getc(f); + + sample->C5_speed = dumbfile_igetw(f) << 1; + + dumbfile_skip(f, 2); /* segment */ + + *offset = dumbfile_igetl(f); + + sample->length = dumbfile_igetl(f); + sample->loop_start = dumbfile_igetl(f); + sample->loop_end = dumbfile_igetl(f); + + /* GUSBegin, GUSLStart, GUSLEnd, GUSLoop, reserverd */ + dumbfile_skip(f, 4+4+4+1+1); + + dumbfile_getnc(sample->name, 28, f); + sample->name[28] = 0; + + /* + if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','S')) + return -1; + */ + + /* BLAH! Shit likes to have broken or missing sample IDs */ + dumbfile_skip(f, 4); + + if ((flags & 3) == 0) { + /* Looks like no sample */ + sample->flags &= ~IT_SAMPLE_EXISTS; + return dumbfile_error(f); + } + + sample->global_volume = 64; + + sample->flags = IT_SAMPLE_EXISTS; + if (flags & 4) sample->flags |= IT_SAMPLE_LOOP; + if (flags & 8) sample->flags |= IT_SAMPLE_PINGPONG_LOOP; + + if (flags & 16) { + sample->flags |= IT_SAMPLE_16BIT; + + sample->length >>= 1; + sample->loop_start >>= 1; + sample->loop_end >>= 1; + } + + if (sample->loop_end) sample->loop_end--; + + sample->default_pan = 0; // 0 = don't use, or 160 = centre? + + if (sample->length <= 0) + sample->flags &= ~IT_SAMPLE_EXISTS; + else if (sample->flags & IT_SAMPLE_LOOP) { + if ((unsigned int)sample->loop_end > (unsigned int)sample->length) + sample->flags &= ~IT_SAMPLE_LOOP; + else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end) + sample->flags &= ~IT_SAMPLE_LOOP; + else + sample->length = sample->loop_end; + } + + + //Do we need to set all these? + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = IT_VIBRATO_SINE; + sample->finetune = 0; + sample->max_resampling_quality = -1; + + return dumbfile_error(f); +} + + +static int it_ptm_read_byte(DUMBFILE *f) +{ + int meh = dumbfile_getc(f); + if (meh < 0) return 0; + return meh; +} + +static int it_ptm_read_sample_data(IT_SAMPLE *sample, int last, DUMBFILE *f) +{ + long n; + int s; + + sample->data = malloc(sample->length * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1)); + if (!sample->data) + return -1; + + s = 0; + + if (sample->flags & IT_SAMPLE_16BIT) { + unsigned char a, b; + for (n = 0; n < sample->length; n++) { + a = s += (signed char) it_ptm_read_byte(f); + b = s += (signed char) it_ptm_read_byte(f); + ((short *)sample->data)[n] = a | (b << 8); + } + } else { + for (n = 0; n < sample->length; n++) { + s += (signed char) it_ptm_read_byte(f); + ((signed char *)sample->data)[n] = s; + } + } + + if (dumbfile_error(f) && !last) + return -1; + + return 0; +} + + + +static int it_ptm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int length) +{ + int buflen = 0; + int bufpos = 0; + int effect, effectvalue; + + IT_ENTRY *entry; + + unsigned char channel; + + if (!length) + return -1; + + pattern->n_rows = 0; + pattern->n_entries = 0; + + /* Read in the pattern data, little by little, and work out how many + * entries we need room for. Sorry, but this is just so funny... + */ + for (;;) { + unsigned char b = buffer[buflen++] = dumbfile_getc(f); + +#if 1 + static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5}; + channel = b & 31; + b >>= 5; + pattern->n_entries++; + if (b) { + if (buflen + used[b] >= 65536) return -1; + dumbfile_getnc(buffer + buflen, used[b], f); + buflen += used[b]; + } else { + /* End of row */ + if (++pattern->n_rows == 64) break; + if (buflen >= 65536) return -1; + } +#else + if (b == 0) { + /* End of row */ + pattern->n_entries++; + if (++pattern->n_rows == 64) break; + if (buflen >= 65536) return -1; + } else { + static const unsigned char used[8] = {0, 2, 2, 4, 1, 3, 3, 5}; + channel = b & 31; + b >>= 5; + if (b) { + pattern->n_entries++; + if (buflen + used[b] >= 65536) return -1; + dumbfile_getnc(buffer + buflen, used[b], f); + buflen += used[b]; + } + } +#endif + + /* We have ensured that buflen < 65536 at this point, so it is safe + * to iterate and read at least one more byte without checking. + * However, now would be a good time to check for errors reading from + * the file. + */ + + if (dumbfile_error(f)) + return -1; + + /* Great. We ran out of data, but there should be data for more rows. + * Fill the rest with null data... + */ + if (buflen >= length && pattern->n_rows < 64) + { + while (pattern->n_rows < 64) + { + if (buflen >= 65536) return -1; + buffer[buflen++] = 0; + pattern->n_entries++; + pattern->n_rows++; + } + break; + } + } + + pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); + + if (!pattern->entry) + return -1; + + entry = pattern->entry; + + while (bufpos < buflen) { + unsigned char b = buffer[bufpos++]; + + if (b == 0) + { + /* End of row */ + IT_SET_END_ROW(entry); + entry++; + continue; + } + + channel = b & 31; + + if (b & 224) { + entry->mask = 0; + entry->channel = channel; + + if (b & 32) { + unsigned char n = buffer[bufpos++]; + if (n == 254 || (n >= 1 && n <= 120)) { + if (n == 254) + entry->note = IT_NOTE_CUT; + else + entry->note = n - 1; + entry->mask |= IT_ENTRY_NOTE; + } + + entry->instrument = buffer[bufpos++]; + if (entry->instrument) + entry->mask |= IT_ENTRY_INSTRUMENT; + } + + if (b & 64) { + effect = buffer[bufpos++]; + effectvalue = buffer[bufpos++]; + _dumb_it_ptm_convert_effect(effect, effectvalue, entry); + } + + if (b & 128) { + entry->volpan = buffer[bufpos++]; + if (entry->volpan <= 64) + entry->mask |= IT_ENTRY_VOLPAN; + } + + entry++; + } + } + + ASSERT(entry == pattern->entry + pattern->n_entries); + + return 0; +} + + + +/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */ +/* Currently we assume the sample data are stored after the sample headers in + * module files. This assumption may be unjustified; let me know if you have + * trouble. + */ + +#define PTM_COMPONENT_INSTRUMENT 1 +#define PTM_COMPONENT_PATTERN 2 +#define PTM_COMPONENT_SAMPLE 3 + +typedef struct PTM_COMPONENT +{ + unsigned char type; + unsigned char n; + long offset; +} +PTM_COMPONENT; + + + +static int ptm_component_compare(const void *e1, const void *e2) +{ + return ((const PTM_COMPONENT *)e1)->offset - + ((const PTM_COMPONENT *)e2)->offset; +} + + + +static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f) +{ + DUMB_IT_SIGDATA *sigdata; + + PTM_COMPONENT *component; + int n_components = 0; + + int n; + + unsigned char *buffer; + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) return NULL; + + /* Skip song name. */ + dumbfile_getnc(sigdata->name, 28, f); + sigdata->name[28] = 0; + + if (dumbfile_getc(f) != 0x1A || dumbfile_igetw(f) != 0x203) { + free(sigdata); + return NULL; + } + + dumbfile_skip(f, 1); + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->sample = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->n_orders = dumbfile_igetw(f); + sigdata->n_instruments = 0; + sigdata->n_samples = dumbfile_igetw(f); + sigdata->n_patterns = dumbfile_igetw(f); + + if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 255 || sigdata->n_patterns > 128) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + sigdata->n_pchannels = dumbfile_igetw(f); + + if (dumbfile_igetw(f) != 0) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + dumbfile_skip(f, 2); + + if (dumbfile_mgetl(f) != DUMB_ID('P','T','M','F')) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + dumbfile_skip(f, 16); + + sigdata->order = malloc(sigdata->n_orders); + if (!sigdata->order) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (sigdata->n_samples) { + sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); + if (!sigdata->sample) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (n = 0; n < sigdata->n_samples; n++) + sigdata->sample[n].data = NULL; + } + + if (sigdata->n_patterns) { + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (n = 0; n < sigdata->n_patterns; n++) + sigdata->pattern[n].entry = NULL; + } + + /** WARNING: which ones? */ + sigdata->flags = IT_STEREO | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_A_PTM; + + sigdata->global_volume = 128; + sigdata->speed = 6; + sigdata->tempo = 125; + sigdata->mixing_volume = 48; + + /* Panning positions for 32 channels */ + { + int i; + for (i = 0; i < 32; i++) { + int c = dumbfile_getc(f); + if (c <= 15) { + sigdata->channel_volume[i] = 64; + sigdata->channel_pan[i] = c; + } else { + /** WARNING: this could be improved if we support channel muting... */ + sigdata->channel_volume[i] = 0; + sigdata->channel_pan[i] = 7; + } + } + } + + /* Orders, byte each, length = sigdata->n_orders (should be even) */ + dumbfile_getnc(sigdata->order, sigdata->n_orders, f); + sigdata->restart_position = 0; + + component = malloc(768*sizeof(*component)); + if (!component) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (it_seek(f, 352)) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + for (n = 0; n < sigdata->n_patterns; n++) { + component[n_components].type = PTM_COMPONENT_PATTERN; + component[n_components].n = n; + component[n_components].offset = dumbfile_igetw(f) << 4; + n_components++; + } + + if (it_seek(f, 608)) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + for (n = 0; n < sigdata->n_samples; n++) { + if (it_ptm_read_sample_header(&sigdata->sample[n], &component[n_components].offset, f)) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + if (!(sigdata->sample[n].flags & IT_SAMPLE_EXISTS)) continue; + component[n_components].type = PTM_COMPONENT_SAMPLE; + component[n_components].n = n; + n_components++; + } + + qsort(component, n_components, sizeof(PTM_COMPONENT), &ptm_component_compare); + + { + int i; + for (i = 0; i < 32; i++) { + sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3; + sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7; + if (sigdata->channel_pan[i] > 64) sigdata->channel_pan[i] = 64; + } + } + + sigdata->pan_separation = 128; + + if (dumbfile_error(f)) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + buffer = malloc(65536); + if (!buffer) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + for (n = 0; n < n_components; n++) { + if (it_seek(f, component[n].offset)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + switch (component[n].type) { + + case PTM_COMPONENT_PATTERN: + if (it_ptm_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + break; + + case PTM_COMPONENT_SAMPLE: + if (it_ptm_read_sample_data(&sigdata->sample[component[n].n], (n + 1 == n_components), f)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + } + + free(buffer); + free(component); + + _dumb_it_fix_invalid_orders(sigdata); + + return sigdata; +} + +static char hexdigit(int in) +{ + if (in < 10) return in + '0'; + else return in + 'A' - 10; +} + +DUH *dumb_read_ptm_quick(DUMBFILE *f) +{ + sigdata_t *sigdata; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_ptm_load_sigdata(f); + + if (!sigdata) + return NULL; + + { + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = "PTM"; + return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/readriff.c b/plugins/dumb/dumb-kode54/src/it/readriff.c index cc1e82fb..10bd884a 100644 --- a/plugins/dumb/dumb-kode54/src/it/readriff.c +++ b/plugins/dumb/dumb-kode54/src/it/readriff.c @@ -1,73 +1,73 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readriff.c - Code to read a RIFF module file / / \ \
- * from memory. | < / \_
- * | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-#include "internal/it.h"
-#include "internal/riff.h"
-
-
-DUH *dumb_read_riff_amff( struct riff * stream );
-DUH *dumb_read_riff_am( struct riff * stream );
-DUH *dumb_read_riff_dsmf( struct riff * stream );
-
-/* dumb_read_riff_quick(): reads a RIFF file into a DUH struct, returning a
- * pointer to the DUH struct. When you have finished with it, you must pass
- * the pointer to unload_duh() so that the memory can be freed.
- */
-DUH *dumb_read_riff_quick( DUMBFILE * f )
-{
- DUH * duh;
- struct riff * stream;
-
- {
- unsigned char * buffer = 0;
- unsigned size = 0;
- long read;
- do
- {
- buffer = realloc( buffer, 32768 + size );
- if ( ! buffer ) return 0;
- read = dumbfile_getnc( buffer + size, 32768, f );
- if ( read < 0 )
- {
- free( buffer );
- return 0;
- }
- size += read;
- }
- while ( read == 32768 );
- stream = riff_parse( buffer, size, 1 );
- if ( ! stream ) stream = riff_parse( buffer, size, 0 );
- free( buffer );
- }
-
- if ( ! stream ) return 0;
-
- if ( stream->type == DUMB_ID( 'A', 'M', ' ', ' ' ) )
- duh = dumb_read_riff_am( stream );
- else if ( stream->type == DUMB_ID( 'A', 'M', 'F', 'F' ) )
- duh = dumb_read_riff_amff( stream );
- else if ( stream->type == DUMB_ID( 'D', 'S', 'M', 'F' ) )
- duh = dumb_read_riff_dsmf( stream );
- else duh = 0;
-
- riff_free( stream );
-
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readriff.c - Code to read a RIFF module file / / \ \ + * from memory. | < / \_ + * | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" +#include "internal/it.h" +#include "internal/riff.h" + + +DUH *dumb_read_riff_amff( struct riff * stream ); +DUH *dumb_read_riff_am( struct riff * stream ); +DUH *dumb_read_riff_dsmf( struct riff * stream ); + +/* dumb_read_riff_quick(): reads a RIFF file into a DUH struct, returning a + * pointer to the DUH struct. When you have finished with it, you must pass + * the pointer to unload_duh() so that the memory can be freed. + */ +DUH *dumb_read_riff_quick( DUMBFILE * f ) +{ + DUH * duh; + struct riff * stream; + + { + unsigned char * buffer = 0; + unsigned size = 0; + long read; + do + { + buffer = realloc( buffer, 32768 + size ); + if ( ! buffer ) return 0; + read = dumbfile_getnc( buffer + size, 32768, f ); + if ( read < 0 ) + { + free( buffer ); + return 0; + } + size += read; + } + while ( read == 32768 ); + stream = riff_parse( buffer, size, 1 ); + if ( ! stream ) stream = riff_parse( buffer, size, 0 ); + free( buffer ); + } + + if ( ! stream ) return 0; + + if ( stream->type == DUMB_ID( 'A', 'M', ' ', ' ' ) ) + duh = dumb_read_riff_am( stream ); + else if ( stream->type == DUMB_ID( 'A', 'M', 'F', 'F' ) ) + duh = dumb_read_riff_amff( stream ); + else if ( stream->type == DUMB_ID( 'D', 'S', 'M', 'F' ) ) + duh = dumb_read_riff_dsmf( stream ); + else duh = 0; + + riff_free( stream ); + + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/reads3m.c b/plugins/dumb/dumb-kode54/src/it/reads3m.c index 0dac8331..77a70f7a 100644 --- a/plugins/dumb/dumb-kode54/src/it/reads3m.c +++ b/plugins/dumb/dumb-kode54/src/it/reads3m.c @@ -1,864 +1,864 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * reads3m.c - Code to read a ScreamTracker 3 / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By entheh. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-// IT_STEREO... :o
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-//#define S3M_BROKEN_OVERLAPPED_SAMPLES
-
-/** WARNING: this is duplicated in itread.c */
-static int it_seek(DUMBFILE *f, long offset)
-{
- long pos = dumbfile_pos(f);
-
- if (pos > offset) {
- return -1;
- }
-
- if (pos < offset)
- if (dumbfile_skip(f, offset - pos))
- return -1;
-
- return 0;
-}
-
-
-
-static int it_s3m_read_sample_header(IT_SAMPLE *sample, long *offset, unsigned char *pack, int cwtv, DUMBFILE *f)
-{
- unsigned char type;
- int flags;
-
- type = dumbfile_getc(f);
-
- dumbfile_getnc(sample->filename, 12, f);
- sample->filename[12] = 0;
-
- if (type > 1) {
- /** WARNING: no adlib support */
- dumbfile_skip(f, 3 + 12 + 1 + 1 + 2 + 2 + 2 + 12);
- dumbfile_getnc(sample->name, 28, f);
- sample->name[28] = 0;
- dumbfile_skip(f, 4);
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return -1; // return error so that another plugin could pick that file up
- }
-
- *offset = dumbfile_getc(f) << 20;
- *offset += dumbfile_igetw(f) << 4;
-
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = dumbfile_igetl(f);
-
- sample->default_volume = dumbfile_getc(f);
-
- dumbfile_skip(f, 1);
-
- flags = dumbfile_getc(f);
-
- if (flags < 0 || (flags != 0 && flags != 4))
- /* Sample is packed apparently (or error reading from file). We don't
- * know how to read packed samples.
- */
- return -1;
-
- *pack = flags;
-
- flags = dumbfile_getc(f);
-
- sample->C5_speed = dumbfile_igetl(f) << 1;
-
- /* Skip four unused bytes and three internal variables. */
- dumbfile_skip(f, 4+2+2+4);
-
- dumbfile_getnc(sample->name, 28, f);
- sample->name[28] = 0;
-
- if (type == 0 || sample->length <= 0) {
- /* Looks like no-existy. Anyway, there's for sure no 'SCRS' ... */
- sample->flags &= ~IT_SAMPLE_EXISTS;
- return dumbfile_error(f);
- }
-
- if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','S'))
- return -1;
-
- sample->global_volume = 64;
-
- sample->flags = IT_SAMPLE_EXISTS;
- if (flags & 1) sample->flags |= IT_SAMPLE_LOOP;
-
- /* The ST3 TECH.DOC is unclear on this, but IMAGO Orpheus is not. Piece of crap. */
-
- if (flags & 2) {
- sample->flags |= IT_SAMPLE_STEREO;
-
- if ((cwtv & 0xF000) == 0x2000) {
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- }
- }
-
- if (flags & 4) {
- sample->flags |= IT_SAMPLE_16BIT;
-
- if ((cwtv & 0xF000) == 0x2000) {
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- }
- }
-
- sample->default_pan = 0; // 0 = don't use, or 160 = centre?
-
- if (sample->flags & IT_SAMPLE_LOOP) {
- if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
- /*sample->flags &= ~IT_SAMPLE_LOOP;*/
- sample->loop_end = sample->length;
- else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else
- /* ScreamTracker seems not to save what comes after the loop end
- * point, but rather to assume it is a duplicate of what comes at
- * the loop start point. I am not completely sure of this though.
- * It is easy to evade; simply truncate the sample.
- */
- sample->length = sample->loop_end;
- }
-
-
- //Do we need to set all these?
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-
-
-static int it_s3m_read_sample_data(IT_SAMPLE *sample, int ffi, unsigned char pack, DUMBFILE *f)
-{
- long n;
-
- long datasize = sample->length;
- if (sample->flags & IT_SAMPLE_STEREO) datasize <<= 1;
-
- sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
- if (!sample->data)
- return -1;
-
- if (pack == 4) {
- if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
- return -1;
- }
- else if (sample->flags & IT_SAMPLE_STEREO) {
- if (sample->flags & IT_SAMPLE_16BIT) {
- for (n = 0; n < datasize; n += 2)
- ((short *)sample->data)[n] = dumbfile_igetw(f);
- for (n = 1; n < datasize; n += 2)
- ((short *)sample->data)[n] = dumbfile_igetw(f);
- } else {
- for (n = 0; n < datasize; n += 2)
- ((signed char *)sample->data)[n] = dumbfile_getc(f);
- for (n = 1; n < datasize; n += 2)
- ((signed char *)sample->data)[n] = dumbfile_getc(f);
- }
- } else if (sample->flags & IT_SAMPLE_16BIT)
- for (n = 0; n < sample->length; n++)
- ((short *)sample->data)[n] = dumbfile_igetw(f);
- else
- for (n = 0; n < sample->length; n++)
- ((signed char *)sample->data)[n] = dumbfile_getc(f);
-
- if (dumbfile_error(f))
- return -1;
-
- if (ffi != 1) {
- /* Convert to signed. */
- if (sample->flags & IT_SAMPLE_16BIT)
- for (n = 0; n < datasize; n++)
- ((short *)sample->data)[n] ^= 0x8000;
- else
- for (n = 0; n < datasize; n++)
- ((signed char *)sample->data)[n] ^= 0x80;
- }
-
- return 0;
-}
-
-
-
-static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int maxlen)
-{
- int length;
- int buflen = 0;
- int bufpos = 0;
-
- IT_ENTRY *entry;
-
- unsigned char channel;
-
- /* Haha, this is hilarious!
- *
- * Well, after some experimentation, it seems that different S3M writers
- * define the format in different ways. The S3M docs say that the first
- * two bytes hold the "length of [the] packed pattern", and the packed
- * pattern data follow. Judging by the contents of ARMANI.S3M, packaged
- * with ScreamTracker itself, the measure of length _includes_ the two
- * bytes used to store the length; in other words, we should read
- * (length - 2) more bytes. However, aryx.s3m, packaged with ModPlug
- * Tracker, excludes these two bytes, so (length) more bytes must be
- * read.
- *
- * Call me crazy, but I just find it insanely funny that the format was
- * misunderstood in this way :D
- *
- * Now we can't just risk reading two extra bytes, because then we
- * overshoot, and DUMBFILEs don't support backward seeking (for a good
- * reason). Luckily, there is a way. We can read the data little by
- * little, and stop when we have 64 rows in memory. Provided we protect
- * against buffer overflow, this method should work with all sensibly
- * written S3M files. If you find one for which it does not work, please
- * let me know at entheh@users.sf.net so I can look at it.
- */
-
- /* Discard the length. */
- /* read at most length bytes, in case of retarded crap */
- length = dumbfile_igetw(f);
-
- if (maxlen)
- {
- maxlen -= 2;
- if (length > maxlen) length = maxlen;
- }
-
- if (dumbfile_error(f) || !length)
- return -1;
-
- pattern->n_rows = 0;
- pattern->n_entries = 0;
-
- /* Read in the pattern data, little by little, and work out how many
- * entries we need room for. Sorry, but this is just so funny...
- */
- for (;;) {
- unsigned char b = buffer[buflen++] = dumbfile_getc(f);
-
-#if 1
- static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5};
- channel = b & 31;
- b >>= 5;
- pattern->n_entries++;
- if (b) {
- if (buflen + used[b] >= 65536) return -1;
- if (buflen + used[b] <= length)
- dumbfile_getnc(buffer + buflen, used[b], f);
- else
- memset(buffer + buflen, 0, used[b]);
- buflen += used[b];
- } else {
- /* End of row */
- if (++pattern->n_rows == 64) break;
- if (buflen >= 65536) return -1;
- }
-#else
- if (b == 0) {
- /* End of row */
- pattern->n_entries++;
- if (++pattern->n_rows == 64) break;
- if (buflen >= 65536) return -1;
- } else {
- static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5};
- channel = b & 31;
- b >>= 5;
- if (b) {
- pattern->n_entries++;
- if (buflen + used[b] >= 65536) return -1;
- dumbfile_getnc(buffer + buflen, used[b], f);
- buflen += used[b];
- }
- }
-#endif
-
- /* We have ensured that buflen < 65536 at this point, so it is safe
- * to iterate and read at least one more byte without checking.
- * However, now would be a good time to check for errors reading from
- * the file.
- */
-
- if (dumbfile_error(f))
- return -1;
-
- /* Great. We ran out of data, but there should be data for more rows.
- * Fill the rest with null data...
- */
- if (buflen >= length && pattern->n_rows < 64)
- {
- while (pattern->n_rows < 64)
- {
- if (buflen >= 65536) return -1;
- buffer[buflen++] = 0;
- pattern->n_entries++;
- pattern->n_rows++;
- }
- break;
- }
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
-
- if (!pattern->entry)
- return -1;
-
- entry = pattern->entry;
-
- while (bufpos < buflen) {
- unsigned char b = buffer[bufpos++];
-
-#if 1
- if (!(b & ~31))
-#else
- if (b == 0)
-#endif
- {
- /* End of row */
- IT_SET_END_ROW(entry);
- entry++;
- continue;
- }
-
- channel = b & 31;
-
- if (b & 224) {
- entry->mask = 0;
- entry->channel = channel;
-
- if (b & 32) {
- unsigned char n = buffer[bufpos++];
- if (n != 255) {
- if (n == 254)
- entry->note = IT_NOTE_CUT;
- else
- entry->note = (n >> 4) * 12 + (n & 15);
- entry->mask |= IT_ENTRY_NOTE;
- }
-
- entry->instrument = buffer[bufpos++];
- if (entry->instrument)
- entry->mask |= IT_ENTRY_INSTRUMENT;
- }
-
- if (b & 64) {
- entry->volpan = buffer[bufpos++];
- if (entry->volpan != 255)
- entry->mask |= IT_ENTRY_VOLPAN;
- }
-
- if (b & 128) {
- entry->effect = buffer[bufpos++];
- entry->effectvalue = buffer[bufpos++];
- // XXX woot
- if (entry->effect && entry->effect < IT_MIDI_MACRO /*!= 255*/) {
- entry->mask |= IT_ENTRY_EFFECT;
- switch (entry->effect) {
- case IT_BREAK_TO_ROW:
- entry->effectvalue -= (entry->effectvalue >> 4) * 6;
- break;
-
- case IT_SET_CHANNEL_VOLUME:
- case IT_CHANNEL_VOLUME_SLIDE:
- case IT_PANNING_SLIDE:
- case IT_GLOBAL_VOLUME_SLIDE:
- case IT_PANBRELLO:
- case IT_MIDI_MACRO:
- entry->mask &= ~IT_ENTRY_EFFECT;
- break;
-
- case IT_S:
- switch (entry->effectvalue >> 4) {
- case IT_S_SET_PANBRELLO_WAVEFORM:
- case IT_S_FINE_PATTERN_DELAY:
- case IT_S7:
- case IT_S_SET_SURROUND_SOUND:
- case IT_S_SET_MIDI_MACRO:
- entry->mask &= ~IT_ENTRY_EFFECT;
- break;
- }
- break;
- }
- }
- /** WARNING: ARGH! CONVERT TEH EFFECTS!@~ */
- }
-
- entry++;
- }
- }
-
- ASSERT(entry == pattern->entry + pattern->n_entries);
-
- return 0;
-}
-
-
-
-/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */
-/* Currently we assume the sample data are stored after the sample headers in
- * module files. This assumption may be unjustified; let me know if you have
- * trouble.
- */
-
-#define S3M_COMPONENT_INSTRUMENT 1
-#define S3M_COMPONENT_PATTERN 2
-#define S3M_COMPONENT_SAMPLE 3
-
-typedef struct S3M_COMPONENT
-{
- unsigned char type;
- unsigned char n;
- long offset;
- short sampfirst; /* component[sampfirst] = first sample data after this */
- short sampnext; /* sampnext is used to create linked lists of sample data */
-}
-S3M_COMPONENT;
-
-
-
-static int s3m_component_compare(const void *e1, const void *e2)
-{
- return ((const S3M_COMPONENT *)e1)->offset -
- ((const S3M_COMPONENT *)e2)->offset;
-}
-
-
-
-static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- int flags, ffi;
- int default_pan_present;
-
- int master_volume;
-
- unsigned char sample_pack[256];
-
- S3M_COMPONENT *component;
- int n_components = 0;
-
- int n;
-
- unsigned char *buffer;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) return NULL;
-
- dumbfile_getnc(sigdata->name, 28, f);
- sigdata->name[28] = 0;
-
- n = dumbfile_getc(f);
-
- if (n != 0x1A && n != 0) {
- free(sigdata);
- return NULL;
- }
-
- if (dumbfile_getc(f) != 16) {
- free(sigdata);
- return NULL;
- }
-
- dumbfile_skip(f, 2);
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_orders = dumbfile_igetw(f);
- sigdata->n_instruments = 0;
- sigdata->n_samples = dumbfile_igetw(f);
- sigdata->n_patterns = dumbfile_igetw(f);
-
- if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 256 || sigdata->n_patterns > 256) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->order = malloc(sigdata->n_orders);
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (sigdata->n_samples) {
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
- }
-
- if (sigdata->n_patterns) {
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
- }
-
- flags = dumbfile_igetw(f);
-
- *cwtv = dumbfile_igetw(f);
-
- if (*cwtv == 0x1300) {
- /** WARNING: volume slides on every frame */
- }
-
- ffi = dumbfile_igetw(f);
-
- /** WARNING: which ones? */
- sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
-
- if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','M')) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->global_volume = dumbfile_getc(f) << 1;
- if ( !sigdata->global_volume || sigdata->global_volume > 128 ) sigdata->global_volume = 128;
- sigdata->speed = dumbfile_getc(f);
- if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
- sigdata->tempo = dumbfile_getc(f);
- master_volume = dumbfile_getc(f); // 7 bits; +128 for stereo
- //what do we do with master_volume? it's not the same as mixing volume...
- sigdata->mixing_volume = 48;
-
- if (master_volume & 128) sigdata->flags |= IT_STEREO;
-
- /* Skip GUS Ultra Click Removal byte. */
- dumbfile_getc(f);
-
- default_pan_present = dumbfile_getc(f);
-
- dumbfile_skip(f, 8);
-
- /* Skip Special Custom Data Pointer. */
- /** WARNING: investigate this? */
- dumbfile_igetw(f);
-
- sigdata->n_pchannels = 0;
- /* Channel settings for 32 channels, 255=unused, +128=disabled */
- {
- int i;
- for (i = 0; i < 32; i++) {
- int c = dumbfile_getc(f);
- if (!(c & (128 | 16))) { /* +128=disabled, +16=Adlib */
- if (sigdata->n_pchannels < i + 1) sigdata->n_pchannels = i + 1;
- sigdata->channel_volume[i] = 64;
- sigdata->channel_pan[i] = c & 8 ? 12 : 3;
- /** WARNING: ah, but it should be 7 for mono... */
- } else {
- /** WARNING: this could be improved if we support channel muting... */
- sigdata->channel_volume[i] = 0;
- sigdata->channel_pan[i] = 7;
- }
- }
- }
-
- /* Orders, byte each, length = sigdata->n_orders (should be even) */
- dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
- sigdata->restart_position = 0;
-
- component = malloc(768*sizeof(*component));
- if (!component) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- for (n = 0; n < sigdata->n_samples; n++) {
- component[n_components].type = S3M_COMPONENT_SAMPLE;
- component[n_components].n = n;
- component[n_components].offset = dumbfile_igetw(f) << 4;
- component[n_components].sampfirst = -1;
- n_components++;
- }
-
- for (n = 0; n < sigdata->n_patterns; n++) {
- long offset = dumbfile_igetw(f) << 4;
- if (offset) {
- component[n_components].type = S3M_COMPONENT_PATTERN;
- component[n_components].n = n;
- component[n_components].offset = offset;
- component[n_components].sampfirst = -1;
- n_components++;
- } else {
- /** WARNING: Empty 64-row pattern ... ? (this does happen!) */
- sigdata->pattern[n].n_rows = 64;
- sigdata->pattern[n].n_entries = 0;
- }
- }
-
- qsort(component, n_components, sizeof(S3M_COMPONENT), &s3m_component_compare);
-
- /* I found a really dumb S3M file that claimed to contain default pan
- * data but didn't contain any. Programs would load it by reading part of
- * the first instrument header, assuming the data to be default pan
- * positions, and then rereading the instrument module. We cannot do this
- * without obfuscating the file input model, so we insert an extra check
- * here that we won't overrun the start of the first component.
- */
- if (default_pan_present == 252 && component[0].offset >= dumbfile_pos(f) + 32) {
- /* Channel default pan positions */
- int i;
- for (i = 0; i < 32; i++) {
- int c = dumbfile_getc(f);
- if (c & 32)
- sigdata->channel_pan[i] = c & 15;
- }
- }
-
- {
- int i;
- for (i = 0; i < 32; i++) {
- sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3;
- sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7;
- }
- }
-
- sigdata->pan_separation = 128;
-
- if (dumbfile_error(f)) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- buffer = malloc(65536);
- if (!buffer) {
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- /* Voila, I must deal with a very dumb S3M myself. This file refers to the same file offset twice
- * for two different patterns. Solution: Eliminate it.
- */
-
- for (n = 0; n < n_components; n++) {
- if (component[n].type == S3M_COMPONENT_PATTERN) {
- int m;
- for (m = n + 1; m < n_components; m++) {
- if (component[m].type == S3M_COMPONENT_PATTERN) {
- if (component[n].offset == component[m].offset) {
- int o, pattern;
- pattern = component[m].n;
- n_components--;
- for (o = m; o < n_components; o++) {
- component[o] = component[o + 1];
- }
- for (o = 0; o < sigdata->n_orders; o++) {
- if (sigdata->order[o] == pattern) {
- sigdata->order[o] = component[n].n;
- }
- }
- sigdata->pattern[pattern].n_rows = 64;
- sigdata->pattern[pattern].n_entries = 0;
- m--;
- } else
- break;
- }
- }
- }
- }
-
- for (n = 0; n < n_components; n++) {
- long offset;
- int m;
-#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
- int last;
-#endif
-
- if (it_seek(f, component[n].offset)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- switch (component[n].type) {
-
- case S3M_COMPONENT_PATTERN:
- if (it_s3m_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- break;
-
- case S3M_COMPONENT_SAMPLE:
- {
- int err = it_s3m_read_sample_header(&sigdata->sample[component[n].n], &offset, &sample_pack[component[n].n], *cwtv, f);
- if (err) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
-
- if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) {
- short *sample;
-
- for (m = n + 1; m < n_components; m++)
- if (component[m].offset > offset)
- break;
- m--;
-
- sample = &component[m].sampfirst;
-
- while (*sample >= 0 && component[*sample].offset <= offset)
- sample = &component[*sample].sampnext;
-
- component[n].sampnext = *sample;
- *sample = n;
-
- component[n].offset = offset;
- }
- }
-
- m = component[n].sampfirst;
-
-#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
- last = -1;
-#endif
-
- while (m >= 0) {
- // XXX
-#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
- if ( last >= 0 ) {
- if ( dumbfile_pos( f ) > component[m].offset ) {
- IT_SAMPLE * s1 = &sigdata->sample[component[last].n];
- IT_SAMPLE * s2 = &sigdata->sample[component[m].n];
- if ( ( s1->flags | s2->flags ) & ( IT_SAMPLE_16BIT | IT_SAMPLE_STEREO ) ) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- if ( component[m].offset >= component[last].offset &&
- component[m].offset + s2->length <= component[last].offset + s1->length ) {
- s2->left = malloc( s2->length );
- if ( ! s2->left ) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- memcpy( s2->left, ( const char * ) s1->left + component[m].offset - component[last].offset, s2->length );
- last = -1;
- }
- }
- } else last = 0;
-
- if ( last >= 0 ) {
-#endif
- if (it_seek(f, component[m].offset)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (it_s3m_read_sample_data(&sigdata->sample[component[m].n], ffi, sample_pack[component[m].n], f)) {
- free(buffer);
- free(component);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
-#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES
- last = m;
- }
-#endif
-
- m = component[m].sampnext;
- }
- }
-
- free(buffer);
- free(component);
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-static char hexdigit(int in)
-{
- if (in < 10) return in + '0';
- else return in + 'A' - 10;
-}
-
-DUH *dumb_read_s3m_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
- int cwtv;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_s3m_load_sigdata(f, &cwtv);
-
- if (!sigdata)
- return NULL;
-
- {
- char version[8];
- const char *tag[3][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "S3M";
- tag[2][0] = "TRACKERVERSION";
- version[0] = hexdigit((cwtv >> 8) & 15);
- version[1] = '.';
- version[2] = hexdigit((cwtv >> 4) & 15);
- version[3] = hexdigit(cwtv & 15);
- version[4] = 0;
- tag[2][1] = (const char *) &version;
- return make_duh(-1, 3, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * reads3m.c - Code to read a ScreamTracker 3 / / \ \ + * module from an open file. | < / \_ + * | \/ /\ / + * By entheh. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +// IT_STEREO... :o +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" +#include "internal/it.h" + +//#define S3M_BROKEN_OVERLAPPED_SAMPLES + +/** WARNING: this is duplicated in itread.c */ +static int it_seek(DUMBFILE *f, long offset) +{ + long pos = dumbfile_pos(f); + + if (pos > offset) { + return -1; + } + + if (pos < offset) + if (dumbfile_skip(f, offset - pos)) + return -1; + + return 0; +} + + + +static int it_s3m_read_sample_header(IT_SAMPLE *sample, long *offset, unsigned char *pack, int cwtv, DUMBFILE *f) +{ + unsigned char type; + int flags; + + type = dumbfile_getc(f); + + dumbfile_getnc(sample->filename, 12, f); + sample->filename[12] = 0; + + if (type > 1) { + /** WARNING: no adlib support */ + dumbfile_skip(f, 3 + 12 + 1 + 1 + 2 + 2 + 2 + 12); + dumbfile_getnc(sample->name, 28, f); + sample->name[28] = 0; + dumbfile_skip(f, 4); + sample->flags &= ~IT_SAMPLE_EXISTS; + return -1; // return error so that another plugin could pick that file up + } + + *offset = dumbfile_getc(f) << 20; + *offset += dumbfile_igetw(f) << 4; + + sample->length = dumbfile_igetl(f); + sample->loop_start = dumbfile_igetl(f); + sample->loop_end = dumbfile_igetl(f); + + sample->default_volume = dumbfile_getc(f); + + dumbfile_skip(f, 1); + + flags = dumbfile_getc(f); + + if (flags < 0 || (flags != 0 && flags != 4)) + /* Sample is packed apparently (or error reading from file). We don't + * know how to read packed samples. + */ + return -1; + + *pack = flags; + + flags = dumbfile_getc(f); + + sample->C5_speed = dumbfile_igetl(f) << 1; + + /* Skip four unused bytes and three internal variables. */ + dumbfile_skip(f, 4+2+2+4); + + dumbfile_getnc(sample->name, 28, f); + sample->name[28] = 0; + + if (type == 0 || sample->length <= 0) { + /* Looks like no-existy. Anyway, there's for sure no 'SCRS' ... */ + sample->flags &= ~IT_SAMPLE_EXISTS; + return dumbfile_error(f); + } + + if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','S')) + return -1; + + sample->global_volume = 64; + + sample->flags = IT_SAMPLE_EXISTS; + if (flags & 1) sample->flags |= IT_SAMPLE_LOOP; + + /* The ST3 TECH.DOC is unclear on this, but IMAGO Orpheus is not. Piece of crap. */ + + if (flags & 2) { + sample->flags |= IT_SAMPLE_STEREO; + + if ((cwtv & 0xF000) == 0x2000) { + sample->length >>= 1; + sample->loop_start >>= 1; + sample->loop_end >>= 1; + } + } + + if (flags & 4) { + sample->flags |= IT_SAMPLE_16BIT; + + if ((cwtv & 0xF000) == 0x2000) { + sample->length >>= 1; + sample->loop_start >>= 1; + sample->loop_end >>= 1; + } + } + + sample->default_pan = 0; // 0 = don't use, or 160 = centre? + + if (sample->flags & IT_SAMPLE_LOOP) { + if ((unsigned int)sample->loop_end > (unsigned int)sample->length) + /*sample->flags &= ~IT_SAMPLE_LOOP;*/ + sample->loop_end = sample->length; + else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end) + sample->flags &= ~IT_SAMPLE_LOOP; + else + /* ScreamTracker seems not to save what comes after the loop end + * point, but rather to assume it is a duplicate of what comes at + * the loop start point. I am not completely sure of this though. + * It is easy to evade; simply truncate the sample. + */ + sample->length = sample->loop_end; + } + + + //Do we need to set all these? + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = IT_VIBRATO_SINE; + sample->finetune = 0; + sample->max_resampling_quality = -1; + + return dumbfile_error(f); +} + + + +static int it_s3m_read_sample_data(IT_SAMPLE *sample, int ffi, unsigned char pack, DUMBFILE *f) +{ + long n; + + long datasize = sample->length; + if (sample->flags & IT_SAMPLE_STEREO) datasize <<= 1; + + sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1)); + if (!sample->data) + return -1; + + if (pack == 4) { + if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0) + return -1; + } + else if (sample->flags & IT_SAMPLE_STEREO) { + if (sample->flags & IT_SAMPLE_16BIT) { + for (n = 0; n < datasize; n += 2) + ((short *)sample->data)[n] = dumbfile_igetw(f); + for (n = 1; n < datasize; n += 2) + ((short *)sample->data)[n] = dumbfile_igetw(f); + } else { + for (n = 0; n < datasize; n += 2) + ((signed char *)sample->data)[n] = dumbfile_getc(f); + for (n = 1; n < datasize; n += 2) + ((signed char *)sample->data)[n] = dumbfile_getc(f); + } + } else if (sample->flags & IT_SAMPLE_16BIT) + for (n = 0; n < sample->length; n++) + ((short *)sample->data)[n] = dumbfile_igetw(f); + else + for (n = 0; n < sample->length; n++) + ((signed char *)sample->data)[n] = dumbfile_getc(f); + + if (dumbfile_error(f)) + return -1; + + if (ffi != 1) { + /* Convert to signed. */ + if (sample->flags & IT_SAMPLE_16BIT) + for (n = 0; n < datasize; n++) + ((short *)sample->data)[n] ^= 0x8000; + else + for (n = 0; n < datasize; n++) + ((signed char *)sample->data)[n] ^= 0x80; + } + + return 0; +} + + + +static int it_s3m_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer, int maxlen) +{ + int length; + int buflen = 0; + int bufpos = 0; + + IT_ENTRY *entry; + + unsigned char channel; + + /* Haha, this is hilarious! + * + * Well, after some experimentation, it seems that different S3M writers + * define the format in different ways. The S3M docs say that the first + * two bytes hold the "length of [the] packed pattern", and the packed + * pattern data follow. Judging by the contents of ARMANI.S3M, packaged + * with ScreamTracker itself, the measure of length _includes_ the two + * bytes used to store the length; in other words, we should read + * (length - 2) more bytes. However, aryx.s3m, packaged with ModPlug + * Tracker, excludes these two bytes, so (length) more bytes must be + * read. + * + * Call me crazy, but I just find it insanely funny that the format was + * misunderstood in this way :D + * + * Now we can't just risk reading two extra bytes, because then we + * overshoot, and DUMBFILEs don't support backward seeking (for a good + * reason). Luckily, there is a way. We can read the data little by + * little, and stop when we have 64 rows in memory. Provided we protect + * against buffer overflow, this method should work with all sensibly + * written S3M files. If you find one for which it does not work, please + * let me know at entheh@users.sf.net so I can look at it. + */ + + /* Discard the length. */ + /* read at most length bytes, in case of retarded crap */ + length = dumbfile_igetw(f); + + if (maxlen) + { + maxlen -= 2; + if (length > maxlen) length = maxlen; + } + + if (dumbfile_error(f) || !length) + return -1; + + pattern->n_rows = 0; + pattern->n_entries = 0; + + /* Read in the pattern data, little by little, and work out how many + * entries we need room for. Sorry, but this is just so funny... + */ + for (;;) { + unsigned char b = buffer[buflen++] = dumbfile_getc(f); + +#if 1 + static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5}; + channel = b & 31; + b >>= 5; + pattern->n_entries++; + if (b) { + if (buflen + used[b] >= 65536) return -1; + if (buflen + used[b] <= length) + dumbfile_getnc(buffer + buflen, used[b], f); + else + memset(buffer + buflen, 0, used[b]); + buflen += used[b]; + } else { + /* End of row */ + if (++pattern->n_rows == 64) break; + if (buflen >= 65536) return -1; + } +#else + if (b == 0) { + /* End of row */ + pattern->n_entries++; + if (++pattern->n_rows == 64) break; + if (buflen >= 65536) return -1; + } else { + static const unsigned char used[8] = {0, 2, 1, 3, 2, 4, 3, 5}; + channel = b & 31; + b >>= 5; + if (b) { + pattern->n_entries++; + if (buflen + used[b] >= 65536) return -1; + dumbfile_getnc(buffer + buflen, used[b], f); + buflen += used[b]; + } + } +#endif + + /* We have ensured that buflen < 65536 at this point, so it is safe + * to iterate and read at least one more byte without checking. + * However, now would be a good time to check for errors reading from + * the file. + */ + + if (dumbfile_error(f)) + return -1; + + /* Great. We ran out of data, but there should be data for more rows. + * Fill the rest with null data... + */ + if (buflen >= length && pattern->n_rows < 64) + { + while (pattern->n_rows < 64) + { + if (buflen >= 65536) return -1; + buffer[buflen++] = 0; + pattern->n_entries++; + pattern->n_rows++; + } + break; + } + } + + pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); + + if (!pattern->entry) + return -1; + + entry = pattern->entry; + + while (bufpos < buflen) { + unsigned char b = buffer[bufpos++]; + +#if 1 + if (!(b & ~31)) +#else + if (b == 0) +#endif + { + /* End of row */ + IT_SET_END_ROW(entry); + entry++; + continue; + } + + channel = b & 31; + + if (b & 224) { + entry->mask = 0; + entry->channel = channel; + + if (b & 32) { + unsigned char n = buffer[bufpos++]; + if (n != 255) { + if (n == 254) + entry->note = IT_NOTE_CUT; + else + entry->note = (n >> 4) * 12 + (n & 15); + entry->mask |= IT_ENTRY_NOTE; + } + + entry->instrument = buffer[bufpos++]; + if (entry->instrument) + entry->mask |= IT_ENTRY_INSTRUMENT; + } + + if (b & 64) { + entry->volpan = buffer[bufpos++]; + if (entry->volpan != 255) + entry->mask |= IT_ENTRY_VOLPAN; + } + + if (b & 128) { + entry->effect = buffer[bufpos++]; + entry->effectvalue = buffer[bufpos++]; + // XXX woot + if (entry->effect && entry->effect < IT_MIDI_MACRO /*!= 255*/) { + entry->mask |= IT_ENTRY_EFFECT; + switch (entry->effect) { + case IT_BREAK_TO_ROW: + entry->effectvalue -= (entry->effectvalue >> 4) * 6; + break; + + case IT_SET_CHANNEL_VOLUME: + case IT_CHANNEL_VOLUME_SLIDE: + case IT_PANNING_SLIDE: + case IT_GLOBAL_VOLUME_SLIDE: + case IT_PANBRELLO: + case IT_MIDI_MACRO: + entry->mask &= ~IT_ENTRY_EFFECT; + break; + + case IT_S: + switch (entry->effectvalue >> 4) { + case IT_S_SET_PANBRELLO_WAVEFORM: + case IT_S_FINE_PATTERN_DELAY: + case IT_S7: + case IT_S_SET_SURROUND_SOUND: + case IT_S_SET_MIDI_MACRO: + entry->mask &= ~IT_ENTRY_EFFECT; + break; + } + break; + } + } + /** WARNING: ARGH! CONVERT TEH EFFECTS!@~ */ + } + + entry++; + } + } + + ASSERT(entry == pattern->entry + pattern->n_entries); + + return 0; +} + + + +/** WARNING: this is duplicated in itread.c - also bad practice to use the same struct name unless they are unified in a header */ +/* Currently we assume the sample data are stored after the sample headers in + * module files. This assumption may be unjustified; let me know if you have + * trouble. + */ + +#define S3M_COMPONENT_INSTRUMENT 1 +#define S3M_COMPONENT_PATTERN 2 +#define S3M_COMPONENT_SAMPLE 3 + +typedef struct S3M_COMPONENT +{ + unsigned char type; + unsigned char n; + long offset; + short sampfirst; /* component[sampfirst] = first sample data after this */ + short sampnext; /* sampnext is used to create linked lists of sample data */ +} +S3M_COMPONENT; + + + +static int s3m_component_compare(const void *e1, const void *e2) +{ + return ((const S3M_COMPONENT *)e1)->offset - + ((const S3M_COMPONENT *)e2)->offset; +} + + + +static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv) +{ + DUMB_IT_SIGDATA *sigdata; + + int flags, ffi; + int default_pan_present; + + int master_volume; + + unsigned char sample_pack[256]; + + S3M_COMPONENT *component; + int n_components = 0; + + int n; + + unsigned char *buffer; + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) return NULL; + + dumbfile_getnc(sigdata->name, 28, f); + sigdata->name[28] = 0; + + n = dumbfile_getc(f); + + if (n != 0x1A && n != 0) { + free(sigdata); + return NULL; + } + + if (dumbfile_getc(f) != 16) { + free(sigdata); + return NULL; + } + + dumbfile_skip(f, 2); + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->sample = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->n_orders = dumbfile_igetw(f); + sigdata->n_instruments = 0; + sigdata->n_samples = dumbfile_igetw(f); + sigdata->n_patterns = dumbfile_igetw(f); + + if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_samples > 256 || sigdata->n_patterns > 256) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + sigdata->order = malloc(sigdata->n_orders); + if (!sigdata->order) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (sigdata->n_samples) { + sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); + if (!sigdata->sample) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (n = 0; n < sigdata->n_samples; n++) + sigdata->sample[n].data = NULL; + } + + if (sigdata->n_patterns) { + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (n = 0; n < sigdata->n_patterns; n++) + sigdata->pattern[n].entry = NULL; + } + + flags = dumbfile_igetw(f); + + *cwtv = dumbfile_igetw(f); + + if (*cwtv == 0x1300) { + /** WARNING: volume slides on every frame */ + } + + ffi = dumbfile_igetw(f); + + /** WARNING: which ones? */ + sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M; + + if (dumbfile_mgetl(f) != DUMB_ID('S','C','R','M')) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + sigdata->global_volume = dumbfile_getc(f) << 1; + if ( !sigdata->global_volume || sigdata->global_volume > 128 ) sigdata->global_volume = 128; + sigdata->speed = dumbfile_getc(f); + if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo? + sigdata->tempo = dumbfile_getc(f); + master_volume = dumbfile_getc(f); // 7 bits; +128 for stereo + //what do we do with master_volume? it's not the same as mixing volume... + sigdata->mixing_volume = 48; + + if (master_volume & 128) sigdata->flags |= IT_STEREO; + + /* Skip GUS Ultra Click Removal byte. */ + dumbfile_getc(f); + + default_pan_present = dumbfile_getc(f); + + dumbfile_skip(f, 8); + + /* Skip Special Custom Data Pointer. */ + /** WARNING: investigate this? */ + dumbfile_igetw(f); + + sigdata->n_pchannels = 0; + /* Channel settings for 32 channels, 255=unused, +128=disabled */ + { + int i; + for (i = 0; i < 32; i++) { + int c = dumbfile_getc(f); + if (!(c & (128 | 16))) { /* +128=disabled, +16=Adlib */ + if (sigdata->n_pchannels < i + 1) sigdata->n_pchannels = i + 1; + sigdata->channel_volume[i] = 64; + sigdata->channel_pan[i] = c & 8 ? 12 : 3; + /** WARNING: ah, but it should be 7 for mono... */ + } else { + /** WARNING: this could be improved if we support channel muting... */ + sigdata->channel_volume[i] = 0; + sigdata->channel_pan[i] = 7; + } + } + } + + /* Orders, byte each, length = sigdata->n_orders (should be even) */ + dumbfile_getnc(sigdata->order, sigdata->n_orders, f); + sigdata->restart_position = 0; + + component = malloc(768*sizeof(*component)); + if (!component) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + for (n = 0; n < sigdata->n_samples; n++) { + component[n_components].type = S3M_COMPONENT_SAMPLE; + component[n_components].n = n; + component[n_components].offset = dumbfile_igetw(f) << 4; + component[n_components].sampfirst = -1; + n_components++; + } + + for (n = 0; n < sigdata->n_patterns; n++) { + long offset = dumbfile_igetw(f) << 4; + if (offset) { + component[n_components].type = S3M_COMPONENT_PATTERN; + component[n_components].n = n; + component[n_components].offset = offset; + component[n_components].sampfirst = -1; + n_components++; + } else { + /** WARNING: Empty 64-row pattern ... ? (this does happen!) */ + sigdata->pattern[n].n_rows = 64; + sigdata->pattern[n].n_entries = 0; + } + } + + qsort(component, n_components, sizeof(S3M_COMPONENT), &s3m_component_compare); + + /* I found a really dumb S3M file that claimed to contain default pan + * data but didn't contain any. Programs would load it by reading part of + * the first instrument header, assuming the data to be default pan + * positions, and then rereading the instrument module. We cannot do this + * without obfuscating the file input model, so we insert an extra check + * here that we won't overrun the start of the first component. + */ + if (default_pan_present == 252 && component[0].offset >= dumbfile_pos(f) + 32) { + /* Channel default pan positions */ + int i; + for (i = 0; i < 32; i++) { + int c = dumbfile_getc(f); + if (c & 32) + sigdata->channel_pan[i] = c & 15; + } + } + + { + int i; + for (i = 0; i < 32; i++) { + sigdata->channel_pan[i] -= (sigdata->channel_pan[i] & 8) >> 3; + sigdata->channel_pan[i] = ((int)sigdata->channel_pan[i] << 5) / 7; + } + } + + sigdata->pan_separation = 128; + + if (dumbfile_error(f)) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + buffer = malloc(65536); + if (!buffer) { + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + /* Voila, I must deal with a very dumb S3M myself. This file refers to the same file offset twice + * for two different patterns. Solution: Eliminate it. + */ + + for (n = 0; n < n_components; n++) { + if (component[n].type == S3M_COMPONENT_PATTERN) { + int m; + for (m = n + 1; m < n_components; m++) { + if (component[m].type == S3M_COMPONENT_PATTERN) { + if (component[n].offset == component[m].offset) { + int o, pattern; + pattern = component[m].n; + n_components--; + for (o = m; o < n_components; o++) { + component[o] = component[o + 1]; + } + for (o = 0; o < sigdata->n_orders; o++) { + if (sigdata->order[o] == pattern) { + sigdata->order[o] = component[n].n; + } + } + sigdata->pattern[pattern].n_rows = 64; + sigdata->pattern[pattern].n_entries = 0; + m--; + } else + break; + } + } + } + } + + for (n = 0; n < n_components; n++) { + long offset; + int m; +#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES + int last; +#endif + + if (it_seek(f, component[n].offset)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + switch (component[n].type) { + + case S3M_COMPONENT_PATTERN: + if (it_s3m_read_pattern(&sigdata->pattern[component[n].n], f, buffer, (n + 1 < n_components) ? (component[n+1].offset - component[n].offset) : 0)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + break; + + case S3M_COMPONENT_SAMPLE: + { + int err = it_s3m_read_sample_header(&sigdata->sample[component[n].n], &offset, &sample_pack[component[n].n], *cwtv, f); + if (err) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + + if (sigdata->sample[component[n].n].flags & IT_SAMPLE_EXISTS) { + short *sample; + + for (m = n + 1; m < n_components; m++) + if (component[m].offset > offset) + break; + m--; + + sample = &component[m].sampfirst; + + while (*sample >= 0 && component[*sample].offset <= offset) + sample = &component[*sample].sampnext; + + component[n].sampnext = *sample; + *sample = n; + + component[n].offset = offset; + } + } + + m = component[n].sampfirst; + +#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES + last = -1; +#endif + + while (m >= 0) { + // XXX +#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES + if ( last >= 0 ) { + if ( dumbfile_pos( f ) > component[m].offset ) { + IT_SAMPLE * s1 = &sigdata->sample[component[last].n]; + IT_SAMPLE * s2 = &sigdata->sample[component[m].n]; + if ( ( s1->flags | s2->flags ) & ( IT_SAMPLE_16BIT | IT_SAMPLE_STEREO ) ) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + if ( component[m].offset >= component[last].offset && + component[m].offset + s2->length <= component[last].offset + s1->length ) { + s2->left = malloc( s2->length ); + if ( ! s2->left ) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + memcpy( s2->left, ( const char * ) s1->left + component[m].offset - component[last].offset, s2->length ); + last = -1; + } + } + } else last = 0; + + if ( last >= 0 ) { +#endif + if (it_seek(f, component[m].offset)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if (it_s3m_read_sample_data(&sigdata->sample[component[m].n], ffi, sample_pack[component[m].n], f)) { + free(buffer); + free(component); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + +#ifdef S3M_BROKEN_OVERLAPPED_SAMPLES + last = m; + } +#endif + + m = component[m].sampnext; + } + } + + free(buffer); + free(component); + + _dumb_it_fix_invalid_orders(sigdata); + + return sigdata; +} + +static char hexdigit(int in) +{ + if (in < 10) return in + '0'; + else return in + 'A' - 10; +} + +DUH *dumb_read_s3m_quick(DUMBFILE *f) +{ + sigdata_t *sigdata; + int cwtv; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_s3m_load_sigdata(f, &cwtv); + + if (!sigdata) + return NULL; + + { + char version[8]; + const char *tag[3][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = "S3M"; + tag[2][0] = "TRACKERVERSION"; + version[0] = hexdigit((cwtv >> 8) & 15); + version[1] = '.'; + version[2] = hexdigit((cwtv >> 4) & 15); + version[3] = hexdigit(cwtv & 15); + version[4] = 0; + tag[2][1] = (const char *) &version; + return make_duh(-1, 3, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/reads3m2.c b/plugins/dumb/dumb-kode54/src/it/reads3m2.c index 0499eecd..c9447c26 100644 --- a/plugins/dumb/dumb-kode54/src/it/reads3m2.c +++ b/plugins/dumb/dumb-kode54/src/it/reads3m2.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * reads3m2.c - Function to read a ScreamTracker 3 / / \ \
- * module from an open file and do an | < / \_
- * initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from reads3m.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_read_s3m(DUMBFILE *f)
-{
- DUH *duh = dumb_read_s3m_quick(f);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * reads3m2.c - Function to read a ScreamTracker 3 / / \ \ + * module from an open file and do an | < / \_ + * initial run-through. | \/ /\ / + * \_ / > / + * Split off from reads3m.c by entheh. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_read_s3m(DUMBFILE *f) +{ + DUH *duh = dumb_read_s3m_quick(f); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/readstm.c b/plugins/dumb/dumb-kode54/src/it/readstm.c index 5972a0f7..edfa4c19 100644 --- a/plugins/dumb/dumb-kode54/src/it/readstm.c +++ b/plugins/dumb/dumb-kode54/src/it/readstm.c @@ -1,397 +1,397 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readstm.c - Code to read a ScreamTracker 2 / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By Chris Moeller. \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-// IT_STEREO... :o
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-/** WARNING: this is duplicated in itread.c */
-static int it_seek(DUMBFILE *f, long offset)
-{
- long pos = dumbfile_pos(f);
-
- if (pos > offset) {
- return -1;
- }
-
- if (pos < offset)
- if (dumbfile_skip(f, offset - pos))
- return -1;
-
- return 0;
-}
-
-static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f )
-{
- dumbfile_getnc( sample->filename, 12, f );
- sample->filename[12] = 0;
-
- memcpy( sample->name, sample->filename, 13 );
-
- dumbfile_skip( f, 2 + 2 );
-
- sample->length = dumbfile_igetw( f );
- sample->loop_start = dumbfile_igetw( f );
- sample->loop_end = dumbfile_igetw( f );
-
- sample->default_volume = dumbfile_getc( f );
-
- dumbfile_skip( f, 1 );
-
- sample->C5_speed = dumbfile_igetw( f ) << 3;
-
- dumbfile_skip( f, 6 );
-
- if ( sample->length < 4 || !sample->default_volume ) {
- /* Looks like no-existy. */
- sample->flags &= ~IT_SAMPLE_EXISTS;
- sample->length = 0;
- return dumbfile_error( f );
- }
-
- sample->flags = IT_SAMPLE_EXISTS;
- sample->global_volume = 64;
- sample->default_pan = 0; // 0 = don't use, or 160 = centre?
-
- if ( ( sample->loop_start < sample->length ) &&
- ( sample->loop_end > sample->loop_start ) &&
- ( sample->loop_end != 0xFFFF ) ) {
- sample->flags |= IT_SAMPLE_LOOP;
- if ( sample->loop_end > sample->length ) sample->loop_end = sample->length;
- }
-
- //Do we need to set all these?
- sample->vibrato_speed = 0;
- sample->vibrato_depth = 0;
- sample->vibrato_rate = 0;
- sample->vibrato_waveform = IT_VIBRATO_SINE;
- sample->finetune = 0;
- sample->max_resampling_quality = -1;
-
- return dumbfile_error(f);
-}
-
-static int it_stm_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f )
-{
- long n;
-
- if ( ! sample->length ) return 0;
-
- n = dumbfile_pos( f );
- if ( n & 15 ) {
- if ( dumbfile_skip( f, 16 - ( n & 15 ) ) )
- return -1;
- }
-
- sample->data = malloc( sample->length );
- if (!sample->data)
- return -1;
-
- if ( dumbfile_getnc( sample->data, sample->length, f ) != sample->length )
- return -1;
-
- return 0;
-}
-
-static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer )
-{
- int pos;
- int channel;
- int row;
- IT_ENTRY *entry;
-
- pattern->n_rows = 64;
-
- if ( dumbfile_getnc( buffer, 64 * 4 * 4, f ) != 64 * 4 * 4 )
- return -1;
-
- pattern->n_entries = 64;
- pos = 0;
- for ( row = 0; row < 64; ++row ) {
- for ( channel = 0; channel < 4; ++channel ) {
- if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] )
- ++pattern->n_entries;
- pos += 4;
- }
- }
-
- pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) );
- if ( !pattern->entry )
- return -1;
-
- entry = pattern->entry;
- pos = 0;
- for ( row = 0; row < 64; ++row ) {
- for ( channel = 0; channel < 4; ++channel ) {
- if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) {
- unsigned note;
- note = buffer[ pos + 0 ];
- entry->channel = channel;
- entry->mask = 0;
- entry->instrument = buffer[ pos + 1 ] >> 3;
- entry->volpan = ( buffer[ pos + 1 ] & 0x07 ) + ( buffer[ pos + 2 ] >> 1 );
- entry->effect = buffer[ pos + 2 ] & 0x0F;
- entry->effectvalue = buffer[ pos + 3 ];
- if ( entry->instrument && entry->instrument < 32 )
- entry->mask |= IT_ENTRY_INSTRUMENT;
- if ( note == 0xFC || note == 0xFE ) {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = IT_NOTE_CUT;
- }
- if ( note < 251 ) {
- entry->mask |= IT_ENTRY_NOTE;
- entry->note = ( note >> 4 ) * 12 + ( note & 0x0F );
- }
- if ( entry->volpan <= 64 )
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->mask |= IT_ENTRY_EFFECT;
- switch ( entry->effect ) {
- case IT_SET_SPEED:
- entry->effectvalue >>= 4;
- break;
-
- case IT_BREAK_TO_ROW:
- entry->effectvalue -= (entry->effectvalue >> 4) * 6;
- break;
-
- case IT_JUMP_TO_ORDER:
- case IT_VOLUME_SLIDE:
- case IT_PORTAMENTO_DOWN:
- case IT_PORTAMENTO_UP:
- case IT_TONE_PORTAMENTO:
- case IT_VIBRATO:
- case IT_TREMOR:
- case IT_ARPEGGIO:
- case IT_VOLSLIDE_VIBRATO:
- case IT_VOLSLIDE_TONEPORTA:
- break;
-
- default:
- entry->mask &= ~IT_ENTRY_EFFECT;
- break;
- }
- if ( entry->mask ) ++entry;
- }
- pos += 4;
- }
- IT_SET_END_ROW(entry);
- ++entry;
- }
-
- pattern->n_entries = entry - pattern->entry;
-
- return 0;
-}
-
-
-
-static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/)
-{
- DUMB_IT_SIGDATA *sigdata;
-
- char tracker_name[ 8 ];
-
- int n;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata) return NULL;
-
- /* Skip song name. */
- dumbfile_getnc(sigdata->name, 20, f);
- sigdata->name[20] = 0;
-
- dumbfile_getnc(tracker_name, 8, f);
- n = dumbfile_getc(f);
- if ( n != 0x02 && n != 0x1A && n != 0x1B )
- {
- free( sigdata );
- return NULL;
- }
- if ( dumbfile_getc(f) != 2 ) /* only support modules */
- {
- free( sigdata );
- return NULL;
- }
- if ( strncasecmp( tracker_name, "!Scream!", 8 ) &&
- strncasecmp( tracker_name, "BMOD2STM", 8 ) &&
- strncasecmp( tracker_name, "WUZAMOD!", 8 ) )
- {
- free( sigdata );
- return NULL;
- }
-
- /* *version = dumbfile_mgetw(f); */
- dumbfile_skip( f, 2 );
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_instruments = 0;
- sigdata->n_samples = 31;
- sigdata->n_pchannels = 4;
-
- sigdata->tempo = 125;
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- /** WARNING: which ones? */
- sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M;
-
- sigdata->speed = dumbfile_getc(f) >> 4;
- if ( sigdata->speed < 1 ) sigdata->speed = 1;
- sigdata->n_patterns = dumbfile_getc(f);
- sigdata->global_volume = dumbfile_getc(f) << 1;
- if ( sigdata->global_volume > 128 ) sigdata->global_volume = 128;
-
- dumbfile_skip(f, 13);
-
- if ( dumbfile_error(f) || sigdata->n_patterns < 1 || sigdata->n_patterns > 99 ) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_samples; n++)
- sigdata->sample[n].data = NULL;
-
- if (sigdata->n_patterns) {
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (n = 0; n < sigdata->n_patterns; n++)
- sigdata->pattern[n].entry = NULL;
- }
-
- memset( sigdata->channel_volume, 64, 4 );
- sigdata->channel_pan[ 0 ] = 48;
- sigdata->channel_pan[ 1 ] = 16;
- sigdata->channel_pan[ 2 ] = 48;
- sigdata->channel_pan[ 3 ] = 16;
-
- for ( n = 0; n < sigdata->n_samples; ++n ) {
- if ( it_stm_read_sample_header( &sigdata->sample[ n ], f ) ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
-
- sigdata->order = malloc( 128 );
- if ( !sigdata->order ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
-
- /* Orders, byte each, length = sigdata->n_orders (should be even) */
- dumbfile_getnc( sigdata->order, 128, f );
- sigdata->restart_position = 0;
-
- for ( n = 127; n >= 0; --n ) {
- if ( sigdata->order[ n ] < sigdata->n_patterns ) break;
- }
- if ( n < 0 ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- sigdata->n_orders = n + 1;
-
- for ( n = 0; n < 128; ++n ) {
- if ( sigdata->order[ n ] >= 99 ) sigdata->order[ n ] = 0xFF;
- }
-
- if ( sigdata->n_patterns ) {
- unsigned char * buffer = malloc( 64 * 4 * 4 );
- if ( ! buffer ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- for ( n = 0; n < sigdata->n_patterns; ++n ) {
- if ( it_stm_read_pattern( &sigdata->pattern[ n ], f, buffer ) ) {
- free( buffer );
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
- free( buffer );
- }
-
- for ( n = 0; n < sigdata->n_samples; ++n ) {
- if ( it_stm_read_sample_data( &sigdata->sample[ n ], f ) ) {
- _dumb_it_unload_sigdata( sigdata );
- return NULL;
- }
- }
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-/*static char hexdigit(int in)
-{
- if (in < 10) return in + '0';
- else return in + 'A' - 10;
-}*/
-
-DUH *dumb_read_stm_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
- /*int ver;*/
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_stm_load_sigdata(f /*, &ver*/);
-
- if (!sigdata)
- return NULL;
-
- {
- /*char version[16];*/
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- tag[1][1] = "STM";
- /*version[0] = 'S';
- version[1] = 'T';
- version[2] = 'M';
- version[3] = ' ';
- version[4] = 'v';
- version[5] = hexdigit((ver >> 8) & 15);
- version[6] = '.';
- version[7] = hexdigit((ver >> 4) & 15);
- version[8] = hexdigit(ver & 15);
- version[9] = 0;
- tag[1][1] = (const char *) &version;*/
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readstm.c - Code to read a ScreamTracker 2 / / \ \ + * module from an open file. | < / \_ + * | \/ /\ / + * By Chris Moeller. \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +// IT_STEREO... :o +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" +#include "internal/it.h" + +/** WARNING: this is duplicated in itread.c */ +static int it_seek(DUMBFILE *f, long offset) +{ + long pos = dumbfile_pos(f); + + if (pos > offset) { + return -1; + } + + if (pos < offset) + if (dumbfile_skip(f, offset - pos)) + return -1; + + return 0; +} + +static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f ) +{ + dumbfile_getnc( sample->filename, 12, f ); + sample->filename[12] = 0; + + memcpy( sample->name, sample->filename, 13 ); + + dumbfile_skip( f, 2 + 2 ); + + sample->length = dumbfile_igetw( f ); + sample->loop_start = dumbfile_igetw( f ); + sample->loop_end = dumbfile_igetw( f ); + + sample->default_volume = dumbfile_getc( f ); + + dumbfile_skip( f, 1 ); + + sample->C5_speed = dumbfile_igetw( f ) << 3; + + dumbfile_skip( f, 6 ); + + if ( sample->length < 4 || !sample->default_volume ) { + /* Looks like no-existy. */ + sample->flags &= ~IT_SAMPLE_EXISTS; + sample->length = 0; + return dumbfile_error( f ); + } + + sample->flags = IT_SAMPLE_EXISTS; + sample->global_volume = 64; + sample->default_pan = 0; // 0 = don't use, or 160 = centre? + + if ( ( sample->loop_start < sample->length ) && + ( sample->loop_end > sample->loop_start ) && + ( sample->loop_end != 0xFFFF ) ) { + sample->flags |= IT_SAMPLE_LOOP; + if ( sample->loop_end > sample->length ) sample->loop_end = sample->length; + } + + //Do we need to set all these? + sample->vibrato_speed = 0; + sample->vibrato_depth = 0; + sample->vibrato_rate = 0; + sample->vibrato_waveform = IT_VIBRATO_SINE; + sample->finetune = 0; + sample->max_resampling_quality = -1; + + return dumbfile_error(f); +} + +static int it_stm_read_sample_data( IT_SAMPLE *sample, DUMBFILE *f ) +{ + long n; + + if ( ! sample->length ) return 0; + + n = dumbfile_pos( f ); + if ( n & 15 ) { + if ( dumbfile_skip( f, 16 - ( n & 15 ) ) ) + return -1; + } + + sample->data = malloc( sample->length ); + if (!sample->data) + return -1; + + if ( dumbfile_getnc( sample->data, sample->length, f ) != sample->length ) + return -1; + + return 0; +} + +static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char *buffer ) +{ + int pos; + int channel; + int row; + IT_ENTRY *entry; + + pattern->n_rows = 64; + + if ( dumbfile_getnc( buffer, 64 * 4 * 4, f ) != 64 * 4 * 4 ) + return -1; + + pattern->n_entries = 64; + pos = 0; + for ( row = 0; row < 64; ++row ) { + for ( channel = 0; channel < 4; ++channel ) { + if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) + ++pattern->n_entries; + pos += 4; + } + } + + pattern->entry = malloc( pattern->n_entries * sizeof( *pattern->entry ) ); + if ( !pattern->entry ) + return -1; + + entry = pattern->entry; + pos = 0; + for ( row = 0; row < 64; ++row ) { + for ( channel = 0; channel < 4; ++channel ) { + if ( buffer[ pos + 0 ] | buffer[ pos + 1 ] | buffer[ pos + 2 ] | buffer[ pos + 3 ] ) { + unsigned note; + note = buffer[ pos + 0 ]; + entry->channel = channel; + entry->mask = 0; + entry->instrument = buffer[ pos + 1 ] >> 3; + entry->volpan = ( buffer[ pos + 1 ] & 0x07 ) + ( buffer[ pos + 2 ] >> 1 ); + entry->effect = buffer[ pos + 2 ] & 0x0F; + entry->effectvalue = buffer[ pos + 3 ]; + if ( entry->instrument && entry->instrument < 32 ) + entry->mask |= IT_ENTRY_INSTRUMENT; + if ( note == 0xFC || note == 0xFE ) { + entry->mask |= IT_ENTRY_NOTE; + entry->note = IT_NOTE_CUT; + } + if ( note < 251 ) { + entry->mask |= IT_ENTRY_NOTE; + entry->note = ( note >> 4 ) * 12 + ( note & 0x0F ); + } + if ( entry->volpan <= 64 ) + entry->mask |= IT_ENTRY_VOLPAN; + entry->mask |= IT_ENTRY_EFFECT; + switch ( entry->effect ) { + case IT_SET_SPEED: + entry->effectvalue >>= 4; + break; + + case IT_BREAK_TO_ROW: + entry->effectvalue -= (entry->effectvalue >> 4) * 6; + break; + + case IT_JUMP_TO_ORDER: + case IT_VOLUME_SLIDE: + case IT_PORTAMENTO_DOWN: + case IT_PORTAMENTO_UP: + case IT_TONE_PORTAMENTO: + case IT_VIBRATO: + case IT_TREMOR: + case IT_ARPEGGIO: + case IT_VOLSLIDE_VIBRATO: + case IT_VOLSLIDE_TONEPORTA: + break; + + default: + entry->mask &= ~IT_ENTRY_EFFECT; + break; + } + if ( entry->mask ) ++entry; + } + pos += 4; + } + IT_SET_END_ROW(entry); + ++entry; + } + + pattern->n_entries = entry - pattern->entry; + + return 0; +} + + + +static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f /*, int * version*/) +{ + DUMB_IT_SIGDATA *sigdata; + + char tracker_name[ 8 ]; + + int n; + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) return NULL; + + /* Skip song name. */ + dumbfile_getnc(sigdata->name, 20, f); + sigdata->name[20] = 0; + + dumbfile_getnc(tracker_name, 8, f); + n = dumbfile_getc(f); + if ( n != 0x02 && n != 0x1A && n != 0x1B ) + { + free( sigdata ); + return NULL; + } + if ( dumbfile_getc(f) != 2 ) /* only support modules */ + { + free( sigdata ); + return NULL; + } + if ( strncasecmp( tracker_name, "!Scream!", 8 ) && + strncasecmp( tracker_name, "BMOD2STM", 8 ) && + strncasecmp( tracker_name, "WUZAMOD!", 8 ) ) + { + free( sigdata ); + return NULL; + } + + /* *version = dumbfile_mgetw(f); */ + dumbfile_skip( f, 2 ); + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->sample = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->n_instruments = 0; + sigdata->n_samples = 31; + sigdata->n_pchannels = 4; + + sigdata->tempo = 125; + sigdata->mixing_volume = 48; + sigdata->pan_separation = 128; + + /** WARNING: which ones? */ + sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M; + + sigdata->speed = dumbfile_getc(f) >> 4; + if ( sigdata->speed < 1 ) sigdata->speed = 1; + sigdata->n_patterns = dumbfile_getc(f); + sigdata->global_volume = dumbfile_getc(f) << 1; + if ( sigdata->global_volume > 128 ) sigdata->global_volume = 128; + + dumbfile_skip(f, 13); + + if ( dumbfile_error(f) || sigdata->n_patterns < 1 || sigdata->n_patterns > 99 ) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); + if (!sigdata->sample) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (n = 0; n < sigdata->n_samples; n++) + sigdata->sample[n].data = NULL; + + if (sigdata->n_patterns) { + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (n = 0; n < sigdata->n_patterns; n++) + sigdata->pattern[n].entry = NULL; + } + + memset( sigdata->channel_volume, 64, 4 ); + sigdata->channel_pan[ 0 ] = 48; + sigdata->channel_pan[ 1 ] = 16; + sigdata->channel_pan[ 2 ] = 48; + sigdata->channel_pan[ 3 ] = 16; + + for ( n = 0; n < sigdata->n_samples; ++n ) { + if ( it_stm_read_sample_header( &sigdata->sample[ n ], f ) ) { + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + } + + sigdata->order = malloc( 128 ); + if ( !sigdata->order ) { + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + + /* Orders, byte each, length = sigdata->n_orders (should be even) */ + dumbfile_getnc( sigdata->order, 128, f ); + sigdata->restart_position = 0; + + for ( n = 127; n >= 0; --n ) { + if ( sigdata->order[ n ] < sigdata->n_patterns ) break; + } + if ( n < 0 ) { + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + sigdata->n_orders = n + 1; + + for ( n = 0; n < 128; ++n ) { + if ( sigdata->order[ n ] >= 99 ) sigdata->order[ n ] = 0xFF; + } + + if ( sigdata->n_patterns ) { + unsigned char * buffer = malloc( 64 * 4 * 4 ); + if ( ! buffer ) { + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + for ( n = 0; n < sigdata->n_patterns; ++n ) { + if ( it_stm_read_pattern( &sigdata->pattern[ n ], f, buffer ) ) { + free( buffer ); + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + } + free( buffer ); + } + + for ( n = 0; n < sigdata->n_samples; ++n ) { + if ( it_stm_read_sample_data( &sigdata->sample[ n ], f ) ) { + _dumb_it_unload_sigdata( sigdata ); + return NULL; + } + } + + _dumb_it_fix_invalid_orders(sigdata); + + return sigdata; +} + +/*static char hexdigit(int in) +{ + if (in < 10) return in + '0'; + else return in + 'A' - 10; +}*/ + +DUH *dumb_read_stm_quick(DUMBFILE *f) +{ + sigdata_t *sigdata; + /*int ver;*/ + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_stm_load_sigdata(f /*, &ver*/); + + if (!sigdata) + return NULL; + + { + /*char version[16];*/ + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + tag[1][1] = "STM"; + /*version[0] = 'S'; + version[1] = 'T'; + version[2] = 'M'; + version[3] = ' '; + version[4] = 'v'; + version[5] = hexdigit((ver >> 8) & 15); + version[6] = '.'; + version[7] = hexdigit((ver >> 4) & 15); + version[8] = hexdigit(ver & 15); + version[9] = 0; + tag[1][1] = (const char *) &version;*/ + return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/readstm2.c b/plugins/dumb/dumb-kode54/src/it/readstm2.c index c336b2a3..dab2c9b7 100644 --- a/plugins/dumb/dumb-kode54/src/it/readstm2.c +++ b/plugins/dumb/dumb-kode54/src/it/readstm2.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readstm2.c - Function to read a ScreamTracker 2 / / \ \
- * module from an open file and do an | < / \_
- * initial run-through. | \/ /\ /
- * \_ / > /
- * By Chris Moeller. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_read_stm(DUMBFILE *f)
-{
- DUH *duh = dumb_read_stm_quick(f);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readstm2.c - Function to read a ScreamTracker 2 / / \ \ + * module from an open file and do an | < / \_ + * initial run-through. | \/ /\ / + * \_ / > / + * By Chris Moeller. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_read_stm(DUMBFILE *f) +{ + DUH *duh = dumb_read_stm_quick(f); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/readxm.c b/plugins/dumb/dumb-kode54/src/it/readxm.c index c76d0f3e..7ceed801 100644 --- a/plugins/dumb/dumb-kode54/src/it/readxm.c +++ b/plugins/dumb/dumb-kode54/src/it/readxm.c @@ -1,1210 +1,1216 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readxm.c - Code to read a Fast Tracker II / / \ \
- * module from an open file. | < / \_
- * | \/ /\ /
- * By Julien Cugniere. Some bits of code taken \_ / > /
- * from reads3m.c. | \ / /
- * | ' /
- * \__/
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-
-
-/** TODO:
-
- * XM_TREMOLO doesn't sound quite right...
- * XM_SET_ENVELOPE_POSITION todo.
-
- * VIBRATO conversion needs to be checked (sample/effect/volume). Plus check
- that effect memory is correct when using XM_VOLSLIDE_VIBRATO.
- - sample vibrato (instrument vibrato) is now handled correctly. - entheh
-
- * XM_E_SET_VIBRATO/TREMOLO_CONTROL: effectvalue&4 -> don't retrig wave when
- a new instrument is played. In retrigger_note()?. Is it worth implementing?
-
- * Lossy fadeout approximation. 0..31 converted to 0 --> won't fade at all.
-
- * Replace DUMB's sawtooth by ramp_down/ramp_up. Update XM loader.
-
- * A lot of things need to be reset when the end of the song is reached.
-
- * It seems that IT and XM don't behave the same way when dealing with
- mixed loops. When IT encounters multiple SBx (x>0) commands on the same
- row, it decrements the loop count for all, but only execute the loop of
- the last one (highest channel). FT2 only decrements the loop count of the
- last one. Not that I know of any modules using so convoluted combinations!
-
- * Maybe we could remove patterns that don't appear in the order table ? Or
- provide a function to "optimize" a DUMB_IT_SIGDATA ?
-
-*/
-
-
-
-#define XM_LINEAR_FREQUENCY 1 /* otherwise, use amiga slides */
-
-#define XM_ENTRY_PACKED 128
-#define XM_ENTRY_NOTE 1
-#define XM_ENTRY_INSTRUMENT 2
-#define XM_ENTRY_VOLUME 4
-#define XM_ENTRY_EFFECT 8
-#define XM_ENTRY_EFFECTVALUE 16
-
-#define XM_NOTE_OFF 97
-
-#define XM_ENVELOPE_ON 1
-#define XM_ENVELOPE_SUSTAIN 2
-#define XM_ENVELOPE_LOOP 4
-
-#define XM_SAMPLE_NO_LOOP 0
-#define XM_SAMPLE_FORWARD_LOOP 1
-#define XM_SAMPLE_PINGPONG_LOOP 2
-#define XM_SAMPLE_16BIT 16
-#define XM_SAMPLE_STEREO 32
-
-#define XM_VIBRATO_SINE 0
-#define XM_VIBRATO_SQUARE 1
-#define XM_VIBRATO_RAMP_DOWN 2
-#define XM_VIBRATO_RAMP_UP 3
-
-
-
-/* Probably useless :) */
-const char xm_convert_vibrato[] = {
- IT_VIBRATO_SINE,
- IT_VIBRATO_XM_SQUARE,
- IT_VIBRATO_RAMP_DOWN,
- IT_VIBRATO_RAMP_UP,
- IT_VIBRATO_RANDOM
-};
-
-
-
-#define XM_MAX_SAMPLES_PER_INSTRUMENT 16
-
-
-
-/* Extra data that doesn't fit inside IT_INSTRUMENT */
-typedef struct XM_INSTRUMENT_EXTRA
-{
- int n_samples;
- int vibrato_type;
- int vibrato_sweep; /* 0-0xFF */
- int vibrato_depth; /* 0-0x0F */
- int vibrato_speed; /* 0-0x3F */
-}
-XM_INSTRUMENT_EXTRA;
-
-
-
-/* Frees the original block if it can't resize it or if size is 0, and acts
- * as malloc if ptr is NULL.
- */
-static void *safe_realloc(void *ptr, size_t size)
-{
- if (ptr == NULL)
- return malloc(size);
-
- if (size == 0) {
- free(ptr);
- return NULL;
- } else {
- void *new_block = realloc(ptr, size);
- if (!new_block)
- free(ptr);
- return new_block;
- }
-}
-
-
-
-/* The interpretation of the XM volume column is left to the player. Here, we
- * just filter bad values.
- */
-// This function is so tiny now, should we inline it?
-static void it_xm_convert_volume(int volume, IT_ENTRY *entry)
-{
- entry->mask |= IT_ENTRY_VOLPAN;
- entry->volpan = volume;
-
- switch (volume >> 4) {
- case 0xA: /* set vibrato speed */
- case 0xB: /* vibrato */
- case 0xF: /* tone porta */
- case 0x6: /* vol slide up */
- case 0x7: /* vol slide down */
- case 0x8: /* fine vol slide up */
- case 0x9: /* fine vol slide down */
- case 0xC: /* set panning */
- case 0xD: /* pan slide left */
- case 0xE: /* pan slide right */
- case 0x1: /* set volume */
- case 0x2: /* set volume */
- case 0x3: /* set volume */
- case 0x4: /* set volume */
- break;
-
- case 0x5:
- if (volume == 0x50)
- break; /* set volume */
- /* else fall through */
-
- default:
- entry->mask &= ~IT_ENTRY_VOLPAN;
- break;
- }
-}
-
-
-
-static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer, int version)
-{
- int size;
- int pos;
- int channel;
- int row;
- int effect, effectvalue;
- IT_ENTRY *entry;
-
- /* pattern header size */
- if (dumbfile_igetl(f) != ( version == 0x0102 ? 0x08 : 0x09 ) ) {
- TRACE("XM error: unexpected pattern header size\n");
- return -1;
- }
-
- /* pattern data packing type */
- if (dumbfile_getc(f) != 0) {
- TRACE("XM error: unexpected pattern packing type\n");
- return -1;
- }
-
- if ( version == 0x0102 )
- pattern->n_rows = dumbfile_getc(f) + 1;
- else
- pattern->n_rows = dumbfile_igetw(f); /* 1..256 */
- size = dumbfile_igetw(f);
- pattern->n_entries = 0;
-
- if (dumbfile_error(f))
- return -1;
-
- if (size == 0)
- return 0;
-
- if (size > 1280 * n_channels) {
- TRACE("XM error: pattern data size > %d bytes\n", 1280 * n_channels);
- return -1;
- }
-
- if (dumbfile_getnc(buffer, size, f) < size)
- return -1;
-
- /* compute number of entries */
- pattern->n_entries = 0;
- pos = channel = row = 0;
- while (pos < size) {
- if (!(buffer[pos] & XM_ENTRY_PACKED) || (buffer[pos] & 31))
- pattern->n_entries++;
-
- channel++;
- if (channel >= n_channels) {
- channel = 0;
- row++;
- pattern->n_entries++;
- }
-
- if (buffer[pos] & XM_ENTRY_PACKED) {
- static const char offset[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
- 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5 };
- pos += 1 + offset[buffer[pos] & 31];
- } else {
- pos += 5;
- }
- }
-
- if (row > pattern->n_rows) {
- TRACE("XM error: wrong number of rows in pattern data\n");
- return -1;
- }
-
- /* Whoops, looks like some modules may be short, a few channels, maybe even rows... */
-
- while (row < pattern->n_rows)
- {
- pattern->n_entries++;
- row++;
- }
-
- pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry));
- if (!pattern->entry)
- return -1;
-
- /* read the entries */
- entry = pattern->entry;
- pos = channel = row = 0;
- while (pos < size) {
- unsigned char mask;
-
- if (buffer[pos] & XM_ENTRY_PACKED)
- mask = buffer[pos++] & 31;
- else
- mask = 31;
-
- if (mask) {
- ASSERT(entry < pattern->entry + pattern->n_entries);
-
- entry->channel = channel;
- entry->mask = 0;
-
- if (mask & XM_ENTRY_NOTE) {
- int note = buffer[pos++]; /* 1-96 <=> C0-B7 */
- entry->note = (note == XM_NOTE_OFF) ? (IT_NOTE_OFF) : (note-1);
- entry->mask |= IT_ENTRY_NOTE;
- }
-
- if (mask & XM_ENTRY_INSTRUMENT) {
- entry->instrument = buffer[pos++]; /* 1-128 */
- entry->mask |= IT_ENTRY_INSTRUMENT;
- }
-
- if (mask & XM_ENTRY_VOLUME)
- it_xm_convert_volume(buffer[pos++], entry);
-
- effect = effectvalue = 0;
- if (mask & XM_ENTRY_EFFECT) effect = buffer[pos++];
- if (mask & XM_ENTRY_EFFECTVALUE) effectvalue = buffer[pos++];
- _dumb_it_xm_convert_effect(effect, effectvalue, entry, 0);
-
- entry++;
- }
-
- channel++;
- if (channel >= n_channels) {
- channel = 0;
- row++;
- IT_SET_END_ROW(entry);
- entry++;
- }
- }
-
- while (row < pattern->n_rows)
- {
- row++;
- IT_SET_END_ROW(entry);
- entry++;
- }
-
- return 0;
-}
-
-
-
-static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data, int y_offset)
-{
- int i, pos;
-
- if (envelope->n_nodes > 12) {
- /* XXX
- TRACE("XM error: wrong number of envelope nodes (%d)\n", envelope->n_nodes);
- envelope->n_nodes = 0;
- return -1; */
- envelope->n_nodes = 12;
- }
-
- if (envelope->sus_loop_start >= 12) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP;
- if (envelope->loop_end >= 12) envelope->loop_end = 0;
- if (envelope->loop_start >= envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON;
-
- pos = 0;
- for (i = 0; i < envelope->n_nodes; i++) {
- envelope->node_t[i] = data[pos++];
- if (data[pos] > 64) {
- TRACE("XM error: out-of-range envelope node (node_y[%d]=%d)\n", i, data[pos]);
- envelope->n_nodes = 0;
- return -1;
- }
- envelope->node_y[i] = (signed char)(data[pos++] + y_offset);
- }
-
- return 0;
-}
-
-
-
-static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA *extra, DUMBFILE *f)
-{
- unsigned long size, bytes_read;
- unsigned short vol_points[24];
- unsigned short pan_points[24];
- int i, type;
-
- /* Header size. Tends to be more than the actual size of the structure.
- * So unread bytes must be skipped before reading the first sample
- * header.
- */
- size = dumbfile_igetl(f);
-
- dumbfile_getnc(instrument->name, 22, f);
- instrument->name[22] = 0;
- instrument->filename[0] = 0;
- dumbfile_skip(f, 1); /* Instrument type. Should be 0, but seems random. */
- extra->n_samples = dumbfile_igetw(f);
-
- if (dumbfile_error(f) || (unsigned int)extra->n_samples > XM_MAX_SAMPLES_PER_INSTRUMENT)
- return -1;
-
- bytes_read = 4 + 22 + 1 + 2;
-
- if (extra->n_samples) {
- /* sample header size */
- dumbfile_skip(f, 4); // XXX can't be trusted, as there are trackers that write the wrong value here
- /*i = dumbfile_igetl(f);
- if (i && i != 0x28) { // XXX some crap with 0 here
- TRACE("XM error: unexpected sample header size\n");
- return -1;
- }*/
-
- /* sample map */
- for (i = 0; i < 96; i++) {
- instrument->map_sample[i] = dumbfile_getc(f) + 1;
- instrument->map_note[i] = i;
- }
-
- if (dumbfile_error(f))
- return 1;
-
- /* volume/panning envelopes */
- for (i = 0; i < 24; i++)
- vol_points[i] = dumbfile_igetw(f);
- for (i = 0; i < 24; i++)
- pan_points[i] = dumbfile_igetw(f);
-
- instrument->volume_envelope.n_nodes = dumbfile_getc(f);
- instrument->pan_envelope.n_nodes = dumbfile_getc(f);
-
- if (dumbfile_error(f))
- return -1;
-
- instrument->volume_envelope.sus_loop_start = dumbfile_getc(f);
- instrument->volume_envelope.loop_start = dumbfile_getc(f);
- instrument->volume_envelope.loop_end = dumbfile_getc(f);
-
- instrument->pan_envelope.sus_loop_start = dumbfile_getc(f);
- instrument->pan_envelope.loop_start = dumbfile_getc(f);
- instrument->pan_envelope.loop_end = dumbfile_getc(f);
-
- /* The envelope handler for XM files won't use sus_loop_end. */
-
- type = dumbfile_getc(f);
- instrument->volume_envelope.flags = 0;
- if ((type & XM_ENVELOPE_ON) && instrument->volume_envelope.n_nodes)
- instrument->volume_envelope.flags |= IT_ENVELOPE_ON;
- if (type & XM_ENVELOPE_LOOP) instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON;
-#if 1
- if (type & XM_ENVELOPE_SUSTAIN) instrument->volume_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP;
-#else // This is now handled in itrender.c
- /* let's avoid fading out when reaching the last envelope node */
- if (!(type & XM_ENVELOPE_LOOP)) {
- instrument->volume_envelope.loop_start = instrument->volume_envelope.n_nodes-1;
- instrument->volume_envelope.loop_end = instrument->volume_envelope.n_nodes-1;
- }
- instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON;
-#endif
-
- type = dumbfile_getc(f);
- instrument->pan_envelope.flags = 0;
- if ((type & XM_ENVELOPE_ON) && instrument->pan_envelope.n_nodes)
- instrument->pan_envelope.flags |= IT_ENVELOPE_ON;
- if (type & XM_ENVELOPE_LOOP) instrument->pan_envelope.flags |= IT_ENVELOPE_LOOP_ON; // should this be here?
- if (type & XM_ENVELOPE_SUSTAIN) instrument->pan_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP;
-
- if (it_xm_make_envelope(&instrument->volume_envelope, vol_points, 0) != 0) {
- TRACE("XM error: volume envelope\n");
- if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) return -1;
- }
-
- if (it_xm_make_envelope(&instrument->pan_envelope, pan_points, -32) != 0) {
- TRACE("XM error: pan envelope\n");
- if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) return -1;
- }
-
- instrument->pitch_envelope.flags = 0;
-
- extra->vibrato_type = dumbfile_getc(f);
- extra->vibrato_sweep = dumbfile_getc(f);
- extra->vibrato_depth = dumbfile_getc(f);
- extra->vibrato_speed = dumbfile_getc(f);
-
- if (dumbfile_error(f) || extra->vibrato_type > 4) // XXX
- return -1;
-
- /** WARNING: lossy approximation */
- instrument->fadeout = (dumbfile_igetw(f)*128 + 64)/0xFFF;
-
- dumbfile_skip(f, 2); /* reserved */
-
- bytes_read += 4 + 96 + 48 + 48 + 14*1 + 2 + 2;
- } else
- for (i = 0; i < 96; i++)
- instrument->map_sample[i] = 0;
-
- if (dumbfile_skip(f, size - bytes_read))
- return -1;
-
- instrument->new_note_action = NNA_NOTE_CUT;
- instrument->dup_check_type = DCT_OFF;
- instrument->dup_check_action = DCA_NOTE_CUT;
- instrument->pp_separation = 0;
- instrument->pp_centre = 60; /* C-5 */
- instrument->global_volume = 128;
- instrument->default_pan = 32;
- instrument->random_volume = 0;
- instrument->random_pan = 0;
- instrument->filter_cutoff = 0;
- instrument->filter_resonance = 0;
-
- return 0;
-}
-
-
-
-/* I (entheh) have two XM files saved by a very naughty program. After a
- * 16-bit sample, it saved a rogue byte. The length of the sample was indeed
- * an odd number, incremented to include the rogue byte.
- *
- * In this function we are converting sample lengths and loop points so they
- * are measured in samples. This means we forget about the extra bytes, and
- * they don't get skipped. So we fail trying to read the next instrument.
- *
- * To get around this, this function returns the number of rogue bytes that
- * won't be accounted for by reading sample->length samples. It returns a
- * negative number on failure.
- */
-static int it_xm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f)
-{
- int type;
- int relative_note_number; /* relative to C4 */
- int finetune;
- int roguebytes;
- int roguebytesmask;
- int reserved;
-
- sample->length = dumbfile_igetl(f);
- sample->loop_start = dumbfile_igetl(f);
- sample->loop_end = sample->loop_start + dumbfile_igetl(f);
- sample->global_volume = 64;
- sample->default_volume = dumbfile_getc(f);
- finetune = (signed char)dumbfile_getc(f); /* -128..127 <=> -1 semitone .. +127/128 of a semitone */
- type = dumbfile_getc(f);
- sample->default_pan = dumbfile_getc(f); /* 0-255 */
- relative_note_number = (signed char)dumbfile_getc(f);
-
- /*dumbfile_skip(f, 1); /* reserved */
- reserved = dumbfile_getc(f);
-
- dumbfile_getnc(sample->name, 22, f);
- sample->name[22] = 0;
-
- sample->filename[0] = 0;
-
- if (dumbfile_error(f))
- return -1;
-
- sample->C5_speed = (long)(16726.0*pow(DUMB_SEMITONE_BASE, relative_note_number) /**pow(DUMB_PITCH_BASE, )*/ );
- sample->finetune = finetune*2;
-
- sample->flags = IT_SAMPLE_EXISTS;
-
- if (reserved == 0xAD &&
- (!(type & (XM_SAMPLE_16BIT | XM_SAMPLE_STEREO))))
- {
- /* F U Olivier Lapicque */
- roguebytes = 4;
- roguebytesmask = 4 << 2;
- }
- else
- {
- roguebytes = (int)sample->length;
- roguebytesmask = 3;
- }
-
- if (type & XM_SAMPLE_16BIT) {
- sample->flags |= IT_SAMPLE_16BIT;
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- } else
- roguebytesmask >>= 1;
-
- if (type & XM_SAMPLE_STEREO) {
- sample->flags |= IT_SAMPLE_STEREO;
- sample->length >>= 1;
- sample->loop_start >>= 1;
- sample->loop_end >>= 1;
- } else
- roguebytesmask >>= 1;
-
- roguebytes &= roguebytesmask;
-
- if ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end) {
- if (type & XM_SAMPLE_FORWARD_LOOP) sample->flags |= IT_SAMPLE_LOOP;
- if (type & XM_SAMPLE_PINGPONG_LOOP) sample->flags |= IT_SAMPLE_LOOP | IT_SAMPLE_PINGPONG_LOOP;
- }
-
- if (sample->length <= 0)
- sample->flags &= ~IT_SAMPLE_EXISTS;
- else if ((unsigned int)sample->loop_end > (unsigned int)sample->length)
- sample->flags &= ~IT_SAMPLE_LOOP;
- else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end)
- sample->flags &= ~IT_SAMPLE_LOOP;
-
- return roguebytes;
-}
-
-
-
-static int it_xm_read_sample_data(IT_SAMPLE *sample, unsigned char roguebytes, DUMBFILE *f)
-{
- int old;
- long i;
- long truncated_size;
- int n_channels;
- long datasize;
-
- if (!(sample->flags & IT_SAMPLE_EXISTS))
- return dumbfile_skip(f, roguebytes);
-
- /* let's get rid of the sample data coming after the end of the loop */
- if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length && roguebytes != 4) {
- truncated_size = sample->length - sample->loop_end;
- sample->length = sample->loop_end;
- } else {
- truncated_size = 0;
- }
-
- n_channels = sample->flags & IT_SAMPLE_STEREO ? 2 : 1;
- datasize = sample->length * n_channels;
-
- sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1));
- if (!sample->data)
- return -1;
-
- if (roguebytes == 4)
- {
- if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0)
- return -1;
- roguebytes = 0;
- }
- else
- {
- /* sample data is stored as signed delta values */
- old = 0;
- if (sample->flags & IT_SAMPLE_16BIT)
- for (i = 0; i < sample->length; i++)
- ((short *)sample->data)[i*n_channels] = old += dumbfile_igetw(f);
- else
- for (i = 0; i < sample->length; i++)
- ((signed char *)sample->data)[i*n_channels] = old += dumbfile_getc(f);
- }
-
- /* skip truncated data */
- dumbfile_skip(f, (sample->flags & IT_SAMPLE_16BIT) ? (2*truncated_size) : (truncated_size));
-
- if (sample->flags & IT_SAMPLE_STEREO) {
- old = 0;
- if (sample->flags & IT_SAMPLE_16BIT)
- for (i = 1; i < datasize; i += 2)
- ((short *)sample->data)[i] = old += dumbfile_igetw(f);
- else
- for (i = 1; i < datasize; i += 2)
- ((signed char *)sample->data)[i] = old += dumbfile_getc(f);
-
- /* skip truncated data */
- dumbfile_skip(f, (sample->flags & IT_SAMPLE_16BIT) ? (2*truncated_size) : (truncated_size));
- }
-
- dumbfile_skip(f, roguebytes);
-
- if (dumbfile_error(f))
- return -1;
-
- return 0;
-}
-
-
-
-/* "Real programmers don't document. If it was hard to write,
- * it should be hard to understand."
- *
- * (Never trust the documentation provided with a tracker.
- * Real files are the only truth...)
- */
-static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
-{
- DUMB_IT_SIGDATA *sigdata;
- char id_text[18];
-
- int header_size;
- int flags;
- int n_channels;
- int total_samples;
- int i, j;
-
- /* check ID text */
- if (dumbfile_getnc(id_text, 17, f) < 17)
- return NULL;
- id_text[17] = 0;
- if (strcmp(id_text, "Extended Module: ") != 0) {
- TRACE("XM error: Not an Extended Module\n");
- return NULL;
- }
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata)
- return NULL;
-
- /* song name */
- if (dumbfile_getnc(sigdata->name, 20, f) < 20) {
- free(sigdata);
- return NULL;
- }
- sigdata->name[20] = 0;
-
- if (dumbfile_getc(f) != 0x1A) {
- TRACE("XM error: 0x1A not found\n");
- free(sigdata);
- return NULL;
- }
-
- /* tracker name */
- if (dumbfile_skip(f, 20)) {
- free(sigdata);
- return NULL;
- }
-
- /* version number */
- * version = dumbfile_igetw(f);
- if (* version > 0x0104 || * version < 0x0102) {
- TRACE("XM error: wrong format version\n");
- free(sigdata);
- return NULL;
- }
-
- /*
- ------------------
- --- Header ---
- ------------------
- */
-
- /* header size */
- header_size = dumbfile_igetl(f);
- if (header_size < (4 + 2*8 + 1) || header_size > 0x114) {
- TRACE("XM error: unexpected header size\n");
- free(sigdata);
- return NULL;
- }
-
- sigdata->song_message = NULL;
- sigdata->order = NULL;
- sigdata->instrument = NULL;
- sigdata->sample = NULL;
- sigdata->pattern = NULL;
- sigdata->midi = NULL;
- sigdata->checkpoint = NULL;
-
- sigdata->n_samples = 0;
- sigdata->n_orders = dumbfile_igetw(f);
- sigdata->restart_position = dumbfile_igetw(f);
- n_channels = dumbfile_igetw(f); /* max 32 but we'll be lenient */
- sigdata->n_pchannels = n_channels;
- sigdata->n_patterns = dumbfile_igetw(f);
- sigdata->n_instruments = dumbfile_igetw(f); /* max 128 */ /* XXX upped to 256 */
- flags = dumbfile_igetw(f);
- sigdata->speed = dumbfile_igetw(f);
- if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo?
- sigdata->tempo = dumbfile_igetw(f);
-
- /* sanity checks */
- // XXX
- i = header_size - 4 - 2 * 8; /* Maximum number of orders expected */
- if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_orders > i || sigdata->n_patterns > 256 || sigdata->n_instruments > 256 || n_channels > DUMB_IT_N_CHANNELS) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- //if (sigdata->restart_position >= sigdata->n_orders)
- //sigdata->restart_position = 0;
-
- /* order table */
- sigdata->order = malloc(sigdata->n_orders*sizeof(*sigdata->order));
- if (!sigdata->order) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- dumbfile_getnc(sigdata->order, sigdata->n_orders, f);
- dumbfile_skip(f, i - sigdata->n_orders);
-
- if (dumbfile_error(f)) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if ( * version > 0x103 ) {
- /*
- --------------------
- --- Patterns ---
- --------------------
- */
-
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++)
- sigdata->pattern[i].entry = NULL;
-
- {
- unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */
- if (!buffer) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++) {
- if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) {
- free(buffer);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- free(buffer);
- }
-
- /*
- -----------------------------------
- --- Instruments and Samples ---
- -----------------------------------
- */
-
- sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
- if (!sigdata->instrument) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- /* With XM, samples are not global, they're part of an instrument. In a
- * file, each instrument is stored with its samples. Because of this, I
- * don't know how to find how many samples are present in the file. Thus
- * I have to do n_instruments reallocation on sigdata->sample.
- * Looking at FT2, it doesn't seem possible to have more than 16 samples
- * per instrument (even though n_samples is stored as 2 bytes). So maybe
- * we could allocate a 128*16 array of samples, and shrink it back to the
- * correct size when we know it?
- * Alternatively, I could allocate samples by blocks of N (still O(n)),
- * or double the number of allocated samples when I need more (O(log n)).
- */
- total_samples = 0;
- sigdata->sample = NULL;
-
- for (i = 0; i < sigdata->n_instruments; i++) {
- XM_INSTRUMENT_EXTRA extra;
-
- if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) {
- // XXX
- if ( ! i )
- {
- TRACE("XM error: instrument %d\n", i+1);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- else
- {
- sigdata->n_instruments = i;
- break;
- }
- }
-
- if (extra.n_samples) {
- unsigned char roguebytes[XM_MAX_SAMPLES_PER_INSTRUMENT];
-
- /* adjust instrument sample map (make indices absolute) */
- for (j = 0; j < 96; j++)
- sigdata->instrument[i].map_sample[j] += total_samples;
-
- sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
- if (!sigdata->sample) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (j = total_samples; j < total_samples+extra.n_samples; j++)
- sigdata->sample[j].data = NULL;
-
- /* read instrument's samples */
- for (j = 0; j < extra.n_samples; j++) {
- IT_SAMPLE *sample = &sigdata->sample[total_samples+j];
- int b = it_xm_read_sample_header(sample, f);
- if (b < 0) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- roguebytes[j] = b;
- // Any reason why these can't be set inside it_xm_read_sample_header()?
- sample->vibrato_speed = extra.vibrato_speed;
- sample->vibrato_depth = extra.vibrato_depth;
- sample->vibrato_rate = extra.vibrato_sweep;
- /* Rate and sweep don't match, but the difference is
- * accounted for in itrender.c.
- */
- sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type];
- sample->max_resampling_quality = -1;
- }
- for (j = 0; j < extra.n_samples; j++) {
- if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- total_samples += extra.n_samples;
- }
- }
-
- sigdata->n_samples = total_samples;
- } else {
- // ahboy! old layout!
- // first instruments and sample headers, then patterns, then sample data!
-
- /*
- -----------------------------------
- --- Instruments and Samples ---
- -----------------------------------
- */
-
- unsigned char * roguebytes = malloc( sigdata->n_instruments * XM_MAX_SAMPLES_PER_INSTRUMENT );
- if (!roguebytes) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
- if (!sigdata->instrument) {
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- total_samples = 0;
- sigdata->sample = NULL;
-
- for (i = 0; i < sigdata->n_instruments; i++) {
- XM_INSTRUMENT_EXTRA extra;
-
- if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) {
- TRACE("XM error: instrument %d\n", i+1);
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
-
- if (extra.n_samples) {
- /* adjust instrument sample map (make indices absolute) */
- for (j = 0; j < 96; j++)
- sigdata->instrument[i].map_sample[j] += total_samples;
-
- sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples));
- if (!sigdata->sample) {
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (j = total_samples; j < total_samples+extra.n_samples; j++)
- sigdata->sample[j].data = NULL;
-
- /* read instrument's samples */
- for (j = 0; j < extra.n_samples; j++) {
- IT_SAMPLE *sample = &sigdata->sample[total_samples+j];
- int b = it_xm_read_sample_header(sample, f);
- if (b < 0) {
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- roguebytes[total_samples+j] = b;
- // Any reason why these can't be set inside it_xm_read_sample_header()?
- sample->vibrato_speed = extra.vibrato_speed;
- sample->vibrato_depth = extra.vibrato_depth;
- sample->vibrato_rate = extra.vibrato_sweep;
- /* Rate and sweep don't match, but the difference is
- * accounted for in itrender.c.
- */
- sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type];
- sample->max_resampling_quality = -1;
- }
- total_samples += extra.n_samples;
- }
- }
-
- sigdata->n_samples = total_samples;
-
- /*
- --------------------
- --- Patterns ---
- --------------------
- */
-
- sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern));
- if (!sigdata->pattern) {
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++)
- sigdata->pattern[i].entry = NULL;
-
- {
- unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */
- if (!buffer) {
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- for (i = 0; i < sigdata->n_patterns; i++) {
- if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) {
- free(buffer);
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
- free(buffer);
- }
-
- // and now we load the sample data
- for (j = 0; j < total_samples; j++) {
- if (it_xm_read_sample_data(&sigdata->sample[j], roguebytes[j], f) != 0) {
- free(roguebytes);
- _dumb_it_unload_sigdata(sigdata);
- return NULL;
- }
- }
-
- free(roguebytes);
- }
-
-
- sigdata->flags = IT_WAS_AN_XM | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO | IT_USE_INSTRUMENTS;
- // Are we OK with IT_COMPATIBLE_GXX off?
- //
- // When specifying note + instr + tone portamento, and an old note is still playing (even after note off):
- // - If Compatible Gxx is on, the new note will be triggered only if the instrument _changes_.
- // - If Compatible Gxx is off, the new note will always be triggered, provided the instrument is specified.
- // - FT2 seems to do the latter (unconfirmed).
-
- // Err, wait. XM playback has its own code. The change made to the IT
- // playbackc code didn't affect XM playback. Forget this then. There's
- // still a bug in XM playback though, and it'll need some investigation...
- // tomorrow...
-
- // UPDATE: IT_COMPATIBLE_GXX is required to be on, so that tone porta has
- // separate memory from portamento.
-
- if (flags & XM_LINEAR_FREQUENCY)
- sigdata->flags |= IT_LINEAR_SLIDES;
-
- sigdata->global_volume = 128;
- sigdata->mixing_volume = 48;
- sigdata->pan_separation = 128;
-
- memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
- memset(sigdata->channel_pan, 32, DUMB_IT_N_CHANNELS);
-
- _dumb_it_fix_invalid_orders(sigdata);
-
- return sigdata;
-}
-
-
-
-#if 0 // no fucking way, dude!
-
-/* The length returned is the time required to play from the beginning of the
- * file to the last row of the last order (which is when the player will
- * loop). Depending on the song, the sound might stop sooner.
- * Due to fixed point roundoffs, I think this is only reliable to the second.
- * Full precision could be achieved by using a double during the computation,
- * or maybe a LONG_LONG.
- */
-long it_compute_length(const DUMB_IT_SIGDATA *sigdata)
-{
- IT_PATTERN *pattern;
- int tempo, speed;
- int loop_start[IT_N_CHANNELS];
- char loop_count[IT_N_CHANNELS];
- int order, entry;
- int row_first_entry = 0;
- int jump, jump_dest;
- int delay, fine_delay;
- int i;
- long t;
-
- if (!sigdata)
- return 0;
-
- tempo = sigdata->tempo;
- speed = sigdata->speed;
- order = entry = 0;
- jump = jump_dest = 0;
- t = 0;
-
- /* for each PATTERN */
- for (order = 0; order < sigdata->n_orders; order++) {
-
- if (sigdata->order[order] == IT_ORDER_END) break;
- if (sigdata->order[order] == IT_ORDER_SKIP) continue;
-
- for (i = 0; i < IT_N_CHANNELS; i++)
- loop_count[i] = -1;
-
- pattern = &sigdata->pattern[ sigdata->order[order] ];
- entry = 0;
- if (jump == IT_BREAK_TO_ROW) {
- int row = 0;
- while (row < jump_dest)
- if (pattern->entry[entry++].channel >= IT_N_CHANNELS)
- row++;
- }
-
- /* for each ROW */
- while (entry < pattern->n_entries) {
- row_first_entry = entry;
- delay = fine_delay = 0;
- jump = 0;
-
- /* for each note NOTE */
- while (entry < pattern->n_entries && pattern->entry[entry].channel < IT_N_CHANNELS) {
- int value = pattern->entry[entry].effectvalue;
- int channel = pattern->entry[entry].channel;
-
- switch (pattern->entry[entry].effect) {
-
- case IT_SET_SPEED: speed = value; break;
-
- case IT_JUMP_TO_ORDER:
- if (value <= order) /* infinite loop */
- return 0;
- jump = IT_JUMP_TO_ORDER;
- jump_dest = value;
- break;
-
- case IT_BREAK_TO_ROW:
- jump = IT_BREAK_TO_ROW;
- jump_dest = value;
- break;
-
- case IT_S:
- switch (HIGH(value)) {
- case IT_S_PATTERN_DELAY: delay = LOW(value); break;
- case IT_S_FINE_PATTERN_DELAY: fine_delay = LOW(value); break;
- case IT_S_PATTERN_LOOP:
- if (LOW(value) == 0) {
- loop_start[channel] = row_first_entry;
- } else {
- if (loop_count[channel] == -1)
- loop_count[channel] = LOW(value);
-
- if (loop_count[channel]) {
- jump = IT_S_PATTERN_LOOP;
- jump_dest = loop_start[channel];
- }
- loop_count[channel]--;
- }
- break;
- }
- break;
-
- case IT_SET_SONG_TEMPO:
- switch (HIGH(value)) { /* slides happen every non-row frames */
- case 0: tempo = tempo - LOW(value)*(speed-1); break;
- case 1: tempo = tempo + LOW(value)*(speed-1); break;
- default: tempo = value;
- }
- tempo = MID(32, tempo, 255);
- break;
- }
-
- entry++;
- }
-
- /* end of ROW */
- entry++;
- t += TICK_TIME_DIVIDEND * (speed*(1+delay) + fine_delay) / tempo;
-
- if (jump == IT_JUMP_TO_ORDER) {
- order = jump_dest - 1;
- break;
- } else if (jump == IT_BREAK_TO_ROW)
- break;
- else if (jump == IT_S_PATTERN_LOOP)
- entry = jump_dest - 1;
- }
-
- /* end of PATTERN */
- }
-
- return t;
-}
-
-#endif /* 0 */
-
-
-static char hexdigit(int in)
-{
- if (in < 10) return in + '0';
- else return in + 'A' - 10;
-}
-
-DUH *dumb_read_xm_quick(DUMBFILE *f)
-{
- sigdata_t *sigdata;
- int ver;
-
- DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it;
-
- sigdata = it_xm_load_sigdata(f, &ver);
-
- if (!sigdata)
- return NULL;
-
- {
- char version[16];
- const char *tag[2][2];
- tag[0][0] = "TITLE";
- tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name;
- tag[1][0] = "FORMAT";
- version[0] = 'X';
- version[1] = 'M';
- version[2] = ' ';
- version[3] = 'v';
- version[4] = hexdigit( ( ver >> 8 ) & 15 );
- version[5] = '.';
- version[6] = hexdigit( ( ver >> 4 ) & 15 );
- version[7] = hexdigit( ver & 15 );
- version[8] = 0;
- tag[1][1] = ( const char * ) & version;
- return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata);
- }
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readxm.c - Code to read a Fast Tracker II / / \ \ + * module from an open file. | < / \_ + * | \/ /\ / + * By Julien Cugniere. Some bits of code taken \_ / > / + * from reads3m.c. | \ / / + * | ' / + * \__/ + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "dumb.h" +#include "internal/it.h" + + + +/** TODO: + + * XM_TREMOLO doesn't sound quite right... + * XM_E_SET_FINETUNE done but not tested yet. + * XM_SET_ENVELOPE_POSITION todo. + + * VIBRATO conversion needs to be checked (sample/effect/volume). Plus check + that effect memory is correct when using XM_VOLSLIDE_VIBRATO. + - sample vibrato (instrument vibrato) is now handled correctly. - entheh + + * XM_E_SET_VIBRATO/TREMOLO_CONTROL: effectvalue&4 -> don't retrig wave when + a new instrument is played. In retrigger_note()?. Is it worth implementing? + + * Lossy fadeout approximation. 0..31 converted to 0 --> won't fade at all. + + * Replace DUMB's sawtooth by ramp_down/ramp_up. Update XM loader. + + * A lot of things need to be reset when the end of the song is reached. + + * It seems that IT and XM don't behave the same way when dealing with + mixed loops. When IT encounters multiple SBx (x>0) commands on the same + row, it decrements the loop count for all, but only execute the loop of + the last one (highest channel). FT2 only decrements the loop count of the + last one. Not that I know of any modules using so convoluted combinations! + + * Maybe we could remove patterns that don't appear in the order table ? Or + provide a function to "optimize" a DUMB_IT_SIGDATA ? + +*/ + + + +#define XM_LINEAR_FREQUENCY 1 /* otherwise, use amiga slides */ + +#define XM_ENTRY_PACKED 128 +#define XM_ENTRY_NOTE 1 +#define XM_ENTRY_INSTRUMENT 2 +#define XM_ENTRY_VOLUME 4 +#define XM_ENTRY_EFFECT 8 +#define XM_ENTRY_EFFECTVALUE 16 + +#define XM_NOTE_OFF 97 + +#define XM_ENVELOPE_ON 1 +#define XM_ENVELOPE_SUSTAIN 2 +#define XM_ENVELOPE_LOOP 4 + +#define XM_SAMPLE_NO_LOOP 0 +#define XM_SAMPLE_FORWARD_LOOP 1 +#define XM_SAMPLE_PINGPONG_LOOP 2 +#define XM_SAMPLE_16BIT 16 +#define XM_SAMPLE_STEREO 32 + +#define XM_VIBRATO_SINE 0 +#define XM_VIBRATO_SQUARE 1 +#define XM_VIBRATO_RAMP_DOWN 2 +#define XM_VIBRATO_RAMP_UP 3 + + + +/* Probably useless :) */ +const char xm_convert_vibrato[] = { + IT_VIBRATO_SINE, + IT_VIBRATO_XM_SQUARE, + IT_VIBRATO_RAMP_DOWN, + IT_VIBRATO_RAMP_UP, + IT_VIBRATO_RANDOM +}; + + + +#define XM_MAX_SAMPLES_PER_INSTRUMENT 16 + + + +/* Extra data that doesn't fit inside IT_INSTRUMENT */ +typedef struct XM_INSTRUMENT_EXTRA +{ + int n_samples; + int vibrato_type; + int vibrato_sweep; /* 0-0xFF */ + int vibrato_depth; /* 0-0x0F */ + int vibrato_speed; /* 0-0x3F */ +} +XM_INSTRUMENT_EXTRA; + + + +/* Frees the original block if it can't resize it or if size is 0, and acts + * as malloc if ptr is NULL. + */ +static void *safe_realloc(void *ptr, size_t size) +{ + if (ptr == NULL) + return malloc(size); + + if (size == 0) { + free(ptr); + return NULL; + } else { + void *new_block = realloc(ptr, size); + if (!new_block) + free(ptr); + return new_block; + } +} + + + +/* The interpretation of the XM volume column is left to the player. Here, we + * just filter bad values. + */ +// This function is so tiny now, should we inline it? +static void it_xm_convert_volume(int volume, IT_ENTRY *entry) +{ + entry->mask |= IT_ENTRY_VOLPAN; + entry->volpan = volume; + + switch (volume >> 4) { + case 0xA: /* set vibrato speed */ + case 0xB: /* vibrato */ + case 0xF: /* tone porta */ + case 0x6: /* vol slide up */ + case 0x7: /* vol slide down */ + case 0x8: /* fine vol slide up */ + case 0x9: /* fine vol slide down */ + case 0xC: /* set panning */ + case 0xD: /* pan slide left */ + case 0xE: /* pan slide right */ + case 0x1: /* set volume */ + case 0x2: /* set volume */ + case 0x3: /* set volume */ + case 0x4: /* set volume */ + break; + + case 0x5: + if (volume == 0x50) + break; /* set volume */ + /* else fall through */ + + default: + entry->mask &= ~IT_ENTRY_VOLPAN; + break; + } +} + + + +static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, unsigned char *buffer, int version) +{ + int size; + int pos; + int channel; + int row; + int effect, effectvalue; + IT_ENTRY *entry; + + /* pattern header size */ + if (dumbfile_igetl(f) != ( version == 0x0102 ? 0x08 : 0x09 ) ) { + TRACE("XM error: unexpected pattern header size\n"); + return -1; + } + + /* pattern data packing type */ + if (dumbfile_getc(f) != 0) { + TRACE("XM error: unexpected pattern packing type\n"); + return -1; + } + + if ( version == 0x0102 ) + pattern->n_rows = dumbfile_getc(f) + 1; + else + pattern->n_rows = dumbfile_igetw(f); /* 1..256 */ + size = dumbfile_igetw(f); + pattern->n_entries = 0; + + if (dumbfile_error(f)) + return -1; + + if (size == 0) + return 0; + + if (size > 1280 * n_channels) { + TRACE("XM error: pattern data size > %d bytes\n", 1280 * n_channels); + return -1; + } + + if (dumbfile_getnc(buffer, size, f) < size) + return -1; + + /* compute number of entries */ + pattern->n_entries = 0; + pos = channel = row = 0; + while (pos < size) { + if (!(buffer[pos] & XM_ENTRY_PACKED) || (buffer[pos] & 31)) + pattern->n_entries++; + + channel++; + if (channel >= n_channels) { + channel = 0; + row++; + pattern->n_entries++; + } + + if (buffer[pos] & XM_ENTRY_PACKED) { + static const char offset[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5 }; + pos += 1 + offset[buffer[pos] & 31]; + } else { + pos += 5; + } + } + + if (row > pattern->n_rows) { + TRACE("XM error: wrong number of rows in pattern data\n"); + return -1; + } + + /* Whoops, looks like some modules may be short, a few channels, maybe even rows... */ + + while (row < pattern->n_rows) + { + pattern->n_entries++; + row++; + } + + pattern->entry = malloc(pattern->n_entries * sizeof(*pattern->entry)); + if (!pattern->entry) + return -1; + + /* read the entries */ + entry = pattern->entry; + pos = channel = row = 0; + while (pos < size) { + unsigned char mask; + + if (buffer[pos] & XM_ENTRY_PACKED) + mask = buffer[pos++] & 31; + else + mask = 31; + + if (mask) { + ASSERT(entry < pattern->entry + pattern->n_entries); + + entry->channel = channel; + entry->mask = 0; + + if (mask & XM_ENTRY_NOTE) { + int note = buffer[pos++]; /* 1-96 <=> C0-B7 */ + entry->note = (note == XM_NOTE_OFF) ? (IT_NOTE_OFF) : (note-1); + entry->mask |= IT_ENTRY_NOTE; + } + + if (mask & XM_ENTRY_INSTRUMENT) { + entry->instrument = buffer[pos++]; /* 1-128 */ + entry->mask |= IT_ENTRY_INSTRUMENT; + } + + if (mask & XM_ENTRY_VOLUME) + it_xm_convert_volume(buffer[pos++], entry); + + effect = effectvalue = 0; + if (mask & XM_ENTRY_EFFECT) effect = buffer[pos++]; + if (mask & XM_ENTRY_EFFECTVALUE) effectvalue = buffer[pos++]; + _dumb_it_xm_convert_effect(effect, effectvalue, entry, 0); + + entry++; + } + + channel++; + if (channel >= n_channels) { + channel = 0; + row++; + IT_SET_END_ROW(entry); + entry++; + } + } + + while (row < pattern->n_rows) + { + row++; + IT_SET_END_ROW(entry); + entry++; + } + + return 0; +} + + + +static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data, int y_offset) +{ + int i, pos; + + if (envelope->n_nodes > 12) { + /* XXX + TRACE("XM error: wrong number of envelope nodes (%d)\n", envelope->n_nodes); + envelope->n_nodes = 0; + return -1; */ + envelope->n_nodes = 12; + } + + if (envelope->sus_loop_start >= 12) envelope->flags &= ~IT_ENVELOPE_SUSTAIN_LOOP; + if (envelope->loop_end >= 12) envelope->loop_end = 0; + if (envelope->loop_start >= envelope->loop_end) envelope->flags &= ~IT_ENVELOPE_LOOP_ON; + + pos = 0; + for (i = 0; i < envelope->n_nodes; i++) { + envelope->node_t[i] = data[pos++]; + if (data[pos] > 64) { + TRACE("XM error: out-of-range envelope node (node_y[%d]=%d)\n", i, data[pos]); + envelope->n_nodes = 0; + return -1; + } + envelope->node_y[i] = (signed char)(data[pos++] + y_offset); + } + + return 0; +} + + + +static int it_xm_read_instrument(IT_INSTRUMENT *instrument, XM_INSTRUMENT_EXTRA *extra, DUMBFILE *f) +{ + unsigned long size, bytes_read; + unsigned short vol_points[24]; + unsigned short pan_points[24]; + int i, type; + + /* Header size. Tends to be more than the actual size of the structure. + * So unread bytes must be skipped before reading the first sample + * header. + */ + size = dumbfile_igetl(f); + + dumbfile_getnc(instrument->name, 22, f); + instrument->name[22] = 0; + instrument->filename[0] = 0; + dumbfile_skip(f, 1); /* Instrument type. Should be 0, but seems random. */ + extra->n_samples = dumbfile_igetw(f); + + if (dumbfile_error(f) || (unsigned int)extra->n_samples > XM_MAX_SAMPLES_PER_INSTRUMENT) + return -1; + + bytes_read = 4 + 22 + 1 + 2; + + if (extra->n_samples) { + /* sample header size */ + dumbfile_skip(f, 4); // XXX can't be trusted, as there are trackers that write the wrong value here + /*i = dumbfile_igetl(f); + if (i && i != 0x28) { // XXX some crap with 0 here + TRACE("XM error: unexpected sample header size\n"); + return -1; + }*/ + + /* sample map */ + for (i = 0; i < 96; i++) { + instrument->map_sample[i] = dumbfile_getc(f) + 1; + instrument->map_note[i] = i; + } + + if (dumbfile_error(f)) + return 1; + + /* volume/panning envelopes */ + for (i = 0; i < 24; i++) + vol_points[i] = dumbfile_igetw(f); + for (i = 0; i < 24; i++) + pan_points[i] = dumbfile_igetw(f); + + instrument->volume_envelope.n_nodes = dumbfile_getc(f); + instrument->pan_envelope.n_nodes = dumbfile_getc(f); + + if (dumbfile_error(f)) + return -1; + + instrument->volume_envelope.sus_loop_start = dumbfile_getc(f); + instrument->volume_envelope.loop_start = dumbfile_getc(f); + instrument->volume_envelope.loop_end = dumbfile_getc(f); + + instrument->pan_envelope.sus_loop_start = dumbfile_getc(f); + instrument->pan_envelope.loop_start = dumbfile_getc(f); + instrument->pan_envelope.loop_end = dumbfile_getc(f); + + /* The envelope handler for XM files won't use sus_loop_end. */ + + type = dumbfile_getc(f); + instrument->volume_envelope.flags = 0; + if ((type & XM_ENVELOPE_ON) && instrument->volume_envelope.n_nodes) + instrument->volume_envelope.flags |= IT_ENVELOPE_ON; + if (type & XM_ENVELOPE_LOOP) instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON; +#if 1 + if (type & XM_ENVELOPE_SUSTAIN) instrument->volume_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP; +#else // This is now handled in itrender.c + /* let's avoid fading out when reaching the last envelope node */ + if (!(type & XM_ENVELOPE_LOOP)) { + instrument->volume_envelope.loop_start = instrument->volume_envelope.n_nodes-1; + instrument->volume_envelope.loop_end = instrument->volume_envelope.n_nodes-1; + } + instrument->volume_envelope.flags |= IT_ENVELOPE_LOOP_ON; +#endif + + type = dumbfile_getc(f); + instrument->pan_envelope.flags = 0; + if ((type & XM_ENVELOPE_ON) && instrument->pan_envelope.n_nodes) + instrument->pan_envelope.flags |= IT_ENVELOPE_ON; + if (type & XM_ENVELOPE_LOOP) instrument->pan_envelope.flags |= IT_ENVELOPE_LOOP_ON; // should this be here? + if (type & XM_ENVELOPE_SUSTAIN) instrument->pan_envelope.flags |= IT_ENVELOPE_SUSTAIN_LOOP; + + if (it_xm_make_envelope(&instrument->volume_envelope, vol_points, 0) != 0) { + TRACE("XM error: volume envelope\n"); + if (instrument->volume_envelope.flags & IT_ENVELOPE_ON) return -1; + } + + if (it_xm_make_envelope(&instrument->pan_envelope, pan_points, -32) != 0) { + TRACE("XM error: pan envelope\n"); + if (instrument->pan_envelope.flags & IT_ENVELOPE_ON) return -1; + } + + instrument->pitch_envelope.flags = 0; + + extra->vibrato_type = dumbfile_getc(f); + extra->vibrato_sweep = dumbfile_getc(f); + extra->vibrato_depth = dumbfile_getc(f); + extra->vibrato_speed = dumbfile_getc(f); + + if (dumbfile_error(f) || extra->vibrato_type > 4) // XXX + return -1; + + /** WARNING: lossy approximation */ + instrument->fadeout = (dumbfile_igetw(f)*128 + 64)/0xFFF; + + dumbfile_skip(f, 2); /* reserved */ + + bytes_read += 4 + 96 + 48 + 48 + 14*1 + 2 + 2; + } else + for (i = 0; i < 96; i++) + instrument->map_sample[i] = 0; + + if (dumbfile_skip(f, size - bytes_read)) + return -1; + + instrument->new_note_action = NNA_NOTE_CUT; + instrument->dup_check_type = DCT_OFF; + instrument->dup_check_action = DCA_NOTE_CUT; + instrument->pp_separation = 0; + instrument->pp_centre = 60; /* C-5 */ + instrument->global_volume = 128; + instrument->default_pan = 32; + instrument->random_volume = 0; + instrument->random_pan = 0; + instrument->filter_cutoff = 0; + instrument->filter_resonance = 0; + + return 0; +} + + + +/* I (entheh) have two XM files saved by a very naughty program. After a + * 16-bit sample, it saved a rogue byte. The length of the sample was indeed + * an odd number, incremented to include the rogue byte. + * + * In this function we are converting sample lengths and loop points so they + * are measured in samples. This means we forget about the extra bytes, and + * they don't get skipped. So we fail trying to read the next instrument. + * + * To get around this, this function returns the number of rogue bytes that + * won't be accounted for by reading sample->length samples. It returns a + * negative number on failure. + */ +static int it_xm_read_sample_header(IT_SAMPLE *sample, DUMBFILE *f) +{ + int type; + int relative_note_number; /* relative to C4 */ + int finetune; + int roguebytes; + int roguebytesmask; + int reserved; + + sample->length = dumbfile_igetl(f); + sample->loop_start = dumbfile_igetl(f); + sample->loop_end = sample->loop_start + dumbfile_igetl(f); + sample->global_volume = 64; + sample->default_volume = dumbfile_getc(f); + finetune = (signed char)dumbfile_getc(f); /* -128..127 <=> -1 semitone .. +127/128 of a semitone */ + type = dumbfile_getc(f); + sample->default_pan = dumbfile_getc(f); /* 0-255 */ + relative_note_number = (signed char)dumbfile_getc(f); + + reserved = dumbfile_getc(f); + + dumbfile_getnc(sample->name, 22, f); + sample->name[22] = 0; + + sample->filename[0] = 0; + + if (dumbfile_error(f)) + return -1; + + sample->C5_speed = (long)(16726.0*pow(DUMB_SEMITONE_BASE, relative_note_number) /**pow(DUMB_PITCH_BASE, )*/ ); + sample->finetune = finetune*2; + + sample->flags = IT_SAMPLE_EXISTS; + + if (reserved == 0xAD && + (!(type & (XM_SAMPLE_16BIT | XM_SAMPLE_STEREO)))) + { + /* F U Olivier Lapicque */ + roguebytes = 4; + roguebytesmask = 4 << 2; + } + else + { + roguebytes = (int)sample->length; + roguebytesmask = 3; + } + + if (type & XM_SAMPLE_16BIT) { + sample->flags |= IT_SAMPLE_16BIT; + sample->length >>= 1; + sample->loop_start >>= 1; + sample->loop_end >>= 1; + } else + roguebytesmask >>= 1; + + if (type & XM_SAMPLE_STEREO) { + sample->flags |= IT_SAMPLE_STEREO; + sample->length >>= 1; + sample->loop_start >>= 1; + sample->loop_end >>= 1; + } else + roguebytesmask >>= 1; + + roguebytes &= roguebytesmask; + + if ((unsigned int)sample->loop_start < (unsigned int)sample->loop_end) { + if (type & XM_SAMPLE_FORWARD_LOOP) sample->flags |= IT_SAMPLE_LOOP; + if (type & XM_SAMPLE_PINGPONG_LOOP) sample->flags |= IT_SAMPLE_LOOP | IT_SAMPLE_PINGPONG_LOOP; + } + + if (sample->length <= 0) + sample->flags &= ~IT_SAMPLE_EXISTS; + else if ((unsigned int)sample->loop_end > (unsigned int)sample->length) + sample->flags &= ~IT_SAMPLE_LOOP; + else if ((unsigned int)sample->loop_start >= (unsigned int)sample->loop_end) + sample->flags &= ~IT_SAMPLE_LOOP; + + return roguebytes; +} + + + +static int it_xm_read_sample_data(IT_SAMPLE *sample, unsigned char roguebytes, DUMBFILE *f) +{ + int old; + long i; + long truncated_size; + int n_channels; + long datasize; + + if (!(sample->flags & IT_SAMPLE_EXISTS)) + return dumbfile_skip(f, roguebytes); + + /* let's get rid of the sample data coming after the end of the loop */ + if ((sample->flags & IT_SAMPLE_LOOP) && sample->loop_end < sample->length && roguebytes != 4) { + truncated_size = sample->length - sample->loop_end; + sample->length = sample->loop_end; + } else { + truncated_size = 0; + } + + n_channels = sample->flags & IT_SAMPLE_STEREO ? 2 : 1; + datasize = sample->length * n_channels; + + sample->data = malloc(datasize * (sample->flags & IT_SAMPLE_16BIT ? 2 : 1)); + if (!sample->data) + return -1; + + if (roguebytes == 4) + { + if (_dumb_it_read_sample_data_adpcm4(sample, f) < 0) + return -1; + roguebytes = 0; + } + else + { + /* sample data is stored as signed delta values */ + old = 0; + if (sample->flags & IT_SAMPLE_16BIT) + for (i = 0; i < sample->length; i++) + ((short *)sample->data)[i*n_channels] = old += dumbfile_igetw(f); + else + for (i = 0; i < sample->length; i++) + ((signed char *)sample->data)[i*n_channels] = old += dumbfile_getc(f); + } + + /* skip truncated data */ + dumbfile_skip(f, (sample->flags & IT_SAMPLE_16BIT) ? (2*truncated_size) : (truncated_size)); + + if (sample->flags & IT_SAMPLE_STEREO) { + old = 0; + if (sample->flags & IT_SAMPLE_16BIT) + for (i = 1; i < datasize; i += 2) + ((short *)sample->data)[i] = old += dumbfile_igetw(f); + else + for (i = 1; i < datasize; i += 2) + ((signed char *)sample->data)[i] = old += dumbfile_getc(f); + + /* skip truncated data */ + dumbfile_skip(f, (sample->flags & IT_SAMPLE_16BIT) ? (2*truncated_size) : (truncated_size)); + } + + dumbfile_skip(f, roguebytes); + + if (dumbfile_error(f)) + return -1; + + return 0; +} + + + +/* "Real programmers don't document. If it was hard to write, + * it should be hard to understand." + * + * (Never trust the documentation provided with a tracker. + * Real files are the only truth...) + */ +static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version) +{ + DUMB_IT_SIGDATA *sigdata; + char id_text[18]; + + int header_size; + int flags; + int n_channels; + int total_samples; + int i, j; + + /* check ID text */ + if (dumbfile_getnc(id_text, 17, f) < 17) + return NULL; + id_text[17] = 0; + if (strcmp(id_text, "Extended Module: ") != 0) { + TRACE("XM error: Not an Extended Module\n"); + return NULL; + } + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) + return NULL; + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) + return NULL; + + /* song name */ + if (dumbfile_getnc(sigdata->name, 20, f) < 20) { + free(sigdata); + return NULL; + } + sigdata->name[20] = 0; + + if (dumbfile_getc(f) != 0x1A) { + TRACE("XM error: 0x1A not found\n"); + free(sigdata); + return NULL; + } + + /* tracker name */ + if (dumbfile_skip(f, 20)) { + free(sigdata); + return NULL; + } + + /* version number */ + * version = dumbfile_igetw(f); + if (* version > 0x0104 || * version < 0x0102) { + TRACE("XM error: wrong format version\n"); + free(sigdata); + return NULL; + } + + /* + ------------------ + --- Header --- + ------------------ + */ + + /* header size */ + header_size = dumbfile_igetl(f); + if (header_size < (4 + 2*8 + 1) || header_size > 0x114) { + TRACE("XM error: unexpected header size\n"); + free(sigdata); + return NULL; + } + + sigdata->song_message = NULL; + sigdata->order = NULL; + sigdata->instrument = NULL; + sigdata->sample = NULL; + sigdata->pattern = NULL; + sigdata->midi = NULL; + sigdata->checkpoint = NULL; + + sigdata->n_samples = 0; + sigdata->n_orders = dumbfile_igetw(f); + sigdata->restart_position = dumbfile_igetw(f); + n_channels = dumbfile_igetw(f); /* max 32 but we'll be lenient */ + sigdata->n_pchannels = n_channels; + sigdata->n_patterns = dumbfile_igetw(f); + sigdata->n_instruments = dumbfile_igetw(f); /* max 128 */ /* XXX upped to 256 */ + flags = dumbfile_igetw(f); + sigdata->speed = dumbfile_igetw(f); + if (sigdata->speed == 0) sigdata->speed = 6; // Should we? What about tempo? + sigdata->tempo = dumbfile_igetw(f); + + /* sanity checks */ + // XXX + i = header_size - 4 - 2 * 8; /* Maximum number of orders expected */ + if (dumbfile_error(f) || sigdata->n_orders <= 0 || sigdata->n_orders > i || sigdata->n_patterns > 256 || sigdata->n_instruments > 256 || n_channels > DUMB_IT_N_CHANNELS) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + //if (sigdata->restart_position >= sigdata->n_orders) + //sigdata->restart_position = 0; + + /* order table */ + sigdata->order = malloc(sigdata->n_orders*sizeof(*sigdata->order)); + if (!sigdata->order) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + dumbfile_getnc(sigdata->order, sigdata->n_orders, f); + dumbfile_skip(f, i - sigdata->n_orders); + + if (dumbfile_error(f)) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + if ( * version > 0x103 ) { + /* + -------------------- + --- Patterns --- + -------------------- + */ + + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (i = 0; i < sigdata->n_patterns; i++) + sigdata->pattern[i].entry = NULL; + + { + unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */ + if (!buffer) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (i = 0; i < sigdata->n_patterns; i++) { + if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) { + free(buffer); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + free(buffer); + } + + /* + ----------------------------------- + --- Instruments and Samples --- + ----------------------------------- + */ + + sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument)); + if (!sigdata->instrument) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + /* With XM, samples are not global, they're part of an instrument. In a + * file, each instrument is stored with its samples. Because of this, I + * don't know how to find how many samples are present in the file. Thus + * I have to do n_instruments reallocation on sigdata->sample. + * Looking at FT2, it doesn't seem possible to have more than 16 samples + * per instrument (even though n_samples is stored as 2 bytes). So maybe + * we could allocate a 128*16 array of samples, and shrink it back to the + * correct size when we know it? + * Alternatively, I could allocate samples by blocks of N (still O(n)), + * or double the number of allocated samples when I need more (O(log n)). + */ + total_samples = 0; + sigdata->sample = NULL; + + for (i = 0; i < sigdata->n_instruments; i++) { + XM_INSTRUMENT_EXTRA extra; + + if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) { + // XXX + if ( ! i ) + { + TRACE("XM error: instrument %d\n", i+1); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + else + { + sigdata->n_instruments = i; + break; + } + } + + if (extra.n_samples) { + unsigned char roguebytes[XM_MAX_SAMPLES_PER_INSTRUMENT]; + + /* adjust instrument sample map (make indices absolute) */ + for (j = 0; j < 96; j++) + sigdata->instrument[i].map_sample[j] += total_samples; + + sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples)); + if (!sigdata->sample) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (j = total_samples; j < total_samples+extra.n_samples; j++) + sigdata->sample[j].data = NULL; + + /* read instrument's samples */ + for (j = 0; j < extra.n_samples; j++) { + IT_SAMPLE *sample = &sigdata->sample[total_samples+j]; + int b = it_xm_read_sample_header(sample, f); + if (b < 0) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + roguebytes[j] = b; + // Any reason why these can't be set inside it_xm_read_sample_header()? + sample->vibrato_speed = extra.vibrato_speed; + sample->vibrato_depth = extra.vibrato_depth; + sample->vibrato_rate = extra.vibrato_sweep; + /* Rate and sweep don't match, but the difference is + * accounted for in itrender.c. + */ + sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type]; + sample->max_resampling_quality = -1; + } + for (j = 0; j < extra.n_samples; j++) { + if (it_xm_read_sample_data(&sigdata->sample[total_samples+j], roguebytes[j], f) != 0) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + total_samples += extra.n_samples; + } + } + + sigdata->n_samples = total_samples; + } else { + // ahboy! old layout! + // first instruments and sample headers, then patterns, then sample data! + + /* + ----------------------------------- + --- Instruments and Samples --- + ----------------------------------- + */ + + unsigned char * roguebytes = malloc( sigdata->n_instruments * XM_MAX_SAMPLES_PER_INSTRUMENT ); + if (!roguebytes) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument)); + if (!sigdata->instrument) { + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + + total_samples = 0; + sigdata->sample = NULL; + + for (i = 0; i < sigdata->n_instruments; i++) { + XM_INSTRUMENT_EXTRA extra; + + if (it_xm_read_instrument(&sigdata->instrument[i], &extra, f) < 0) { + TRACE("XM error: instrument %d\n", i+1); + free(roguebytes); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (j = total_samples; j < total_samples+extra.n_samples; j++) + sigdata->sample[j].data = NULL; + + if (extra.n_samples) { + /* adjust instrument sample map (make indices absolute) */ + for (j = 0; j < 96; j++) + sigdata->instrument[i].map_sample[j] += total_samples; + + sigdata->sample = safe_realloc(sigdata->sample, sizeof(*sigdata->sample)*(total_samples+extra.n_samples)); + if (!sigdata->sample) { + free(roguebytes); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (j = total_samples; j < total_samples+extra.n_samples; j++) + sigdata->sample[j].data = NULL; + + /* read instrument's samples */ + for (j = 0; j < extra.n_samples; j++) { + IT_SAMPLE *sample = &sigdata->sample[total_samples+j]; + int b = it_xm_read_sample_header(sample, f); + if (b < 0) { + free(roguebytes); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + roguebytes[total_samples+j] = b; + // Any reason why these can't be set inside it_xm_read_sample_header()? + sample->vibrato_speed = extra.vibrato_speed; + sample->vibrato_depth = extra.vibrato_depth; + sample->vibrato_rate = extra.vibrato_sweep; + /* Rate and sweep don't match, but the difference is + * accounted for in itrender.c. + */ + sample->vibrato_waveform = xm_convert_vibrato[extra.vibrato_type]; + sample->max_resampling_quality = -1; + } + total_samples += extra.n_samples; + } + } + + sigdata->n_samples = total_samples; + + /* + -------------------- + --- Patterns --- + -------------------- + */ + + sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); + if (!sigdata->pattern) { + free(roguebytes); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (i = 0; i < sigdata->n_patterns; i++) + sigdata->pattern[i].entry = NULL; + + { + unsigned char *buffer = malloc(1280 * n_channels); /* 256 rows * 5 bytes */ + if (!buffer) { + free(roguebytes); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + for (i = 0; i < sigdata->n_patterns; i++) { + if (it_xm_read_pattern(&sigdata->pattern[i], f, n_channels, buffer, * version) != 0) { + free(buffer); + free(roguebytes); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + free(buffer); + } + + // and now we load the sample data + for (j = 0; j < total_samples; j++) { + if (it_xm_read_sample_data(&sigdata->sample[j], roguebytes[j], f) != 0) { + free(roguebytes); + _dumb_it_unload_sigdata(sigdata); + return NULL; + } + } + + free(roguebytes); + } + + + sigdata->flags = IT_WAS_AN_XM | IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_STEREO | IT_USE_INSTRUMENTS; + // Are we OK with IT_COMPATIBLE_GXX off? + // + // When specifying note + instr + tone portamento, and an old note is still playing (even after note off): + // - If Compatible Gxx is on, the new note will be triggered only if the instrument _changes_. + // - If Compatible Gxx is off, the new note will always be triggered, provided the instrument is specified. + // - FT2 seems to do the latter (unconfirmed). + + // Err, wait. XM playback has its own code. The change made to the IT + // playbackc code didn't affect XM playback. Forget this then. There's + // still a bug in XM playback though, and it'll need some investigation... + // tomorrow... + + // UPDATE: IT_COMPATIBLE_GXX is required to be on, so that tone porta has + // separate memory from portamento. + + if (flags & XM_LINEAR_FREQUENCY) + sigdata->flags |= IT_LINEAR_SLIDES; + + sigdata->global_volume = 128; + sigdata->mixing_volume = 48; + sigdata->pan_separation = 128; + + memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS); + memset(sigdata->channel_pan, 32, DUMB_IT_N_CHANNELS); + + _dumb_it_fix_invalid_orders(sigdata); + + return sigdata; +} + + + +#if 0 // no fucking way, dude! + +/* The length returned is the time required to play from the beginning of the + * file to the last row of the last order (which is when the player will + * loop). Depending on the song, the sound might stop sooner. + * Due to fixed point roundoffs, I think this is only reliable to the second. + * Full precision could be achieved by using a double during the computation, + * or maybe a LONG_LONG. + */ +long it_compute_length(const DUMB_IT_SIGDATA *sigdata) +{ + IT_PATTERN *pattern; + int tempo, speed; + int loop_start[IT_N_CHANNELS]; + char loop_count[IT_N_CHANNELS]; + int order, entry; + int row_first_entry = 0; + int jump, jump_dest; + int delay, fine_delay; + int i; + long t; + + if (!sigdata) + return 0; + + tempo = sigdata->tempo; + speed = sigdata->speed; + order = entry = 0; + jump = jump_dest = 0; + t = 0; + + /* for each PATTERN */ + for (order = 0; order < sigdata->n_orders; order++) { + + if (sigdata->order[order] == IT_ORDER_END) break; + if (sigdata->order[order] == IT_ORDER_SKIP) continue; + + for (i = 0; i < IT_N_CHANNELS; i++) + loop_count[i] = -1; + + pattern = &sigdata->pattern[ sigdata->order[order] ]; + entry = 0; + if (jump == IT_BREAK_TO_ROW) { + int row = 0; + while (row < jump_dest) + if (pattern->entry[entry++].channel >= IT_N_CHANNELS) + row++; + } + + /* for each ROW */ + while (entry < pattern->n_entries) { + row_first_entry = entry; + delay = fine_delay = 0; + jump = 0; + + /* for each note NOTE */ + while (entry < pattern->n_entries && pattern->entry[entry].channel < IT_N_CHANNELS) { + int value = pattern->entry[entry].effectvalue; + int channel = pattern->entry[entry].channel; + + switch (pattern->entry[entry].effect) { + + case IT_SET_SPEED: speed = value; break; + + case IT_JUMP_TO_ORDER: + if (value <= order) /* infinite loop */ + return 0; + jump = IT_JUMP_TO_ORDER; + jump_dest = value; + break; + + case IT_BREAK_TO_ROW: + jump = IT_BREAK_TO_ROW; + jump_dest = value; + break; + + case IT_S: + switch (HIGH(value)) { + case IT_S_PATTERN_DELAY: delay = LOW(value); break; + case IT_S_FINE_PATTERN_DELAY: fine_delay = LOW(value); break; + case IT_S_PATTERN_LOOP: + if (LOW(value) == 0) { + loop_start[channel] = row_first_entry; + } else { + if (loop_count[channel] == -1) + loop_count[channel] = LOW(value); + + if (loop_count[channel]) { + jump = IT_S_PATTERN_LOOP; + jump_dest = loop_start[channel]; + } + loop_count[channel]--; + } + break; + } + break; + + case IT_SET_SONG_TEMPO: + switch (HIGH(value)) { /* slides happen every non-row frames */ + case 0: tempo = tempo - LOW(value)*(speed-1); break; + case 1: tempo = tempo + LOW(value)*(speed-1); break; + default: tempo = value; + } + tempo = MID(32, tempo, 255); + break; + } + + entry++; + } + + /* end of ROW */ + entry++; + t += TICK_TIME_DIVIDEND * (speed*(1+delay) + fine_delay) / tempo; + + if (jump == IT_JUMP_TO_ORDER) { + order = jump_dest - 1; + break; + } else if (jump == IT_BREAK_TO_ROW) + break; + else if (jump == IT_S_PATTERN_LOOP) + entry = jump_dest - 1; + } + + /* end of PATTERN */ + } + + return t; +} + +#endif /* 0 */ + + +static char hexdigit(int in) +{ + if (in < 10) return in + '0'; + else return in + 'A' - 10; +} + +DUH *dumb_read_xm_quick(DUMBFILE *f) +{ + sigdata_t *sigdata; + int ver; + + DUH_SIGTYPE_DESC *descptr = &_dumb_sigtype_it; + + sigdata = it_xm_load_sigdata(f, &ver); + + if (!sigdata) + return NULL; + + { + char version[16]; + const char *tag[2][2]; + tag[0][0] = "TITLE"; + tag[0][1] = ((DUMB_IT_SIGDATA *)sigdata)->name; + tag[1][0] = "FORMAT"; + version[0] = 'X'; + version[1] = 'M'; + version[2] = ' '; + version[3] = 'v'; + version[4] = hexdigit( ( ver >> 8 ) & 15 ); + version[5] = '.'; + version[6] = hexdigit( ( ver >> 4 ) & 15 ); + version[7] = hexdigit( ver & 15 ); + version[8] = 0; + tag[1][1] = ( const char * ) & version; + return make_duh(-1, 2, (const char *const (*)[2])tag, 1, &descptr, &sigdata); + } +} diff --git a/plugins/dumb/dumb-kode54/src/it/readxm2.c b/plugins/dumb/dumb-kode54/src/it/readxm2.c index c79f753f..b678bd2d 100644 --- a/plugins/dumb/dumb-kode54/src/it/readxm2.c +++ b/plugins/dumb/dumb-kode54/src/it/readxm2.c @@ -1,29 +1,29 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * readxm2.c - Function to read a Fast Tracker II / / \ \
- * module from an open file and do an | < / \_
- * initial run-through. | \/ /\ /
- * \_ / > /
- * Split off from readxm.c by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-#include "dumb.h"
-
-
-
-DUH *dumb_read_xm(DUMBFILE *f)
-{
- DUH *duh = dumb_read_xm_quick(f);
- dumb_it_do_initial_runthrough(duh);
- return duh;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * readxm2.c - Function to read a Fast Tracker II / / \ \ + * module from an open file and do an | < / \_ + * initial run-through. | \/ /\ / + * \_ / > / + * Split off from readxm.c by entheh. | \ / / + * | ' / + * \__/ + */ + +#include "dumb.h" + + + +DUH *dumb_read_xm(DUMBFILE *f) +{ + DUH *duh = dumb_read_xm_quick(f); + dumb_it_do_initial_runthrough(duh); + return duh; +} diff --git a/plugins/dumb/dumb-kode54/src/it/xmeffect.c b/plugins/dumb/dumb-kode54/src/it/xmeffect.c index 2187a0b3..143bd804 100644 --- a/plugins/dumb/dumb-kode54/src/it/xmeffect.c +++ b/plugins/dumb/dumb-kode54/src/it/xmeffect.c @@ -1,243 +1,243 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * xmeffect.c - Code for converting MOD/XM / / \ \
- * effects to IT effects. | < / \_
- * | \/ /\ /
- * By Julien Cugniere. Ripped out of readxm.c \_ / > /
- * by entheh. | \ / /
- * | ' /
- * \__/
- */
-
-
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-#include "internal/it.h"
-
-#if 0
-unsigned char **_dumb_malloc2(int w, int h)
-{
- unsigned char **line = malloc(h * sizeof(*line));
- int i;
- if (!line) return NULL;
-
- line[0] = malloc(w * h * sizeof(*line[0]));
- if (!line[0]) {
- free(line);
- return NULL;
- }
-
- for (i = 1; i < h; i++)
- line[i] = line[i-1] + w;
-
- memset(line[0], 0, w*h);
-
- return line;
-}
-
-
-
-void _dumb_free2(unsigned char **line)
-{
- if (line) {
- if (line[0])
- free(line[0]);
- free(line);
- }
-}
-
-
-
-/* Effects having a memory. 2 means that the two parts of the effectvalue
- * should be handled separately.
- */
-static const char xm_has_memory[] = {
-/* 0 1 2 3 4 5 6 7 8 9 A B C D (E) F G H K L P R T (X) */
- 0, 1, 1, 1, 2, 1, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
-
-/* E0 E1 E2 E3 E4 E5 E6 E7 E9 EA EB EC ED EE X1 X2 */
- 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-#endif
-
-
-
-/* Effects marked with 'special' are handled specifically in itrender.c */
-void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry, int mod)
-{
-const int log = 0;
-
- if ((!effect && !value) || (effect >= XM_N_EFFECTS))
- return;
-
-if (log) printf("%c%02X", (effect<10)?('0'+effect):('A'+effect-10), value);
-
- /* Linearisation of the effect number... */
- if (effect == XM_E) {
- effect = EBASE + HIGH(value);
- value = LOW(value);
- } else if (effect == XM_X) {
- effect = XBASE + HIGH(value);
- value = LOW(value);
- }
-
-if (log) printf(" - %2d %02X", effect, value);
-
-#if 0 // This should be handled in itrender.c!
- /* update effect memory */
- switch (xm_has_memory[effect]) {
- case 1:
- if (!value)
- value = memory[entry->channel][effect];
- else
- memory[entry->channel][effect] = value;
- break;
-
- case 2:
- if (!HIGH(value))
- SET_HIGH(value, HIGH(memory[entry->channel][effect]));
- else
- SET_HIGH(memory[entry->channel][effect], HIGH(value));
-
- if (!LOW(value))
- SET_LOW(value, LOW(memory[entry->channel][effect]));
- else
- SET_LOW(memory[entry->channel][effect], LOW(value));
- break;
- }
-#endif
-
- /* convert effect */
- entry->mask |= IT_ENTRY_EFFECT;
- switch (effect) {
-
- case XM_APPREGIO: effect = IT_ARPEGGIO; break;
- case XM_VIBRATO: effect = IT_VIBRATO; break;
- case XM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break;
- case XM_TREMOLO: effect = IT_TREMOLO; break;
- case XM_SET_PANNING: effect = IT_SET_PANNING; break;
- case XM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break;
- case XM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break;
- case XM_MULTI_RETRIG: effect = IT_RETRIGGER_NOTE; break;
- case XM_TREMOR: effect = IT_TREMOR; break;
- case XM_PORTAMENTO_UP: effect = IT_XM_PORTAMENTO_UP; break;
- case XM_PORTAMENTO_DOWN: effect = IT_XM_PORTAMENTO_DOWN; break;
- case XM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break; /* special */
- case XM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break; /* special */
- case XM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break; /* special */
-
- case XM_PATTERN_BREAK:
- effect = IT_BREAK_TO_ROW;
- value = BCD_TO_NORMAL(value);
- if (value > 63) value = 0; /* FT2, maybe ProTracker? */
- break;
-
- case XM_VOLUME_SLIDE: /* special */
- effect = IT_VOLUME_SLIDE;
- value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
- break;
-
- case XM_PANNING_SLIDE:
- effect = IT_PANNING_SLIDE;
- //value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
- value = HIGH(value) ? EFFECT_VALUE(0, HIGH(value)) : EFFECT_VALUE(LOW(value), 0);
- break;
-
- case XM_GLOBAL_VOLUME_SLIDE: /* special */
- effect = IT_GLOBAL_VOLUME_SLIDE;
- value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value));
- break;
-
- case XM_SET_TEMPO_BPM:
- if (mod) effect = (value <= 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
- else effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO);
- break;
-
- case XM_SET_GLOBAL_VOLUME:
- effect = IT_SET_GLOBAL_VOLUME;
- value *= 2;
- break;
-
- case XM_KEY_OFF:
- effect = IT_XM_KEY_OFF;
- break;
-
- case XM_SET_ENVELOPE_POSITION:
- effect = IT_XM_SET_ENVELOPE_POSITION;
- break;
-
- case EBASE+XM_E_SET_FILTER: effect = SBASE+IT_S_SET_FILTER; break;
- case EBASE+XM_E_SET_GLISSANDO_CONTROL: effect = SBASE+IT_S_SET_GLISSANDO_CONTROL; break; /** TODO */
- case EBASE+XM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break;
- case EBASE+XM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break;
- case EBASE+XM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break;
- case EBASE+XM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break;
- case EBASE+XM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break;
- case EBASE+XM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break;
- case EBASE+XM_E_FINE_VOLSLIDE_UP: effect = IT_XM_FINE_VOLSLIDE_UP; break;
- case EBASE+XM_E_FINE_VOLSLIDE_DOWN: effect = IT_XM_FINE_VOLSLIDE_DOWN; break;
-
- case EBASE + XM_E_FINE_PORTA_UP:
- effect = IT_PORTAMENTO_UP;
- value = EFFECT_VALUE(0xF, value);
- break;
-
- case EBASE + XM_E_FINE_PORTA_DOWN:
- effect = IT_PORTAMENTO_DOWN;
- value = EFFECT_VALUE(0xF, value);
- break;
-
- case EBASE + XM_E_RETRIG_NOTE:
- effect = IT_XM_RETRIGGER_NOTE;
- value = EFFECT_VALUE(0, value);
- break;
-
- case EBASE + XM_E_SET_VIBRATO_CONTROL:
- effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM;
- value &= ~4;
- break;
-
- case EBASE + XM_E_SET_TREMOLO_CONTROL:
- effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM;
- value &= ~4;
- break;
-
- case XBASE + XM_X_EXTRAFINE_PORTA_UP:
- effect = IT_PORTAMENTO_UP;
- value = EFFECT_VALUE(0xE, value);
- break;
-
- case XBASE + XM_X_EXTRAFINE_PORTA_DOWN:
- effect = IT_PORTAMENTO_DOWN;
- value = EFFECT_VALUE(0xE, value);
- break;
-
- default:
- /* user effect (often used in demos for synchronisation) */
- entry->mask &= ~IT_ENTRY_EFFECT;
- }
-
-if (log) printf(" - %2d %02X", effect, value);
-
- /* Inverse linearisation... */
- if (effect >= SBASE && effect < SBASE+16) {
- value = EFFECT_VALUE(effect-SBASE, value);
- effect = IT_S;
- }
-
-if (log) printf(" - %c%02X\n", 'A'+effect-1, value);
-
- entry->effect = effect;
- entry->effectvalue = value;
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * xmeffect.c - Code for converting MOD/XM / / \ \ + * effects to IT effects. | < / \_ + * | \/ /\ / + * By Julien Cugniere. Ripped out of readxm.c \_ / > / + * by entheh. | \ / / + * | ' / + * \__/ + */ + + + +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" +#include "internal/it.h" + +#if 0 +unsigned char **_dumb_malloc2(int w, int h) +{ + unsigned char **line = malloc(h * sizeof(*line)); + int i; + if (!line) return NULL; + + line[0] = malloc(w * h * sizeof(*line[0])); + if (!line[0]) { + free(line); + return NULL; + } + + for (i = 1; i < h; i++) + line[i] = line[i-1] + w; + + memset(line[0], 0, w*h); + + return line; +} + + + +void _dumb_free2(unsigned char **line) +{ + if (line) { + if (line[0]) + free(line[0]); + free(line); + } +} + + + +/* Effects having a memory. 2 means that the two parts of the effectvalue + * should be handled separately. + */ +static const char xm_has_memory[] = { +/* 0 1 2 3 4 5 6 7 8 9 A B C D (E) F G H K L P R T (X) */ + 0, 1, 1, 1, 2, 1, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + +/* E0 E1 E2 E3 E4 E5 E6 E7 E9 EA EB EC ED EE X1 X2 */ + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +#endif + + + +/* Effects marked with 'special' are handled specifically in itrender.c */ +void _dumb_it_xm_convert_effect(int effect, int value, IT_ENTRY *entry, int mod) +{ +const int log = 0; + + if ((!effect && !value) || (effect >= XM_N_EFFECTS)) + return; + +if (log) printf("%c%02X", (effect<10)?('0'+effect):('A'+effect-10), value); + + /* Linearisation of the effect number... */ + if (effect == XM_E) { + effect = EBASE + HIGH(value); + value = LOW(value); + } else if (effect == XM_X) { + effect = XBASE + HIGH(value); + value = LOW(value); + } + +if (log) printf(" - %2d %02X", effect, value); + +#if 0 // This should be handled in itrender.c! + /* update effect memory */ + switch (xm_has_memory[effect]) { + case 1: + if (!value) + value = memory[entry->channel][effect]; + else + memory[entry->channel][effect] = value; + break; + + case 2: + if (!HIGH(value)) + SET_HIGH(value, HIGH(memory[entry->channel][effect])); + else + SET_HIGH(memory[entry->channel][effect], HIGH(value)); + + if (!LOW(value)) + SET_LOW(value, LOW(memory[entry->channel][effect])); + else + SET_LOW(memory[entry->channel][effect], LOW(value)); + break; + } +#endif + + /* convert effect */ + entry->mask |= IT_ENTRY_EFFECT; + switch (effect) { + + case XM_APPREGIO: effect = IT_ARPEGGIO; break; + case XM_VIBRATO: effect = IT_VIBRATO; break; + case XM_TONE_PORTAMENTO: effect = IT_TONE_PORTAMENTO; break; + case XM_TREMOLO: effect = IT_TREMOLO; break; + case XM_SET_PANNING: effect = IT_SET_PANNING; break; + case XM_SAMPLE_OFFSET: effect = IT_SET_SAMPLE_OFFSET; break; + case XM_POSITION_JUMP: effect = IT_JUMP_TO_ORDER; break; + case XM_MULTI_RETRIG: effect = IT_RETRIGGER_NOTE; break; + case XM_TREMOR: effect = IT_TREMOR; break; + case XM_PORTAMENTO_UP: effect = IT_XM_PORTAMENTO_UP; break; + case XM_PORTAMENTO_DOWN: effect = IT_XM_PORTAMENTO_DOWN; break; + case XM_SET_CHANNEL_VOLUME: effect = IT_SET_CHANNEL_VOLUME; break; /* special */ + case XM_VOLSLIDE_TONEPORTA: effect = IT_VOLSLIDE_TONEPORTA; break; /* special */ + case XM_VOLSLIDE_VIBRATO: effect = IT_VOLSLIDE_VIBRATO; break; /* special */ + + case XM_PATTERN_BREAK: + effect = IT_BREAK_TO_ROW; + value = BCD_TO_NORMAL(value); + if (value > 63) value = 0; /* FT2, maybe ProTracker? */ + break; + + case XM_VOLUME_SLIDE: /* special */ + effect = IT_VOLUME_SLIDE; + value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value)); + break; + + case XM_PANNING_SLIDE: + effect = IT_PANNING_SLIDE; + //value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value)); + value = HIGH(value) ? EFFECT_VALUE(0, HIGH(value)) : EFFECT_VALUE(LOW(value), 0); + break; + + case XM_GLOBAL_VOLUME_SLIDE: /* special */ + effect = IT_GLOBAL_VOLUME_SLIDE; + value = HIGH(value) ? EFFECT_VALUE(HIGH(value), 0) : EFFECT_VALUE(0, LOW(value)); + break; + + case XM_SET_TEMPO_BPM: + if (mod) effect = (value <= 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO); + else effect = (value < 0x20) ? (IT_SET_SPEED) : (IT_SET_SONG_TEMPO); + break; + + case XM_SET_GLOBAL_VOLUME: + effect = IT_SET_GLOBAL_VOLUME; + value *= 2; + break; + + case XM_KEY_OFF: + effect = IT_XM_KEY_OFF; + break; + + case XM_SET_ENVELOPE_POSITION: + effect = IT_XM_SET_ENVELOPE_POSITION; + break; + + case EBASE+XM_E_SET_FILTER: effect = SBASE+IT_S_SET_FILTER; break; + case EBASE+XM_E_SET_GLISSANDO_CONTROL: effect = SBASE+IT_S_SET_GLISSANDO_CONTROL; break; /** TODO */ + case EBASE+XM_E_SET_FINETUNE: effect = SBASE+IT_S_FINETUNE; break; + case EBASE+XM_E_SET_LOOP: effect = SBASE+IT_S_PATTERN_LOOP; break; + case EBASE+XM_E_NOTE_CUT: effect = SBASE+IT_S_DELAYED_NOTE_CUT; break; + case EBASE+XM_E_NOTE_DELAY: effect = SBASE+IT_S_NOTE_DELAY; break; + case EBASE+XM_E_PATTERN_DELAY: effect = SBASE+IT_S_PATTERN_DELAY; break; + case EBASE+XM_E_SET_PANNING: effect = SBASE+IT_S_SET_PAN; break; + case EBASE+XM_E_FINE_VOLSLIDE_UP: effect = IT_XM_FINE_VOLSLIDE_UP; break; + case EBASE+XM_E_FINE_VOLSLIDE_DOWN: effect = IT_XM_FINE_VOLSLIDE_DOWN; break; + + case EBASE + XM_E_FINE_PORTA_UP: + effect = IT_PORTAMENTO_UP; + value = EFFECT_VALUE(0xF, value); + break; + + case EBASE + XM_E_FINE_PORTA_DOWN: + effect = IT_PORTAMENTO_DOWN; + value = EFFECT_VALUE(0xF, value); + break; + + case EBASE + XM_E_RETRIG_NOTE: + effect = IT_XM_RETRIGGER_NOTE; + value = EFFECT_VALUE(0, value); + break; + + case EBASE + XM_E_SET_VIBRATO_CONTROL: + effect = SBASE+IT_S_SET_VIBRATO_WAVEFORM; + value &= ~4; + break; + + case EBASE + XM_E_SET_TREMOLO_CONTROL: + effect = SBASE+IT_S_SET_TREMOLO_WAVEFORM; + value &= ~4; + break; + + case XBASE + XM_X_EXTRAFINE_PORTA_UP: + effect = IT_PORTAMENTO_UP; + value = EFFECT_VALUE(0xE, value); + break; + + case XBASE + XM_X_EXTRAFINE_PORTA_DOWN: + effect = IT_PORTAMENTO_DOWN; + value = EFFECT_VALUE(0xE, value); + break; + + default: + /* user effect (often used in demos for synchronisation) */ + entry->mask &= ~IT_ENTRY_EFFECT; + } + +if (log) printf(" - %2d %02X", effect, value); + + /* Inverse linearisation... */ + if (effect >= SBASE && effect < SBASE+16) { + value = EFFECT_VALUE(effect-SBASE, value); + effect = IT_S; + } + +if (log) printf(" - %c%02X\n", 'A'+effect-1, value); + + entry->effect = effect; + entry->effectvalue = value; +} diff --git a/plugins/dumb/dumb-kode54/src/sigtypes/combine.c b/plugins/dumb/dumb-kode54/src/sigtypes/combine.c index 497f085c..842359a1 100644 --- a/plugins/dumb/dumb-kode54/src/sigtypes/combine.c +++ b/plugins/dumb/dumb-kode54/src/sigtypes/combine.c @@ -1,243 +1,243 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * combine.c - The combining (COMB) signal type. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * This takes multiple monaural signals and | \ / /
- * combines them into a single multichannel | ' /
- * signal. It assumes the correct number of \__/
- * channels is passed. An ASSERT() is in place
- * to check the number of channels when you
- * compile with -DDEBUGMODE. As an exception, if one channel is passed the
- * signals are all mixed together.
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-
-
-
-#define SIGTYPE_COMBINING DUMB_ID('C','O','M','B')
-
-
-
-typedef struct COMBINING_SIGNAL
-{
- int n_signals;
- int sig[ZERO_SIZE];
-}
-COMBINING_SIGNAL;
-
-
-
-typedef struct COMBINING_SAMPINFO
-{
- int n_signals;
- int downmix;
- DUH_SIGNAL_SAMPINFO *csampinfo[ZERO_SIZE];
-}
-COMBINING_SAMPINFO;
-
-
-
-static void *combining_load_signal(DUH *duh, DUMBFILE *file)
-{
- COMBINING_SIGNAL *signal;
- int n_signals;
-
- (void)duh;
-
- n_signals = dumbfile_getc(file);
-
- /* No point in combining only one signal! */
- if (dumbfile_error(file) || n_signals <= 1)
- return NULL;
-
- signal = malloc(sizeof(*signal) + n_signals * sizeof(*signal->sig));
- if (!signal)
- return NULL;
-
- signal->n_signals = n_signals;
-
- {
- int n;
- for (n = 0; n < signal->n_signals; n++) {
- signal->sig[n] = dumbfile_igetl(file);
- if (dumbfile_error(file)) {
- free(signal);
- return NULL;
- }
- }
- }
-
- return signal;
-}
-
-
-
-static void *combining_start_samples(DUH *duh, void *signal, int n_channels, long pos)
-{
-#define signal ((COMBINING_SIGNAL *)signal)
-
- COMBINING_SAMPINFO *sampinfo;
-
- sampinfo = malloc(sizeof(*sampinfo) + signal->n_signals * sizeof(*sampinfo->csampinfo));
- if (!sampinfo)
- return NULL;
-
- sampinfo->n_signals = signal->n_signals;
- if (n_channels == 1)
- sampinfo->downmix = 1;
- else if (n_channels == signal->n_signals)
- sampinfo->downmix = 0;
- else {
- TRACE("Combining signal discrepancy: %d signals, %d channels.\n", signal->n_signals, n_channels);
- free(sampinfo);
- return NULL;
- }
-
- {
- int worthwhile = 0;
-
- {
- int n;
- for (n = 0; n < signal->n_signals; n++) {
- sampinfo->csampinfo[n] = duh_signal_start_samples(duh, signal->sig[n], 1, pos);
- if (sampinfo->csampinfo[n])
- worthwhile = 1;
- }
- }
-
- if (!worthwhile) {
- free(sampinfo);
- return NULL;
- }
- }
-
- return sampinfo;
-
-#undef signal
-}
-
-
-
-static long combining_render_samples(
- void *sampinfo,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
-#define sampinfo ((COMBINING_SAMPINFO *)sampinfo)
-
- long max_size;
-
- int n;
-
- if (sampinfo->downmix)
- volume /= sampinfo->n_signals;
-
- max_size = duh_signal_render_samples(sampinfo->csampinfo[0], volume, delta, size, samples);
-
- if (sampinfo->downmix) {
-
- long s;
- long sz;
-
- sample_t *sampbuf = malloc(size * sizeof(sample_t));
-
- if (!sampbuf)
- return 0;
-
- for (n = 1; n < sampinfo->n_signals; n++) {
- sz = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, &sampbuf);
- if (sz > max_size) {
- for (s = max_size; s < sz; s++)
- samples[0][s] = sampbuf[s];
- sz = max_size;
- max_size = s;
- }
- for (s = 0; s < sz; s++)
- samples[0][s] += sampbuf[s];
- }
-
- free(sampbuf);
-
- } else {
-
- long *sz = malloc(size * sizeof(*sz));
- long s;
-
- if (!sz)
- return 0;
-
- sz[0] = max_size;
-
- for (n = 1; n < sampinfo->n_signals; n++) {
- sz[n] = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, samples + n);
- if (sz[n] > max_size)
- max_size = sz[n];
- }
-
- for (n = 0; n < sampinfo->n_signals; n++)
- for (s = sz[n]; s < max_size; s++)
- samples[n][s] = 0;
-
- free(sz);
-
- }
-
- return max_size;
-
-#undef sampinfo
-}
-
-
-
-static void combining_end_samples(void *sampinfo)
-{
-#define sampinfo ((COMBINING_SAMPINFO *)sampinfo)
-
- int n;
-
- for (n = 0; n < sampinfo->n_signals; n++)
- duh_signal_end_samples(sampinfo->csampinfo[n]);
-
- free(sampinfo);
-
-#undef sampinfo
-}
-
-
-
-static void combining_unload_signal(void *signal)
-{
- free(signal);
-}
-
-
-
-static DUH_SIGTYPE_DESC sigtype_combining = {
- SIGTYPE_COMBINING,
- &combining_load_signal,
- &combining_start_samples,
- NULL,
- &combining_render_samples,
- &combining_end_samples,
- &combining_unload_signal
-};
-
-
-void dumb_register_sigtype_combining(void)
-{
- dumb_register_sigtype(&sigtype_combining);
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * combine.c - The combining (COMB) signal type. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * This takes multiple monaural signals and | \ / / + * combines them into a single multichannel | ' / + * signal. It assumes the correct number of \__/ + * channels is passed. An ASSERT() is in place + * to check the number of channels when you + * compile with -DDEBUGMODE. As an exception, if one channel is passed the + * signals are all mixed together. + */ + +#include <stdlib.h> + +#include "dumb.h" + + + +#define SIGTYPE_COMBINING DUMB_ID('C','O','M','B') + + + +typedef struct COMBINING_SIGNAL +{ + int n_signals; + int sig[ZERO_SIZE]; +} +COMBINING_SIGNAL; + + + +typedef struct COMBINING_SAMPINFO +{ + int n_signals; + int downmix; + DUH_SIGNAL_SAMPINFO *csampinfo[ZERO_SIZE]; +} +COMBINING_SAMPINFO; + + + +static void *combining_load_signal(DUH *duh, DUMBFILE *file) +{ + COMBINING_SIGNAL *signal; + int n_signals; + + (void)duh; + + n_signals = dumbfile_getc(file); + + /* No point in combining only one signal! */ + if (dumbfile_error(file) || n_signals <= 1) + return NULL; + + signal = malloc(sizeof(*signal) + n_signals * sizeof(*signal->sig)); + if (!signal) + return NULL; + + signal->n_signals = n_signals; + + { + int n; + for (n = 0; n < signal->n_signals; n++) { + signal->sig[n] = dumbfile_igetl(file); + if (dumbfile_error(file)) { + free(signal); + return NULL; + } + } + } + + return signal; +} + + + +static void *combining_start_samples(DUH *duh, void *signal, int n_channels, long pos) +{ +#define signal ((COMBINING_SIGNAL *)signal) + + COMBINING_SAMPINFO *sampinfo; + + sampinfo = malloc(sizeof(*sampinfo) + signal->n_signals * sizeof(*sampinfo->csampinfo)); + if (!sampinfo) + return NULL; + + sampinfo->n_signals = signal->n_signals; + if (n_channels == 1) + sampinfo->downmix = 1; + else if (n_channels == signal->n_signals) + sampinfo->downmix = 0; + else { + TRACE("Combining signal discrepancy: %d signals, %d channels.\n", signal->n_signals, n_channels); + free(sampinfo); + return NULL; + } + + { + int worthwhile = 0; + + { + int n; + for (n = 0; n < signal->n_signals; n++) { + sampinfo->csampinfo[n] = duh_signal_start_samples(duh, signal->sig[n], 1, pos); + if (sampinfo->csampinfo[n]) + worthwhile = 1; + } + } + + if (!worthwhile) { + free(sampinfo); + return NULL; + } + } + + return sampinfo; + +#undef signal +} + + + +static long combining_render_samples( + void *sampinfo, + float volume, float delta, + long size, sample_t **samples +) +{ +#define sampinfo ((COMBINING_SAMPINFO *)sampinfo) + + long max_size; + + int n; + + if (sampinfo->downmix) + volume /= sampinfo->n_signals; + + max_size = duh_signal_render_samples(sampinfo->csampinfo[0], volume, delta, size, samples); + + if (sampinfo->downmix) { + + long s; + long sz; + + sample_t *sampbuf = malloc(size * sizeof(sample_t)); + + if (!sampbuf) + return 0; + + for (n = 1; n < sampinfo->n_signals; n++) { + sz = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, &sampbuf); + if (sz > max_size) { + for (s = max_size; s < sz; s++) + samples[0][s] = sampbuf[s]; + sz = max_size; + max_size = s; + } + for (s = 0; s < sz; s++) + samples[0][s] += sampbuf[s]; + } + + free(sampbuf); + + } else { + + long *sz = malloc(size * sizeof(*sz)); + long s; + + if (!sz) + return 0; + + sz[0] = max_size; + + for (n = 1; n < sampinfo->n_signals; n++) { + sz[n] = duh_signal_render_samples(sampinfo->csampinfo[n], volume, delta, size, samples + n); + if (sz[n] > max_size) + max_size = sz[n]; + } + + for (n = 0; n < sampinfo->n_signals; n++) + for (s = sz[n]; s < max_size; s++) + samples[n][s] = 0; + + free(sz); + + } + + return max_size; + +#undef sampinfo +} + + + +static void combining_end_samples(void *sampinfo) +{ +#define sampinfo ((COMBINING_SAMPINFO *)sampinfo) + + int n; + + for (n = 0; n < sampinfo->n_signals; n++) + duh_signal_end_samples(sampinfo->csampinfo[n]); + + free(sampinfo); + +#undef sampinfo +} + + + +static void combining_unload_signal(void *signal) +{ + free(signal); +} + + + +static DUH_SIGTYPE_DESC sigtype_combining = { + SIGTYPE_COMBINING, + &combining_load_signal, + &combining_start_samples, + NULL, + &combining_render_samples, + &combining_end_samples, + &combining_unload_signal +}; + + +void dumb_register_sigtype_combining(void) +{ + dumb_register_sigtype(&sigtype_combining); +} diff --git a/plugins/dumb/dumb-kode54/src/sigtypes/sample.c b/plugins/dumb/dumb-kode54/src/sigtypes/sample.c index 4695de91..d810958e 100644 --- a/plugins/dumb/dumb-kode54/src/sigtypes/sample.c +++ b/plugins/dumb/dumb-kode54/src/sigtypes/sample.c @@ -1,340 +1,340 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * sample.c - The sample (SAMP) signal type. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * This only supports monaural samples. For | \ / /
- * multiple channels, use multiple samples and | ' /
- * a combining signal (COMB). \__/
- */
-
-/* NOTE: filters need not be credited yet, as they will be moved elsewhere. */
-/** WARNING don't forget to move these filters somewhere */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-
-
-/** WARNING move these things somewhere useful, for DUH writing - this applies to other signal types too */
-#define SIGTYPE_SAMPLE DUMB_ID('S','A','M','P')
-
-
-
-#define SAMPFLAG_16BIT 1 /* sample in file is 16 bit, rather than 8 bit */
-#define SAMPFLAG_LOOP 2 /* loop indefinitely */
-#define SAMPFLAG_XLOOP 4 /* loop x times; only relevant if LOOP not set */
-#define SAMPFLAG_PINGPONG 8 /* loop back and forth, if LOOP or XLOOP set */
-
-
-/* SAMPPARAM_N_LOOPS: add 'value' iterations to the loop. 'value' is assumed
- * to be positive.
- */
-#define SAMPPARAM_N_LOOPS 0
-
-
-
-typedef struct SAMPLE_SIGDATA
-{
- long size;
- int flags;
- long loop_start;
- long loop_end;
- sample_t *samples;
-}
-SAMPLE_SIGDATA;
-
-
-
-typedef struct SAMPLE_SIGRENDERER
-{
- SAMPLE_SIGDATA *sigdata;
- int n_channels;
- DUMB_RESAMPLER r;
- int n_loops;
-}
-SAMPLE_SIGRENDERER;
-
-
-
-static sigdata_t *sample_load_sigdata(DUH *duh, DUMBFILE *file)
-{
- SAMPLE_SIGDATA *sigdata;
- long size;
- long n;
- int flags;
-
- (void)duh;
-
- size = dumbfile_igetl(file);
-
- if (dumbfile_error(file) || size <= 0)
- return NULL;
-
- flags = dumbfile_getc(file);
- if (flags < 0)
- return NULL;
-
- sigdata = malloc(sizeof(*sigdata));
- if (!sigdata)
- return NULL;
-
- sigdata->samples = malloc(size * sizeof(sample_t));
- if (!sigdata->samples) {
- free(sigdata);
- return NULL;
- }
-
- sigdata->size = size;
- sigdata->flags = flags;
-
- if (sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) {
- sigdata->loop_start = dumbfile_igetl(file);
-
- if (dumbfile_error(file) || (unsigned long)sigdata->loop_start >= (unsigned long)size) {
- free(sigdata->samples);
- free(sigdata);
- return NULL;
- }
-
- if (sigdata->flags & SAMPFLAG_LOOP)
- sigdata->loop_end = size;
- else {
- sigdata->loop_end = dumbfile_igetl(file);
-
- if (dumbfile_error(file) || sigdata->loop_end <= sigdata->loop_start || sigdata->loop_end > size) {
- free(sigdata->samples);
- free(sigdata);
- return NULL;
- }
- }
- } else {
- sigdata->loop_start = 0;
- sigdata->loop_end = size;
- }
-
- if (sigdata->flags & SAMPFLAG_16BIT) {
- for (n = 0; n < size; n++) {
- int m = dumbfile_igetw(file);
- if (m < 0) {
- free(sigdata->samples);
- free(sigdata);
- return NULL;
- }
- sigdata->samples[n] = (int)(signed short)m << 8;
- }
- } else {
- for (n = 0; n < size; n++) {
- int m = dumbfile_getc(file);
- if (m < 0) {
- free(sigdata->samples);
- free(sigdata);
- return NULL;
- }
- sigdata->samples[n] = (int)(signed char)m << 16;
- }
- }
-
- return sigdata;
-}
-
-
-
-static void sample_pickup(DUMB_RESAMPLER *r, void *data)
-{
- SAMPLE_SIGRENDERER *sigrenderer = data;
-
- if (!(sigrenderer->sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP))) {
- r->dir = 0;
- return;
- }
-
- if (!(sigrenderer->sigdata->flags & SAMPFLAG_LOOP) && sigrenderer->n_loops == 0) {
- r->dir = 0;
- return;
- }
-
- if (sigrenderer->sigdata->flags & SAMPFLAG_PINGPONG) {
- if (r->dir < 0) {
- r->pos = (r->start << 1) - 1 - r->pos;
- r->subpos ^= 65535;
- r->dir = 1;
- } else {
- r->pos = (r->end << 1) - 1 - r->pos;
- r->subpos ^= 65535;
- r->dir = -1;
- }
- } else
- r->pos -= r->end - r->start;
-
- if (!(sigrenderer->sigdata->flags & SAMPFLAG_LOOP)) {
- if (sigrenderer->n_loops > 0) {
- sigrenderer->n_loops--;
- if (sigrenderer->n_loops == 0) {
- r->start = 0;
- r->end = sigrenderer->sigdata->size;
- }
- }
- }
-}
-
-
-
-static sigrenderer_t *sample_start_sigrenderer(DUH *duh, sigdata_t *data, int n_channels, long pos)
-{
- SAMPLE_SIGDATA *sigdata = data;
- SAMPLE_SIGRENDERER *sigrenderer;
-
- (void)duh;
-
- sigrenderer = malloc(sizeof(*sigrenderer));
- if (!sigrenderer) return NULL;
-
- sigrenderer->sigdata = data;
- sigrenderer->n_channels = n_channels;
- dumb_reset_resampler(&sigrenderer->r, sigdata->samples, pos, 0, sigdata->size);
- sigrenderer->r.pickup = &sample_pickup;
- sigrenderer->r.pickup_data = sigrenderer;
- sigrenderer->n_loops = 0;
-
- return sigrenderer;
-}
-
-
-
-#if 0
-/* The name says it all ;-) */
-static void sample_cheap_low_pass_filter(sample *src, long size, float max_freq) {
-
- long i;
- float fact = max_freq / 44100.0f;
-
- for (i = 0; i < size-1; i++) {
- float d = src[i+1] - src[i];
- if (d > fact)
- src[i+1] += fact - d;
- else if (d < -fact)
- src[i+1] += -d - fact;
- }
-
- return;
-}
-
-
-
-/* Dithering with noise shaping filter. Set shape = 0 for no shaping. */
-static void sample_dither_filter(float *src, long size, float shape) {
- float r1 = 0, r2 = 0;
- float s1 = 0, s2 = 0; /* Feedback buffer */
- float o = 0.5f / 255;
- float tmp;
- int i;
-
- for (i = 0; i < size; i++) {
- r2 = r1;
- r1 = rand() / (float)RAND_MAX;
-
- tmp = src[i] + shape * (s1 + s1 - s2);
- src[i] = tmp + o * (r1 - r2);
- src[i] = MID(-1.0f, src[i], 1.0f);
-
- s2 = s1;
- s1 = tmp - src[i];
- }
- return;
-}
-#endif
-
-
-
-static void sample_sigrenderer_set_sigparam(sigrenderer_t *data, unsigned char id, long value)
-{
- SAMPLE_SIGRENDERER *sigrenderer = data;
-
- if (id == SAMPPARAM_N_LOOPS) {
- if ((sigrenderer->sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) == SAMPFLAG_XLOOP) {
- sigrenderer->n_loops += value;
- sigrenderer->r.start = sigrenderer->n_loops ? sigrenderer->sigdata->loop_start : 0;
- sigrenderer->r.end = sigrenderer->n_loops ? sigrenderer->sigdata->loop_end : sigrenderer->sigdata->size;
- }
- }
-}
-
-
-
-static long sample_sigrenderer_get_samples(
- sigrenderer_t *data,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
- SAMPLE_SIGRENDERER *sigrenderer = data;
-
- DUMB_RESAMPLER initial_r = sigrenderer->r;
-
- long s = dumb_resample(&sigrenderer->r, samples[0], size, volume, delta);
-
- int n;
- for (n = 1; n < sigrenderer->n_channels; n++) {
- sigrenderer->r = initial_r;
- dumb_resample(&sigrenderer->r, samples[n], size, volume, delta);
- }
-
- return s;
-}
-
-
-
-static void sample_sigrenderer_get_current_sample(sigrenderer_t *data, float volume, sample_t *samples)
-{
- SAMPLE_SIGRENDERER *sigrenderer = data;
- int n;
- for (n = 0; n < sigrenderer->n_channels; n++)
- samples[n] = dumb_resample_get_current_sample(&sigrenderer->r, volume);
-}
-
-
-
-static void sample_end_sigrenderer(sigrenderer_t *sigrenderer)
-{
- free(sigrenderer);
-}
-
-
-
-static void sample_unload_sigdata(sigdata_t *data)
-{
- SAMPLE_SIGDATA *sigdata = data;
- free(sigdata->samples);
- free(data);
-}
-
-
-
-static DUH_SIGTYPE_DESC sigtype_sample = {
- SIGTYPE_SAMPLE,
- &sample_load_sigdata,
- &sample_start_sigrenderer,
- &sample_sigrenderer_set_sigparam,
- &sample_sigrenderer_get_samples,
- &sample_sigrenderer_get_current_sample,
- &sample_end_sigrenderer,
- &sample_unload_sigdata
-};
-
-
-
-void dumb_register_sigtype_sample(void)
-{
- dumb_register_sigtype(&sigtype_sample);
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * sample.c - The sample (SAMP) signal type. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * This only supports monaural samples. For | \ / / + * multiple channels, use multiple samples and | ' / + * a combining signal (COMB). \__/ + */ + +/* NOTE: filters need not be credited yet, as they will be moved elsewhere. */ +/** WARNING don't forget to move these filters somewhere */ + +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" + + +/** WARNING move these things somewhere useful, for DUH writing - this applies to other signal types too */ +#define SIGTYPE_SAMPLE DUMB_ID('S','A','M','P') + + + +#define SAMPFLAG_16BIT 1 /* sample in file is 16 bit, rather than 8 bit */ +#define SAMPFLAG_LOOP 2 /* loop indefinitely */ +#define SAMPFLAG_XLOOP 4 /* loop x times; only relevant if LOOP not set */ +#define SAMPFLAG_PINGPONG 8 /* loop back and forth, if LOOP or XLOOP set */ + + +/* SAMPPARAM_N_LOOPS: add 'value' iterations to the loop. 'value' is assumed + * to be positive. + */ +#define SAMPPARAM_N_LOOPS 0 + + + +typedef struct SAMPLE_SIGDATA +{ + long size; + int flags; + long loop_start; + long loop_end; + sample_t *samples; +} +SAMPLE_SIGDATA; + + + +typedef struct SAMPLE_SIGRENDERER +{ + SAMPLE_SIGDATA *sigdata; + int n_channels; + DUMB_RESAMPLER r; + int n_loops; +} +SAMPLE_SIGRENDERER; + + + +static sigdata_t *sample_load_sigdata(DUH *duh, DUMBFILE *file) +{ + SAMPLE_SIGDATA *sigdata; + long size; + long n; + int flags; + + (void)duh; + + size = dumbfile_igetl(file); + + if (dumbfile_error(file) || size <= 0) + return NULL; + + flags = dumbfile_getc(file); + if (flags < 0) + return NULL; + + sigdata = malloc(sizeof(*sigdata)); + if (!sigdata) + return NULL; + + sigdata->samples = malloc(size * sizeof(sample_t)); + if (!sigdata->samples) { + free(sigdata); + return NULL; + } + + sigdata->size = size; + sigdata->flags = flags; + + if (sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) { + sigdata->loop_start = dumbfile_igetl(file); + + if (dumbfile_error(file) || (unsigned long)sigdata->loop_start >= (unsigned long)size) { + free(sigdata->samples); + free(sigdata); + return NULL; + } + + if (sigdata->flags & SAMPFLAG_LOOP) + sigdata->loop_end = size; + else { + sigdata->loop_end = dumbfile_igetl(file); + + if (dumbfile_error(file) || sigdata->loop_end <= sigdata->loop_start || sigdata->loop_end > size) { + free(sigdata->samples); + free(sigdata); + return NULL; + } + } + } else { + sigdata->loop_start = 0; + sigdata->loop_end = size; + } + + if (sigdata->flags & SAMPFLAG_16BIT) { + for (n = 0; n < size; n++) { + int m = dumbfile_igetw(file); + if (m < 0) { + free(sigdata->samples); + free(sigdata); + return NULL; + } + sigdata->samples[n] = (int)(signed short)m << 8; + } + } else { + for (n = 0; n < size; n++) { + int m = dumbfile_getc(file); + if (m < 0) { + free(sigdata->samples); + free(sigdata); + return NULL; + } + sigdata->samples[n] = (int)(signed char)m << 16; + } + } + + return sigdata; +} + + + +static void sample_pickup(DUMB_RESAMPLER *r, void *data) +{ + SAMPLE_SIGRENDERER *sigrenderer = data; + + if (!(sigrenderer->sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP))) { + r->dir = 0; + return; + } + + if (!(sigrenderer->sigdata->flags & SAMPFLAG_LOOP) && sigrenderer->n_loops == 0) { + r->dir = 0; + return; + } + + if (sigrenderer->sigdata->flags & SAMPFLAG_PINGPONG) { + if (r->dir < 0) { + r->pos = (r->start << 1) - 1 - r->pos; + r->subpos ^= 65535; + r->dir = 1; + } else { + r->pos = (r->end << 1) - 1 - r->pos; + r->subpos ^= 65535; + r->dir = -1; + } + } else + r->pos -= r->end - r->start; + + if (!(sigrenderer->sigdata->flags & SAMPFLAG_LOOP)) { + if (sigrenderer->n_loops > 0) { + sigrenderer->n_loops--; + if (sigrenderer->n_loops == 0) { + r->start = 0; + r->end = sigrenderer->sigdata->size; + } + } + } +} + + + +static sigrenderer_t *sample_start_sigrenderer(DUH *duh, sigdata_t *data, int n_channels, long pos) +{ + SAMPLE_SIGDATA *sigdata = data; + SAMPLE_SIGRENDERER *sigrenderer; + + (void)duh; + + sigrenderer = malloc(sizeof(*sigrenderer)); + if (!sigrenderer) return NULL; + + sigrenderer->sigdata = data; + sigrenderer->n_channels = n_channels; + dumb_reset_resampler(&sigrenderer->r, sigdata->samples, pos, 0, sigdata->size); + sigrenderer->r.pickup = &sample_pickup; + sigrenderer->r.pickup_data = sigrenderer; + sigrenderer->n_loops = 0; + + return sigrenderer; +} + + + +#if 0 +/* The name says it all ;-) */ +static void sample_cheap_low_pass_filter(sample *src, long size, float max_freq) { + + long i; + float fact = max_freq / 44100.0f; + + for (i = 0; i < size-1; i++) { + float d = src[i+1] - src[i]; + if (d > fact) + src[i+1] += fact - d; + else if (d < -fact) + src[i+1] += -d - fact; + } + + return; +} + + + +/* Dithering with noise shaping filter. Set shape = 0 for no shaping. */ +static void sample_dither_filter(float *src, long size, float shape) { + float r1 = 0, r2 = 0; + float s1 = 0, s2 = 0; /* Feedback buffer */ + float o = 0.5f / 255; + float tmp; + int i; + + for (i = 0; i < size; i++) { + r2 = r1; + r1 = rand() / (float)RAND_MAX; + + tmp = src[i] + shape * (s1 + s1 - s2); + src[i] = tmp + o * (r1 - r2); + src[i] = MID(-1.0f, src[i], 1.0f); + + s2 = s1; + s1 = tmp - src[i]; + } + return; +} +#endif + + + +static void sample_sigrenderer_set_sigparam(sigrenderer_t *data, unsigned char id, long value) +{ + SAMPLE_SIGRENDERER *sigrenderer = data; + + if (id == SAMPPARAM_N_LOOPS) { + if ((sigrenderer->sigdata->flags & (SAMPFLAG_LOOP | SAMPFLAG_XLOOP)) == SAMPFLAG_XLOOP) { + sigrenderer->n_loops += value; + sigrenderer->r.start = sigrenderer->n_loops ? sigrenderer->sigdata->loop_start : 0; + sigrenderer->r.end = sigrenderer->n_loops ? sigrenderer->sigdata->loop_end : sigrenderer->sigdata->size; + } + } +} + + + +static long sample_sigrenderer_get_samples( + sigrenderer_t *data, + float volume, float delta, + long size, sample_t **samples +) +{ + SAMPLE_SIGRENDERER *sigrenderer = data; + + DUMB_RESAMPLER initial_r = sigrenderer->r; + + long s = dumb_resample(&sigrenderer->r, samples[0], size, volume, delta); + + int n; + for (n = 1; n < sigrenderer->n_channels; n++) { + sigrenderer->r = initial_r; + dumb_resample(&sigrenderer->r, samples[n], size, volume, delta); + } + + return s; +} + + + +static void sample_sigrenderer_get_current_sample(sigrenderer_t *data, float volume, sample_t *samples) +{ + SAMPLE_SIGRENDERER *sigrenderer = data; + int n; + for (n = 0; n < sigrenderer->n_channels; n++) + samples[n] = dumb_resample_get_current_sample(&sigrenderer->r, volume); +} + + + +static void sample_end_sigrenderer(sigrenderer_t *sigrenderer) +{ + free(sigrenderer); +} + + + +static void sample_unload_sigdata(sigdata_t *data) +{ + SAMPLE_SIGDATA *sigdata = data; + free(sigdata->samples); + free(data); +} + + + +static DUH_SIGTYPE_DESC sigtype_sample = { + SIGTYPE_SAMPLE, + &sample_load_sigdata, + &sample_start_sigrenderer, + &sample_sigrenderer_set_sigparam, + &sample_sigrenderer_get_samples, + &sample_sigrenderer_get_current_sample, + &sample_end_sigrenderer, + &sample_unload_sigdata +}; + + + +void dumb_register_sigtype_sample(void) +{ + dumb_register_sigtype(&sigtype_sample); +} diff --git a/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c b/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c index cfade4d6..38cbe783 100644 --- a/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c +++ b/plugins/dumb/dumb-kode54/src/sigtypes/sequence.c @@ -1,592 +1,592 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * sequence.c - The sequence (SEQU) signal type. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * | \ / /
- * | ' /
- * \__/
- */
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "dumb.h"
-
-
-
-#define SIGTYPE_SEQUENCE DUMB_ID('S','E','Q','U')
-
-
-
-/* We have 256 intervals per semitone, 12 * 256 per octave
- 2 ** (1 / (12 * 256)) = 1.000225659305069791926712241547647863626
-
- pow(DUMB_PITCH_BASE, x) = 1.5
- x = log2(1.5) / log2(DUMB_PITCH_BASE)
- x = log2(1.5) * 12 * 256
- x = 1797.004802
- cf.
- x = 7 * 256 = 1792
-
- so, for the perfect fifth temperament, use an interval of 1797.
-*/
-
-
-
-/* Sequencing format
- * -----------------
- *
- * NOTE: A LOT OF THIS IS NOW REDUNDANT. PLEASE REFER TO duhspecs.txt.
- *
- * When a signal is initiated, it claims a reference number. If any other
- * currently playing signal has the same number, that signal becomes
- * anonymous and inaccessible; that is, if multiple signals were initiated
- * with the same reference, the reference belongs to the most recent.
- *
- * Signals can be stopped, or have their pitch, volume or parameters changed,
- * using the reference number. A signal may stop prematurely if it runs out
- * of data, in which case the reference number becomes void, and operations
- * on it will be ignored. Such a situation will not flag any kind of warning,
- * since it may be the result of inaccuracies when resampling.
- *
- * The sequence consists of a series of commands. All commands begin with a
- * long int, which is the time to wait after the last command (or the
- * beginning of the sequence) before executing this command. 65536 represents
- * one second. A time of -1 (or in fact any negative time) terminates the
- * sequence, but any currently playing signals will continue until they run
- * out. Make sure no non-terminating signals are playing when the sequence
- * ends!
- *
- * The time, if nonnegative, is followed by one byte indicating the type of
- * command. This byte can have the following values:
- *
- * SEQUENCE_START_SIGNAL
- * unsigned char ref; - Reference. Need more than 256? Use two sequences,
- * and get your brain seen to.
- * int sig; - The index of the signal to initiate.
- * long pos; - The position at which to start. 65536 represents one second.
- * unsigned short volume; - Volume. 65535 represents the maximum volume, so
- * you will want to go lower than this if you are
- * playing more than one signal at once.
- * signed short pitch; - Pitch. 0 represents a frequency of 65536 Hz. Scale
- * is logarithmic. Add 256 to increase pitch by one
- * semitone in the even temperament, or add 12*256 to
- * increase pitch by one octave in any temperament
- * (i.e. double the frequency).
- *
- * SEQUENCE_SET_VOLUME
- * unsigned char ref;
- * unsigned short volume;
- *
- * SEQUENCE_SET_PITCH
- * unsigned char ref;
- * signed short pitch;
- *
- * SEQUENCE_SET_PARAMETER
- * unsigned char ref;
- * unsigned char id;
- * long value;
- * - see the description of the set_parameter function pointer for
- * information on 'id' and 'value'.
- *
- * SEQUENCE_STOP_SIGNAL
- * unsigned char ref;
- */
-
-
-
-#define SEQUENCE_START_SIGNAL 0
-#define SEQUENCE_SET_VOLUME 1
-#define SEQUENCE_SET_PITCH 2
-#define SEQUENCE_SET_PARAMETER 3
-#define SEQUENCE_STOP_SIGNAL 4
-
-
-
-typedef struct SEQUENCE_PLAYING
-{
- struct SEQUENCE_PLAYING *next;
-
- DUH_SIGNAL_SAMPINFO *sampinfo;
-
- int ref;
-
- int pitch;
- int volume;
-}
-SEQUENCE_PLAYING;
-
-
-
-typedef struct SEQUENCE_SAMPINFO
-{
- DUH *duh;
-
- int n_channels;
-
- unsigned char *signal;
-
- long time_left;
- int sub_time_left;
-
- SEQUENCE_PLAYING *playing;
-}
-SEQUENCE_SAMPINFO;
-
-
-
-#define sequence_c(signal) ((int)*((*(signal))++))
-
-
-static int sequence_w(unsigned char **signal)
-{
- int v = (*signal)[0] | ((*signal)[1] << 8);
- *signal += 2;
- return v;
-}
-
-
-static long sequence_l(unsigned char **signal)
-{
- long v = (*signal)[0] | ((*signal)[1] << 8) | ((*signal)[2] << 16) | ((*signal)[3] << 24);
- *signal += 4;
- return v;
-}
-
-
-static long sequence_cl(unsigned char **signal)
-{
- long v = sequence_c(signal);
- if (v & 0x80) {
- v &= 0x7F;
- v |= sequence_c(signal) << 7;
- if (v & 0x4000) {
- v &= 0x3FFF;
- v |= sequence_c(signal) << 14;
- if (v & 0x200000) {
- v &= 0x1FFFFF;
- v |= sequence_c(signal) << 21;
- if (v & 0x10000000) {
- v &= 0x0FFFFFFF;
- v |= sequence_c(signal) << 28;
- }
- }
- }
- }
- return v;
-}
-
-
-
-static void *sequence_load_signal(DUH *duh, DUMBFILE *file)
-{
- long size;
- unsigned char *signal;
-
- (void)duh;
-
- size = dumbfile_igetl(file);
- if (dumbfile_error(file) || size <= 0)
- return NULL;
-
- signal = malloc(size);
- if (!signal)
- return NULL;
-
- if (dumbfile_getnc((char *)signal, size, file) < size) {
- free(signal);
- return NULL;
- }
-
- return signal;
-}
-
-
-
-static long render(
- SEQUENCE_SAMPINFO *sampinfo,
- float volume, float delta,
- long pos, long size, sample_t **samples
-)
-{
- sample_t **splptr;
-
- SEQUENCE_PLAYING **playing_p = &sampinfo->playing;
-
- long max_size = 0;
- long part_size;
-
- int n;
- long i;
-
- for (n = 0; n < sampinfo->n_channels; n++)
- memset(samples[n] + pos, 0, size * sizeof(sample_t));
-
- splptr = malloc(sampinfo->n_channels * sizeof(*splptr));
- if (!splptr)
- return 0;
-
- splptr[0] = malloc(sampinfo->n_channels * size * sizeof(sample_t));
- if (!splptr[0]) {
- free(splptr);
- return 0;
- }
-
- for (n = 1; n < sampinfo->n_channels; n++)
- splptr[n] = splptr[n - 1] + size;
-
- while (*playing_p) {
- SEQUENCE_PLAYING *playing = *playing_p;
-
- part_size = duh_signal_render_samples(
- playing->sampinfo,
- volume * (float)playing->volume * (1.0f / 65535.0f),
- (float)(pow(DUMB_PITCH_BASE, playing->pitch) * delta),
- size, splptr
- );
-
- for (n = 0; n < sampinfo->n_channels; n++)
- for (i = 0; i < part_size; i++)
- samples[n][pos+i] += splptr[n][i];
-
- if (part_size > max_size)
- max_size = part_size;
-
- if (part_size < size) {
- *playing_p = playing->next;
- duh_signal_end_samples(playing->sampinfo);
- free(playing);
- } else
- playing_p = &playing->next;
- }
-
- free(splptr[0]);
- free(splptr);
-
- return max_size;
-}
-
-
-
-/* 'offset' is added to the position at which the signal should start. It is
- * currently assumed to be positive, and is currently only used when seeking
- * forwards in the sequence.
- */
-static void sequence_command(SEQUENCE_SAMPINFO *sampinfo, long offset)
-{
- int command = sequence_c(&sampinfo->signal);
-
- if (command == SEQUENCE_START_SIGNAL) {
-
- int ref = sequence_c(&sampinfo->signal);
- int sig = sequence_cl(&sampinfo->signal);
- long pos = sequence_cl(&sampinfo->signal);
- int volume = sequence_w(&sampinfo->signal);
- int pitch = (int)(signed short)sequence_w(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref)
- playing->ref = -1;
- playing = playing->next;
- }
-
- playing = malloc(sizeof(SEQUENCE_PLAYING));
-
- if (playing) {
- playing->sampinfo = duh_signal_start_samples(sampinfo->duh, sig, sampinfo->n_channels, pos + offset);
-
- if (playing->sampinfo) {
- playing->ref = ref;
- playing->pitch = pitch;
- playing->volume = volume;
-
- playing->next = sampinfo->playing;
- sampinfo->playing = playing;
- } else
- free(playing);
- }
-
- } else if (command == SEQUENCE_SET_VOLUME) {
-
- int ref = sequence_c(&sampinfo->signal);
- int volume = sequence_w(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref) {
- playing->volume = volume;
- break;
- }
- playing = playing->next;
- }
-
- } else if (command == SEQUENCE_SET_PITCH) {
-
- int ref = sequence_c(&sampinfo->signal);
- int pitch = (int)(signed short)sequence_w(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref) {
- playing->pitch = pitch;
- break;
- }
- playing = playing->next;
- }
-
- } else if (command == SEQUENCE_SET_PARAMETER) {
-
- int ref = sequence_c(&sampinfo->signal);
- unsigned char id = sequence_c(&sampinfo->signal);
- long value = sequence_l(&sampinfo->signal);
-
- SEQUENCE_PLAYING *playing = sampinfo->playing;
-
- while (playing) {
- if (playing->ref == ref) {
- duh_signal_set_parameter(playing->sampinfo, id, value);
- break;
- }
- playing = playing->next;
- }
-
- } else if (command == SEQUENCE_STOP_SIGNAL) {
-
- int ref = sequence_c(&sampinfo->signal);
-
- SEQUENCE_PLAYING **playing_p = &sampinfo->playing;
-
- while (*playing_p) {
- SEQUENCE_PLAYING *playing = *playing_p;
-
- if (playing->ref == ref) {
- duh_signal_end_samples(playing->sampinfo);
- *playing_p = playing->next;
- free(playing);
- break;
- }
-
- playing_p = &playing->next;
- }
-
- } else {
-
- TRACE("Error in sequence: unknown command %d.\n", command);
- sampinfo->signal = NULL;
-
- }
-}
-
-
-
-static void *sequence_start_samples(DUH *duh, void *signal, int n_channels, long pos)
-{
- SEQUENCE_SAMPINFO *sampinfo;
- long time = sequence_cl((unsigned char **)&signal);
-
- if (time < 0)
- return NULL;
-
- sampinfo = malloc(sizeof(SEQUENCE_SAMPINFO));
- if (!sampinfo)
- return NULL;
-
- sampinfo->duh = duh;
- sampinfo->n_channels = n_channels;
- sampinfo->signal = signal;
- sampinfo->playing = NULL;
-
- /* Seek to 'pos'. */
- while (time < pos) {
- pos -= time;
-
- sequence_command(sampinfo, pos);
-
- time = sequence_cl(&sampinfo->signal);
-
- if (time < 0) {
- sampinfo->signal = NULL;
- return sampinfo;
- }
- }
-
- sampinfo->time_left = time - pos;
- sampinfo->sub_time_left = 0;
-
- return sampinfo;
-}
-
-
-
-static long sequence_render_samples(
- void *sampinfo,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
-
-#define sampinfo ((SEQUENCE_SAMPINFO *)sampinfo)
-
- long pos = 0;
-
- int dt = (int)(delta * 65536.0f + 0.5f);
-
- long todo;
- LONG_LONG t;
-
- while (sampinfo->signal) {
- todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt);
-
- if (todo >= size)
- break;
-
- if (todo) {
- render(sampinfo, volume, delta, pos, todo, samples);
-
- pos += todo;
- size -= todo;
-
- todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt);
- t = sampinfo->sub_time_left - (LONG_LONG)todo * dt;
- sampinfo->sub_time_left = (long)t & 65535;
- sampinfo->time_left += (long)(t >> 16);
- }
-
- sequence_command(sampinfo, 0);
-
- todo = sequence_cl(&sampinfo->signal);
-
- if (todo >= 0)
- sampinfo->time_left += todo;
- else
- sampinfo->signal = NULL;
- }
-
- if (sampinfo->signal) {
- render(sampinfo, volume, delta, pos, size, samples);
-
- pos += size;
-
- t = sampinfo->sub_time_left - (LONG_LONG)size * dt;
- sampinfo->sub_time_left = (long)t & 65535;
- sampinfo->time_left += (long)(t >> 16);
- } else
- pos += render(sampinfo, volume, delta, pos, size, samples);
-
- return pos;
-
-
-/** WARNING - remove this... */
-#if 0
- float size_unified = size * delta;
-
- int n;
-
- sample_t **samples2 = malloc(sampinfo->n_channels * sizeof(*samples2));
- memcpy(samples2, samples, sampinfo->n_channels * sizeof(*samples2));
-
- while (sampinfo->signal && sampinfo->time < size_unified) {
-
- {
- long sz = (long)(sampinfo->time / delta);
-
- if (sz)
- render(sampinfo, volume, delta, sz, samples2);
-
- for (n = 0; n < sampinfo->n_channels; n++)
- samples2[n] += sz;
-
- size -= sz;
- pos += sz;
-
- sampinfo->time -= sz * delta;
- }
-
- sequence_command(sampinfo, 0);
-
- {
- long time = sequence_cl(&sampinfo->signal);
-
- if (time >= 0)
- sampinfo->time += (float)time;
- else
- sampinfo->signal = NULL;
- }
-
- size_unified = size * delta;
- }
-
- if (sampinfo->signal) {
- render(sampinfo, volume, delta, size, samples2);
- sampinfo->time -= size_unified;
- pos += size;
- } else
- pos += render(sampinfo, volume, delta, size, samples2);
-
- free(samples2);
-
- return pos;
-#endif
-
-#undef sampinfo
-
-}
-
-
-
-static void sequence_end_samples(void *sampinfo)
-{
- SEQUENCE_PLAYING *playing = ((SEQUENCE_SAMPINFO *)sampinfo)->playing;
-
- while (playing) {
- SEQUENCE_PLAYING *next = playing->next;
-
- duh_signal_end_samples(playing->sampinfo);
- free(playing);
-
- playing = next;
- }
-
- free(sampinfo);
-}
-
-
-
-static void sequence_unload_signal(void *signal)
-{
- free(signal);
-}
-
-
-
-static DUH_SIGTYPE_DESC sigtype_sequence = {
- SIGTYPE_SEQUENCE,
- &sequence_load_signal,
- &sequence_start_samples,
- NULL,
- &sequence_render_samples,
- &sequence_end_samples,
- &sequence_unload_signal
-};
-
-
-
-void dumb_register_sigtype_sequence(void)
-{
- dumb_register_sigtype(&sigtype_sequence);
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * sequence.c - The sequence (SEQU) signal type. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * | \ / / + * | ' / + * \__/ + */ + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#include "dumb.h" + + + +#define SIGTYPE_SEQUENCE DUMB_ID('S','E','Q','U') + + + +/* We have 256 intervals per semitone, 12 * 256 per octave + 2 ** (1 / (12 * 256)) = 1.000225659305069791926712241547647863626 + + pow(DUMB_PITCH_BASE, x) = 1.5 + x = log2(1.5) / log2(DUMB_PITCH_BASE) + x = log2(1.5) * 12 * 256 + x = 1797.004802 + cf. + x = 7 * 256 = 1792 + + so, for the perfect fifth temperament, use an interval of 1797. +*/ + + + +/* Sequencing format + * ----------------- + * + * NOTE: A LOT OF THIS IS NOW REDUNDANT. PLEASE REFER TO duhspecs.txt. + * + * When a signal is initiated, it claims a reference number. If any other + * currently playing signal has the same number, that signal becomes + * anonymous and inaccessible; that is, if multiple signals were initiated + * with the same reference, the reference belongs to the most recent. + * + * Signals can be stopped, or have their pitch, volume or parameters changed, + * using the reference number. A signal may stop prematurely if it runs out + * of data, in which case the reference number becomes void, and operations + * on it will be ignored. Such a situation will not flag any kind of warning, + * since it may be the result of inaccuracies when resampling. + * + * The sequence consists of a series of commands. All commands begin with a + * long int, which is the time to wait after the last command (or the + * beginning of the sequence) before executing this command. 65536 represents + * one second. A time of -1 (or in fact any negative time) terminates the + * sequence, but any currently playing signals will continue until they run + * out. Make sure no non-terminating signals are playing when the sequence + * ends! + * + * The time, if nonnegative, is followed by one byte indicating the type of + * command. This byte can have the following values: + * + * SEQUENCE_START_SIGNAL + * unsigned char ref; - Reference. Need more than 256? Use two sequences, + * and get your brain seen to. + * int sig; - The index of the signal to initiate. + * long pos; - The position at which to start. 65536 represents one second. + * unsigned short volume; - Volume. 65535 represents the maximum volume, so + * you will want to go lower than this if you are + * playing more than one signal at once. + * signed short pitch; - Pitch. 0 represents a frequency of 65536 Hz. Scale + * is logarithmic. Add 256 to increase pitch by one + * semitone in the even temperament, or add 12*256 to + * increase pitch by one octave in any temperament + * (i.e. double the frequency). + * + * SEQUENCE_SET_VOLUME + * unsigned char ref; + * unsigned short volume; + * + * SEQUENCE_SET_PITCH + * unsigned char ref; + * signed short pitch; + * + * SEQUENCE_SET_PARAMETER + * unsigned char ref; + * unsigned char id; + * long value; + * - see the description of the set_parameter function pointer for + * information on 'id' and 'value'. + * + * SEQUENCE_STOP_SIGNAL + * unsigned char ref; + */ + + + +#define SEQUENCE_START_SIGNAL 0 +#define SEQUENCE_SET_VOLUME 1 +#define SEQUENCE_SET_PITCH 2 +#define SEQUENCE_SET_PARAMETER 3 +#define SEQUENCE_STOP_SIGNAL 4 + + + +typedef struct SEQUENCE_PLAYING +{ + struct SEQUENCE_PLAYING *next; + + DUH_SIGNAL_SAMPINFO *sampinfo; + + int ref; + + int pitch; + int volume; +} +SEQUENCE_PLAYING; + + + +typedef struct SEQUENCE_SAMPINFO +{ + DUH *duh; + + int n_channels; + + unsigned char *signal; + + long time_left; + int sub_time_left; + + SEQUENCE_PLAYING *playing; +} +SEQUENCE_SAMPINFO; + + + +#define sequence_c(signal) ((int)*((*(signal))++)) + + +static int sequence_w(unsigned char **signal) +{ + int v = (*signal)[0] | ((*signal)[1] << 8); + *signal += 2; + return v; +} + + +static long sequence_l(unsigned char **signal) +{ + long v = (*signal)[0] | ((*signal)[1] << 8) | ((*signal)[2] << 16) | ((*signal)[3] << 24); + *signal += 4; + return v; +} + + +static long sequence_cl(unsigned char **signal) +{ + long v = sequence_c(signal); + if (v & 0x80) { + v &= 0x7F; + v |= sequence_c(signal) << 7; + if (v & 0x4000) { + v &= 0x3FFF; + v |= sequence_c(signal) << 14; + if (v & 0x200000) { + v &= 0x1FFFFF; + v |= sequence_c(signal) << 21; + if (v & 0x10000000) { + v &= 0x0FFFFFFF; + v |= sequence_c(signal) << 28; + } + } + } + } + return v; +} + + + +static void *sequence_load_signal(DUH *duh, DUMBFILE *file) +{ + long size; + unsigned char *signal; + + (void)duh; + + size = dumbfile_igetl(file); + if (dumbfile_error(file) || size <= 0) + return NULL; + + signal = malloc(size); + if (!signal) + return NULL; + + if (dumbfile_getnc((char *)signal, size, file) < size) { + free(signal); + return NULL; + } + + return signal; +} + + + +static long render( + SEQUENCE_SAMPINFO *sampinfo, + float volume, float delta, + long pos, long size, sample_t **samples +) +{ + sample_t **splptr; + + SEQUENCE_PLAYING **playing_p = &sampinfo->playing; + + long max_size = 0; + long part_size; + + int n; + long i; + + for (n = 0; n < sampinfo->n_channels; n++) + memset(samples[n] + pos, 0, size * sizeof(sample_t)); + + splptr = malloc(sampinfo->n_channels * sizeof(*splptr)); + if (!splptr) + return 0; + + splptr[0] = malloc(sampinfo->n_channels * size * sizeof(sample_t)); + if (!splptr[0]) { + free(splptr); + return 0; + } + + for (n = 1; n < sampinfo->n_channels; n++) + splptr[n] = splptr[n - 1] + size; + + while (*playing_p) { + SEQUENCE_PLAYING *playing = *playing_p; + + part_size = duh_signal_render_samples( + playing->sampinfo, + volume * (float)playing->volume * (1.0f / 65535.0f), + (float)(pow(DUMB_PITCH_BASE, playing->pitch) * delta), + size, splptr + ); + + for (n = 0; n < sampinfo->n_channels; n++) + for (i = 0; i < part_size; i++) + samples[n][pos+i] += splptr[n][i]; + + if (part_size > max_size) + max_size = part_size; + + if (part_size < size) { + *playing_p = playing->next; + duh_signal_end_samples(playing->sampinfo); + free(playing); + } else + playing_p = &playing->next; + } + + free(splptr[0]); + free(splptr); + + return max_size; +} + + + +/* 'offset' is added to the position at which the signal should start. It is + * currently assumed to be positive, and is currently only used when seeking + * forwards in the sequence. + */ +static void sequence_command(SEQUENCE_SAMPINFO *sampinfo, long offset) +{ + int command = sequence_c(&sampinfo->signal); + + if (command == SEQUENCE_START_SIGNAL) { + + int ref = sequence_c(&sampinfo->signal); + int sig = sequence_cl(&sampinfo->signal); + long pos = sequence_cl(&sampinfo->signal); + int volume = sequence_w(&sampinfo->signal); + int pitch = (int)(signed short)sequence_w(&sampinfo->signal); + + SEQUENCE_PLAYING *playing = sampinfo->playing; + + while (playing) { + if (playing->ref == ref) + playing->ref = -1; + playing = playing->next; + } + + playing = malloc(sizeof(SEQUENCE_PLAYING)); + + if (playing) { + playing->sampinfo = duh_signal_start_samples(sampinfo->duh, sig, sampinfo->n_channels, pos + offset); + + if (playing->sampinfo) { + playing->ref = ref; + playing->pitch = pitch; + playing->volume = volume; + + playing->next = sampinfo->playing; + sampinfo->playing = playing; + } else + free(playing); + } + + } else if (command == SEQUENCE_SET_VOLUME) { + + int ref = sequence_c(&sampinfo->signal); + int volume = sequence_w(&sampinfo->signal); + + SEQUENCE_PLAYING *playing = sampinfo->playing; + + while (playing) { + if (playing->ref == ref) { + playing->volume = volume; + break; + } + playing = playing->next; + } + + } else if (command == SEQUENCE_SET_PITCH) { + + int ref = sequence_c(&sampinfo->signal); + int pitch = (int)(signed short)sequence_w(&sampinfo->signal); + + SEQUENCE_PLAYING *playing = sampinfo->playing; + + while (playing) { + if (playing->ref == ref) { + playing->pitch = pitch; + break; + } + playing = playing->next; + } + + } else if (command == SEQUENCE_SET_PARAMETER) { + + int ref = sequence_c(&sampinfo->signal); + unsigned char id = sequence_c(&sampinfo->signal); + long value = sequence_l(&sampinfo->signal); + + SEQUENCE_PLAYING *playing = sampinfo->playing; + + while (playing) { + if (playing->ref == ref) { + duh_signal_set_parameter(playing->sampinfo, id, value); + break; + } + playing = playing->next; + } + + } else if (command == SEQUENCE_STOP_SIGNAL) { + + int ref = sequence_c(&sampinfo->signal); + + SEQUENCE_PLAYING **playing_p = &sampinfo->playing; + + while (*playing_p) { + SEQUENCE_PLAYING *playing = *playing_p; + + if (playing->ref == ref) { + duh_signal_end_samples(playing->sampinfo); + *playing_p = playing->next; + free(playing); + break; + } + + playing_p = &playing->next; + } + + } else { + + TRACE("Error in sequence: unknown command %d.\n", command); + sampinfo->signal = NULL; + + } +} + + + +static void *sequence_start_samples(DUH *duh, void *signal, int n_channels, long pos) +{ + SEQUENCE_SAMPINFO *sampinfo; + long time = sequence_cl((unsigned char **)&signal); + + if (time < 0) + return NULL; + + sampinfo = malloc(sizeof(SEQUENCE_SAMPINFO)); + if (!sampinfo) + return NULL; + + sampinfo->duh = duh; + sampinfo->n_channels = n_channels; + sampinfo->signal = signal; + sampinfo->playing = NULL; + + /* Seek to 'pos'. */ + while (time < pos) { + pos -= time; + + sequence_command(sampinfo, pos); + + time = sequence_cl(&sampinfo->signal); + + if (time < 0) { + sampinfo->signal = NULL; + return sampinfo; + } + } + + sampinfo->time_left = time - pos; + sampinfo->sub_time_left = 0; + + return sampinfo; +} + + + +static long sequence_render_samples( + void *sampinfo, + float volume, float delta, + long size, sample_t **samples +) +{ + +#define sampinfo ((SEQUENCE_SAMPINFO *)sampinfo) + + long pos = 0; + + int dt = (int)(delta * 65536.0f + 0.5f); + + long todo; + LONG_LONG t; + + while (sampinfo->signal) { + todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt); + + if (todo >= size) + break; + + if (todo) { + render(sampinfo, volume, delta, pos, todo, samples); + + pos += todo; + size -= todo; + + todo = (long)((((LONG_LONG)sampinfo->time_left << 16) | sampinfo->sub_time_left) / dt); + t = sampinfo->sub_time_left - (LONG_LONG)todo * dt; + sampinfo->sub_time_left = (long)t & 65535; + sampinfo->time_left += (long)(t >> 16); + } + + sequence_command(sampinfo, 0); + + todo = sequence_cl(&sampinfo->signal); + + if (todo >= 0) + sampinfo->time_left += todo; + else + sampinfo->signal = NULL; + } + + if (sampinfo->signal) { + render(sampinfo, volume, delta, pos, size, samples); + + pos += size; + + t = sampinfo->sub_time_left - (LONG_LONG)size * dt; + sampinfo->sub_time_left = (long)t & 65535; + sampinfo->time_left += (long)(t >> 16); + } else + pos += render(sampinfo, volume, delta, pos, size, samples); + + return pos; + + +/** WARNING - remove this... */ +#if 0 + float size_unified = size * delta; + + int n; + + sample_t **samples2 = malloc(sampinfo->n_channels * sizeof(*samples2)); + memcpy(samples2, samples, sampinfo->n_channels * sizeof(*samples2)); + + while (sampinfo->signal && sampinfo->time < size_unified) { + + { + long sz = (long)(sampinfo->time / delta); + + if (sz) + render(sampinfo, volume, delta, sz, samples2); + + for (n = 0; n < sampinfo->n_channels; n++) + samples2[n] += sz; + + size -= sz; + pos += sz; + + sampinfo->time -= sz * delta; + } + + sequence_command(sampinfo, 0); + + { + long time = sequence_cl(&sampinfo->signal); + + if (time >= 0) + sampinfo->time += (float)time; + else + sampinfo->signal = NULL; + } + + size_unified = size * delta; + } + + if (sampinfo->signal) { + render(sampinfo, volume, delta, size, samples2); + sampinfo->time -= size_unified; + pos += size; + } else + pos += render(sampinfo, volume, delta, size, samples2); + + free(samples2); + + return pos; +#endif + +#undef sampinfo + +} + + + +static void sequence_end_samples(void *sampinfo) +{ + SEQUENCE_PLAYING *playing = ((SEQUENCE_SAMPINFO *)sampinfo)->playing; + + while (playing) { + SEQUENCE_PLAYING *next = playing->next; + + duh_signal_end_samples(playing->sampinfo); + free(playing); + + playing = next; + } + + free(sampinfo); +} + + + +static void sequence_unload_signal(void *signal) +{ + free(signal); +} + + + +static DUH_SIGTYPE_DESC sigtype_sequence = { + SIGTYPE_SEQUENCE, + &sequence_load_signal, + &sequence_start_samples, + NULL, + &sequence_render_samples, + &sequence_end_samples, + &sequence_unload_signal +}; + + + +void dumb_register_sigtype_sequence(void) +{ + dumb_register_sigtype(&sigtype_sequence); +} diff --git a/plugins/dumb/dumb-kode54/src/sigtypes/sterpan.c b/plugins/dumb/dumb-kode54/src/sigtypes/sterpan.c index 22fe5d28..b60c0c5e 100644 --- a/plugins/dumb/dumb-kode54/src/sigtypes/sterpan.c +++ b/plugins/dumb/dumb-kode54/src/sigtypes/sterpan.c @@ -1,206 +1,206 @@ -/* _______ ____ __ ___ ___
- * \ _ \ \ / \ / \ \ / / ' ' '
- * | | \ \ | | || | \/ | . .
- * | | | | | | || ||\ /| |
- * | | | | | | || || \/ | | ' ' '
- * | | | | | | || || | | . .
- * | |_/ / \ \__// || | |
- * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
- * / \
- * / . \
- * sterpan.c - The stereo pan (SPAN) signal type. / / \ \
- * | < / \_
- * By entheh. | \/ /\ /
- * \_ / > /
- * This takes a single monaural signal and | \ / /
- * expands it to two channels, applying a | ' /
- * stereo pan in the process. The stereo pan \__/
- * is generated by delaying and damping the
- * channel opposite the sound source. If only
- * one channel is requested of this signal, it will simply chain to the other
- * signal.
- *
- * In order for the delay to work properly, this must be played at 65536 Hz.
- * The pitch at which you want the sample to play can be passed in parameter
- * #1. Parameter #0 specifies the panning position, -256 to 256.
- *
- * NOTE: THIS IS NOT HOW IT WORKS AT THE MOMENT. AT THE MOMENT, THIS ROUTINE
- * SIMPLY VARIES THE VOLUMES.
- */
-
-#include <stdlib.h>
-
-#include "dumb.h"
-
-
-
-#define SIGTYPE_STEREOPAN DUMB_ID('S','P','A','N')
-
-
-
-#define SPANPARAM_PAN 0
-
-
-
-typedef struct STEREOPAN_SIGNAL
-{
- int sig;
-}
-STEREOPAN_SIGNAL;
-
-
-
-typedef struct STEREOPAN_SAMPINFO
-{
- float pan;
- int stereo;
- DUH_SIGNAL_SAMPINFO *csampinfo;
-}
-STEREOPAN_SAMPINFO;
-
-
-
-static void *stereopan_load_signal(DUH *duh, DUMBFILE *file)
-{
- STEREOPAN_SIGNAL *signal;
-
- (void)duh;
-
- signal = malloc(sizeof(*signal));
-
- if (!signal)
- return NULL;
-
- signal->sig = dumbfile_igetl(file);
-
- if (dumbfile_error(file)) {
- free(signal);
- return NULL;
- }
-
- return signal;
-}
-
-
-
-static void *stereopan_start_samples(DUH *duh, void *signal, int n_channels, long pos)
-{
- STEREOPAN_SAMPINFO *sampinfo;
-
-#define signal ((STEREOPAN_SIGNAL *)signal)
-
- if ((unsigned int)(n_channels - 1) >= 2) {
- TRACE("Stereo pan signal requiring 1 or 2 channels called with %d channels.\n", n_channels);
- return NULL;
- }
-
- sampinfo = malloc(sizeof(*sampinfo));
- if (!sampinfo)
- return NULL;
-
- sampinfo->pan = 0;
-
- sampinfo->stereo = n_channels - 1;
-
- sampinfo->csampinfo = duh_signal_start_samples(duh, signal->sig, 1, pos);
- if (!sampinfo->csampinfo) {
- free(sampinfo);
- return NULL;
- }
-
-#undef signal
-
- return sampinfo;
-}
-
-
-
-static void stereopan_set_parameter(void *sampinfo, unsigned char id, long value)
-{
-#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
-
- if (id == SPANPARAM_PAN && value >= -256 && value <= 256)
- sampinfo->pan = value * (1.0f / 256.0f);
-
-#undef sampinfo
-}
-
-
-
-static long stereopan_render_samples(
- void *sampinfo,
- float volume, float delta,
- long size, sample_t **samples
-)
-{
-#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
-
- if (!sampinfo->stereo)
- return duh_signal_render_samples(sampinfo->csampinfo, volume, delta, size, samples);
-
- if (sampinfo->pan >= 0) {
- long sz = duh_signal_render_samples(sampinfo->csampinfo, volume * (1.0f + sampinfo->pan), delta, size, samples + 1);
- long s;
- int vol;
-
- volume = (1.0f - sampinfo->pan) / (1.0f + sampinfo->pan);
- vol = (int)(volume * 65536 + 0.5);
-
- for (s = 0; s < sz; s++)
- samples[0][s] = (samples[1][s] * vol) >> 16;
-
- return sz;
- } else {
- long sz = duh_signal_render_samples(sampinfo->csampinfo, volume * (1.0f - sampinfo->pan), delta, size, samples);
- long s;
- int vol;
-
- volume = (1.0f + sampinfo->pan) / (1.0f - sampinfo->pan);
- vol = (int)(volume * 65536 + 0.5);
-
- for (s = 0; s < sz; s++)
- samples[1][s] = (samples[0][s] * vol) >> 16;
-
- return sz;
- }
-
-#undef sampinfo
-}
-
-
-
-static void stereopan_end_samples(void *sampinfo)
-{
-#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo)
-
- duh_signal_end_samples(sampinfo->csampinfo);
- free(sampinfo);
-
-#undef sampinfo
-}
-
-
-
-static void stereopan_unload_signal(void *signal)
-{
- free(signal);
-}
-
-
-
-static DUH_SIGTYPE_DESC sigtype_stereopan = {
- SIGTYPE_STEREOPAN,
- &stereopan_load_signal,
- &stereopan_start_samples,
- &stereopan_set_parameter,
- &stereopan_render_samples,
- &stereopan_end_samples,
- &stereopan_unload_signal
-};
-
-
-
-void dumb_register_sigtype_stereopan(void)
-{
- dumb_register_sigtype(&sigtype_stereopan);
-}
+/* _______ ____ __ ___ ___ + * \ _ \ \ / \ / \ \ / / ' ' ' + * | | \ \ | | || | \/ | . . + * | | | | | | || ||\ /| | + * | | | | | | || || \/ | | ' ' ' + * | | | | | | || || | | . . + * | |_/ / \ \__// || | | + * /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque + * / \ + * / . \ + * sterpan.c - The stereo pan (SPAN) signal type. / / \ \ + * | < / \_ + * By entheh. | \/ /\ / + * \_ / > / + * This takes a single monaural signal and | \ / / + * expands it to two channels, applying a | ' / + * stereo pan in the process. The stereo pan \__/ + * is generated by delaying and damping the + * channel opposite the sound source. If only + * one channel is requested of this signal, it will simply chain to the other + * signal. + * + * In order for the delay to work properly, this must be played at 65536 Hz. + * The pitch at which you want the sample to play can be passed in parameter + * #1. Parameter #0 specifies the panning position, -256 to 256. + * + * NOTE: THIS IS NOT HOW IT WORKS AT THE MOMENT. AT THE MOMENT, THIS ROUTINE + * SIMPLY VARIES THE VOLUMES. + */ + +#include <stdlib.h> + +#include "dumb.h" + + + +#define SIGTYPE_STEREOPAN DUMB_ID('S','P','A','N') + + + +#define SPANPARAM_PAN 0 + + + +typedef struct STEREOPAN_SIGNAL +{ + int sig; +} +STEREOPAN_SIGNAL; + + + +typedef struct STEREOPAN_SAMPINFO +{ + float pan; + int stereo; + DUH_SIGNAL_SAMPINFO *csampinfo; +} +STEREOPAN_SAMPINFO; + + + +static void *stereopan_load_signal(DUH *duh, DUMBFILE *file) +{ + STEREOPAN_SIGNAL *signal; + + (void)duh; + + signal = malloc(sizeof(*signal)); + + if (!signal) + return NULL; + + signal->sig = dumbfile_igetl(file); + + if (dumbfile_error(file)) { + free(signal); + return NULL; + } + + return signal; +} + + + +static void *stereopan_start_samples(DUH *duh, void *signal, int n_channels, long pos) +{ + STEREOPAN_SAMPINFO *sampinfo; + +#define signal ((STEREOPAN_SIGNAL *)signal) + + if ((unsigned int)(n_channels - 1) >= 2) { + TRACE("Stereo pan signal requiring 1 or 2 channels called with %d channels.\n", n_channels); + return NULL; + } + + sampinfo = malloc(sizeof(*sampinfo)); + if (!sampinfo) + return NULL; + + sampinfo->pan = 0; + + sampinfo->stereo = n_channels - 1; + + sampinfo->csampinfo = duh_signal_start_samples(duh, signal->sig, 1, pos); + if (!sampinfo->csampinfo) { + free(sampinfo); + return NULL; + } + +#undef signal + + return sampinfo; +} + + + +static void stereopan_set_parameter(void *sampinfo, unsigned char id, long value) +{ +#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo) + + if (id == SPANPARAM_PAN && value >= -256 && value <= 256) + sampinfo->pan = value * (1.0f / 256.0f); + +#undef sampinfo +} + + + +static long stereopan_render_samples( + void *sampinfo, + float volume, float delta, + long size, sample_t **samples +) +{ +#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo) + + if (!sampinfo->stereo) + return duh_signal_render_samples(sampinfo->csampinfo, volume, delta, size, samples); + + if (sampinfo->pan >= 0) { + long sz = duh_signal_render_samples(sampinfo->csampinfo, volume * (1.0f + sampinfo->pan), delta, size, samples + 1); + long s; + int vol; + + volume = (1.0f - sampinfo->pan) / (1.0f + sampinfo->pan); + vol = (int)(volume * 65536 + 0.5); + + for (s = 0; s < sz; s++) + samples[0][s] = (samples[1][s] * vol) >> 16; + + return sz; + } else { + long sz = duh_signal_render_samples(sampinfo->csampinfo, volume * (1.0f - sampinfo->pan), delta, size, samples); + long s; + int vol; + + volume = (1.0f + sampinfo->pan) / (1.0f - sampinfo->pan); + vol = (int)(volume * 65536 + 0.5); + + for (s = 0; s < sz; s++) + samples[1][s] = (samples[0][s] * vol) >> 16; + + return sz; + } + +#undef sampinfo +} + + + +static void stereopan_end_samples(void *sampinfo) +{ +#define sampinfo ((STEREOPAN_SAMPINFO *)sampinfo) + + duh_signal_end_samples(sampinfo->csampinfo); + free(sampinfo); + +#undef sampinfo +} + + + +static void stereopan_unload_signal(void *signal) +{ + free(signal); +} + + + +static DUH_SIGTYPE_DESC sigtype_stereopan = { + SIGTYPE_STEREOPAN, + &stereopan_load_signal, + &stereopan_start_samples, + &stereopan_set_parameter, + &stereopan_render_samples, + &stereopan_end_samples, + &stereopan_unload_signal +}; + + + +void dumb_register_sigtype_stereopan(void) +{ + dumb_register_sigtype(&sigtype_stereopan); +} diff --git a/plugins/dumb/dumb-kode54/src/tools/it/load_it.cpp b/plugins/dumb/dumb-kode54/src/tools/it/load_it.cpp index ed88e706..bc749cb5 100644 --- a/plugins/dumb/dumb-kode54/src/tools/it/load_it.cpp +++ b/plugins/dumb/dumb-kode54/src/tools/it/load_it.cpp @@ -1,824 +1,824 @@ -#ifdef FORTIFY
-#include "fortify.h"
-#endif
-#include <stdio.h>
-#ifdef MSS
-#include "mss.h"
-#endif
-
-#include <string.h>
-
-#include "allegro.h"
-#include "modulus.h"
-#include "typedef.hpp"
-
-int detect_it(char *f) {
- int sig;
- PACKFILE *fn = pack_fopen(f, "rb");
-
- if (fn == NULL)
- return FALSE;
-
- sig = pack_mgetl(fn);
- if (sig != AL_ID('I','M','P','M')) {
- pack_fclose(fn);
- return FALSE;
- }
- pack_fclose(fn);
-
- return TRUE;
-}
-
-MODULUS *create_it() {
- MODULUS *m = (MODULUS*)malloc(sizeof(MODULUS));
- if (!m)
- return NULL;
- memset(m, 0, sizeof(MODULUS));
- return m;
-}
-
-void destroy_it(MODULUS *j) {
-
- if (song->Music == j)
- stop_it();
-
- //remove patterns:
- for (int i=0; i<j->NumPatterns; i++) {
- free(j->Pattern[i].Note);
- }
- if (j->Pattern)
- free(j->Pattern);
- //remove instruments;
- if (j->Instrument)
- free(j->Instrument);
- //remove samples;
- for (int i=0; i<j->NumSamples; i++) {
- destroy_sample(j->Sample[i].Sample);
- }
- if (j->Sample)
- free(j->Sample);
- //remove orders:
- if (j->Order)
- free(j->Order);
- //remove channels:
- for (int i=0; i<64; i++) {
- if (j->Channel[i].VChannel) {
- MODULUS_VCHANNEL *vchn = song->Music->Channel[i].VChannel;
- MODULUS_VCHANNEL *prev = NULL;
-
- if (!vchn)
- continue;
-
- for (;;) {
- deallocate_voice(vchn->voice);
-
- prev = vchn;
- vchn = vchn->next;
- free(prev);
-
- if (!vchn)
- break;
- }
- }
- }
- free(j);
-}
-
-//#define DEBUG_IT_SIZE
-
-int get_module_size(MODULUS *j) {
- int a, b, c, d = 0, e;
- a = sizeof(MODULUS) + j->NumOrders;
- b = j->NumInstruments * sizeof(MODULUS_INSTRUMENT);
- c = j->NumSamples * sizeof(MODULUS_SAMPLE);
-
- for (int i=0; i<j->NumSamples; i++)
- d += j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
-
- e = 4 + sizeof(MODULUS_PATTERN) * j->NumPatterns;
-
- for (int i=0; i<j->NumPatterns; i++)
- e += j->Pattern[i].NumNotes * sizeof(MODULUS_NOTE);
- #ifdef DEBUG_IT_SIZE
- printf("Base: %i, Instruments(%i): %i, Samples(%i): %i, Data: %i, Patterns(%i): %i\n", a, j->NumInstruments, b, j->NumSamples, c, d, j->NumPatterns, e);
- #endif
-
- return a+b+c+d+e;
-}
-
-#define MAX_IT_CHN 64
-
-//#define DEBUG_HEADER
-//#define DEBUG_INSTRUMENTS
-//#define DEBUG_SAMPLES
-//#define DEBUG_PATTERNS
-
-static dword *sourcebuf = NULL;
-static dword *sourcepos = NULL;
-static byte rembits = 0;
-
-int readblock(PACKFILE *f) {
- long size;
- int c = pack_igetw(f);
- if (c == -1)
- return 0;
- size = c;
-
- sourcebuf = (dword*)malloc(size+4);
- if (!sourcebuf)
- return 0;
-
- c = pack_fread(sourcebuf, size, f);
- if (c < 1) {
- free(sourcebuf);
- sourcebuf = NULL;
- return 0;
- }
- sourcepos = sourcebuf;
- rembits = 32;
- return 1;
-}
-
-void freeblock() {
- if (sourcebuf)
- free(sourcebuf);
- sourcebuf = NULL;
-}
-
-dword readbits(char b) {
- dword val;
- if (b <= rembits) {
- val = *sourcepos & ((1 << b) - 1);
- *sourcepos >>= b;
- rembits -= b;
- }
- else {
- dword nbits = b - rembits;
- val = *sourcepos;
- sourcepos++;
- val |= ((*sourcepos & ((1 << nbits) - 1)) << rembits);
- *sourcepos >>= nbits;
- rembits = 32 - nbits;
- }
- return val;
-}
-
-void decompress8(PACKFILE *f, void *data, int len, int tver) {
- char *destbuf = (char*)data;
- char *destpos = destbuf;
- int blocklen, blockpos;
- byte bitwidth;
- word val;
- char d1, d2;
-
- memset(destbuf, 0, len);
-
- while (len>0) {
- //Read a block of compressed data:
- if (!readblock(f))
- return;
- //Set up a few variables
- blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes
- blockpos = 0;
- bitwidth = 9;
- d1 = d2 = 0;
- //Start the decompression:
- while (blockpos < blocklen) {
- //Read a value:
- val = readbits(bitwidth);
- //Check for bit width change:
-
- if (bitwidth < 7) { //Method 1:
- if (val == (1 << (bitwidth - 1))) {
- val = readbits(3) + 1;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth < 9) { //Method 2
- byte border = (0xFF >> (9 - bitwidth)) - 4;
-
- if (val > border && val <= (border + 8)) {
- val -= border;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth == 9) { //Method 3
- if (val & 0x100) {
- bitwidth = (val + 1) & 0xFF;
- continue;
- }
- }
- else { //Illegal width, abort ?
- freeblock();
- return;
- }
-
- //Expand the value to signed byte:
- char v; //The sample value:
- if (bitwidth < 8) {
- byte shift = 8 - bitwidth;
- v = (val << shift);
- v >>= shift;
- }
- else
- v = (char)val;
-
- //And integrate the sample value
- //(It always has to end with integration doesn't it ? ;-)
- d1 += v;
- d2 += d1;
-
- //Store !
- *destpos = ((tver == 0x215) ? d2 : d1);
- destpos++;
- blockpos++;
- }
- freeblock();
- len -= blocklen;
- }
- return;
-}
-
-void decompress16(PACKFILE *f, void *data, int len, int tver) {
- //make the output buffer:
- short *destbuf = (short*)data;
- short *destpos = destbuf;
- int blocklen, blockpos;
- byte bitwidth;
- long val;
- short d1, d2;
-
- memset(destbuf, 0, len);
-
- while (len>0) {
- //Read a block of compressed data:
- if (!readblock(f))
- return;
- //Set up a few variables
- blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes
- blockpos = 0;
- bitwidth = 17;
- d1 = d2 = 0;
- //Start the decompression:
- while (blockpos < blocklen) {
- val = readbits(bitwidth);
- //Check for bit width change:
-
- if (bitwidth < 7) { //Method 1:
- if (val == (1 << (bitwidth - 1))) {
- val = readbits(4) + 1;
- bitwidth = (val < bitwidth) ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth < 17) { //Method 2
- word border = (0xFFFF >> (17 - bitwidth)) - 8;
-
- if (val > border && val <= (border + 16)) {
- val -= border;
- bitwidth = val < bitwidth ? val : val + 1;
- continue;
- }
- }
- else if (bitwidth == 17) { //Method 3
- if (val & 0x10000) {
- bitwidth = (val + 1) & 0xFF;
- continue;
- }
- }
- else { //Illegal width, abort ?
- freeblock();
- return;
- }
-
- //Expand the value to signed byte:
- short v; //The sample value:
- if (bitwidth < 16) {
- byte shift = 16 - bitwidth;
- v = (val << shift);
- v >>= shift;
- }
- else
- v = (short)val;
-
- //And integrate the sample value
- //(It always has to end with integration doesn't it ? ;-)
- d1 += v;
- d2 += d1;
-
- //Store !
- *destpos = ((tver == 0x215) ? d2 : d1);
- destpos++;
- blockpos++;
- }
- freeblock();
- len -= blocklen;
- }
- return;
-}
-
-MODULUS *load_it(char *file) {
- PACKFILE *f;
- MODULUS *j = create_it();
- int tver, tver2, flag, msglen, msgoffs;
- int *insoffs = NULL, *samoffs = NULL, *patoffs = NULL;
-
- if (!j)
- return NULL;
-
- if (!detect_it(file))
- return NULL;
-
- f = pack_fopen(file, "rb");
-
- if (!f) {
- #ifdef DEBUG_HEADER
- printf("Error Opening!\n");
- #endif
- return NULL;
- }
-
- pack_fseek(f, 30);
- pack_igetw(f); //I have no idea...
-
- j->NumOrders = pack_igetw(f);
- j->NumInstruments = pack_igetw(f);
- j->NumSamples = pack_igetw(f);
- j->NumPatterns = pack_igetw(f);
-
- #ifdef DEBUG_HEADER
- printf("Loading IT: %i Orders %i Instruments, %i Samples, %i Patterns\n", j->NumOrders, j->NumInstruments, j->NumSamples, j->NumPatterns);
- #endif
-
- tver = pack_igetw(f);
- j->Version = tver2 = pack_igetw(f);
-
- #ifdef DEBUG_HEADER
- printf("Tracker ver: %X, %X\n", tver, tver2);
- #endif
-
- j->Flags = pack_igetw(f);
- flag = pack_igetw(f);
-
- j->GlobalVolume = pack_getc(f);
- j->MixVolume = pack_getc(f);
- j->Speed = pack_getc(f);
- j->Tempo = pack_getc(f);
- j->PanningSeperation = pack_getc(f);
-
- #ifdef DEBUG_HEADER
- printf("Global Volume: %i, Mixing Volume: %i, Speed: %i, Tempo: %i, PanSep: %i\n", j->GlobalVolume, j->MixVolume, j->Speed, j->Tempo, j->PanningSeperation);
- #endif
-
- pack_getc(f); //Damn....I need more info on this.
-
- msglen = pack_igetw(f);
- msgoffs = pack_igetl(f);
-
- pack_fseek(f, 4);
-
- #ifdef DEBUG_HEADER
- printf("Channel Pan:");
- #endif
-
- for (int i=0; i<MAX_IT_CHN; i++) {
- j->Channel[i].Pan = pack_getc(f);
- #ifdef DEBUG_HEADER
- printf(" %i", j->Channel[i].Pan);
- #endif
- }
- #ifdef DEBUG_HEADER
- printf("\nChannel Vol:");
- #endif
- for (int i=0; i<MAX_IT_CHN; i++) {
- j->Channel[i].Volume = pack_getc(f);
- #ifdef DEBUG_HEADER
- printf(" %i", j->Channel[i].Volume);
- #endif
- }
- #ifdef DEBUG_HEADER
- printf("\n");
- #endif
-
- j->Order = (unsigned char *)malloc(j->NumOrders);
- pack_fread(j->Order, j->NumOrders, f);
-
- if (j->NumInstruments)
- insoffs = (int*)malloc(4 * j->NumInstruments);
- if (j->NumSamples)
- samoffs = (int*)malloc(4 * j->NumSamples);
- if (j->NumPatterns)
- patoffs = (int*)malloc(4 * j->NumPatterns);
-
- pack_fread(insoffs, 4 * j->NumInstruments, f);
- pack_fread(samoffs, 4 * j->NumSamples, f);
- pack_fread(patoffs, 4 * j->NumPatterns, f);
-
- if (flag&1) { //Song message attached
- //Ignore.
- }
- if (flag & 4) { //skip something:
- short u;
- char dummy[8];
- u = pack_igetw(f);
- for (int i=0; i<u; u++)
- pack_fread(dummy, 8, f);
- }
- if (flag & 8) { //MIDI commands ???
- char dummy[33];
- for (int i=0; i<9+16+128; i++)
- pack_fread(dummy, 32, f);
-
- }
-
- if (j->NumInstruments)
- j->Instrument = (MODULUS_INSTRUMENT*)malloc(sizeof(MODULUS_INSTRUMENT) * j->NumInstruments);
- #ifdef DEBUG_INSTRUMENTS
- if (!j->Instrument)
- printf("No Mem for Instruments!\n");
- #endif
-
-
- for (int i=0; i<j->NumInstruments; i++) {
- pack_fclose(f);
- f = pack_fopen(file, "rb");
- #ifdef DEBUG_INSTRUMENTS
- if (!f)
- printf("Error Opening!\n");
- #endif
- pack_fseek(f, insoffs[i] + 17);
-
- j->Instrument[i].NewNoteAction = pack_getc(f);
- j->Instrument[i].DuplicateCheckType = pack_getc(f);
- j->Instrument[i].DuplicateCheckAction = pack_getc(f);
- j->Instrument[i].FadeOut = pack_igetw(f);
- j->Instrument[i].PitchPanSeperation = pack_getc(f);
- j->Instrument[i].PitchPanCenter = pack_getc(f);
- j->Instrument[i].GlobalVolume = pack_getc(f);
- j->Instrument[i].DefaultPan = pack_getc(f);
- #ifdef DEBUG_INSTRUMENTS
- printf("I%02i @ 0x%X, NNA %i, DCT %i, DCA %i, FO %i, PPS %i, PPC %i, GVol %i, DPan %i\n", i, insoffs[i], j->Instrument[i].NewNoteAction, j->Instrument[i].DuplicateCheckType, j->Instrument[i].DuplicateCheckAction, j->Instrument[i].FadeOut, j->Instrument[i].PitchPanSeperation, j->Instrument[i].PitchPanCenter, j->Instrument[i].GlobalVolume, j->Instrument[i].DefaultPan);
- #endif
-
- pack_fseek(f, 38);
-
- for (int k=0; k<120; k++) {
- j->Instrument[i].NoteNote[k] = pack_getc(f);
- j->Instrument[i].NoteSample[k] = pack_getc(f) - 1;
- }
-
- j->Instrument[i].VolumeEnvelope.Flag = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.NumNodes = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.LoopBegin = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.LoopEnd = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.SustainLoopBegin = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.SustainLoopEnd = pack_getc(f);
- for (int k=0; k<j->Instrument[i].VolumeEnvelope.NumNodes; k++) {
- j->Instrument[i].VolumeEnvelope.NodeY[k] = pack_getc(f);
- j->Instrument[i].VolumeEnvelope.NodeTick[k] = pack_igetw(f);
- }
- pack_fseek(f, 75 - j->Instrument[i].VolumeEnvelope.NumNodes * 3);
-
- j->Instrument[i].PanningEnvelope.Flag = pack_getc(f);
- j->Instrument[i].PanningEnvelope.NumNodes = pack_getc(f);
- j->Instrument[i].PanningEnvelope.LoopBegin = pack_getc(f);
- j->Instrument[i].PanningEnvelope.LoopEnd = pack_getc(f);
- j->Instrument[i].PanningEnvelope.SustainLoopBegin = pack_getc(f);
- j->Instrument[i].PanningEnvelope.SustainLoopEnd = pack_getc(f);
- for (int k=0; k<j->Instrument[i].PanningEnvelope.NumNodes; k++) {
- j->Instrument[i].PanningEnvelope.NodeY[k] = pack_getc(f);
- j->Instrument[i].PanningEnvelope.NodeTick[k] = pack_igetw(f);
- }
- pack_fseek(f, 75 - j->Instrument[i].PanningEnvelope.NumNodes * 3);
-
- j->Instrument[i].PitchEnvelope.Flag = pack_getc(f);
- j->Instrument[i].PitchEnvelope.NumNodes = pack_getc(f);
- j->Instrument[i].PitchEnvelope.LoopBegin = pack_getc(f);
- j->Instrument[i].PitchEnvelope.LoopEnd = pack_getc(f);
- j->Instrument[i].PitchEnvelope.SustainLoopBegin = pack_getc(f);
- j->Instrument[i].PitchEnvelope.SustainLoopEnd = pack_getc(f);
- for (int k=0; k<j->Instrument[i].PitchEnvelope.NumNodes; k++) {
- j->Instrument[i].PitchEnvelope.NodeY[k] = pack_getc(f);
- j->Instrument[i].PitchEnvelope.NodeTick[k] = pack_igetw(f);
- }
- }
-
- if (j->NumSamples)
- j->Sample = (MODULUS_SAMPLE*)malloc(sizeof(MODULUS_SAMPLE) * j->NumSamples);
-
- #ifdef DEBUG_SAMPLES
- if (!j->Sample)
- printf("No Mem for Samples!\n");
- #endif
-
- for (int i=0; i<j->NumSamples; i++) {
- int sam_samptr, convert;
-
- pack_fclose(f);
- f = pack_fopen(file, "rb");
- #ifdef DEBUG_SAMPLES
- if (!f)
- printf("Error opening!\n");
- #endif
-
- pack_fseek(f, samoffs[i] + 17);
-
- j->Sample[i].GlobalVolume = pack_getc(f);
- j->Sample[i].Flag = pack_getc(f);
- j->Sample[i].Volume = pack_getc(f);
-
- #ifdef DEBUG_SAMPLES
- printf("S%02i @ 0x%X, Vol: %i/%i, Flag: %i", i, samoffs[i], j->Sample[i].GlobalVolume, j->Sample[i].Volume, j->Sample[i].Flag);
- #endif
-
- pack_fseek(f, 26);
-
- convert = pack_getc(f);
- pack_getc(f); //Panning ?
-
- j->Sample[i].SampleLength = pack_igetl(f);
- j->Sample[i].LoopBegin = pack_igetl(f);
- j->Sample[i].LoopEnd = pack_igetl(f);
- j->Sample[i].C5Speed = pack_igetl(f);
- j->Sample[i].SustainLoopBegin = pack_igetl(f);
- j->Sample[i].SustainLoopEnd = pack_igetl(f);
-
- #ifdef DEBUG_SAMPLES
- printf(", SLen: %i, LpB: %i, LpE: %i, C5S: %i\n", j->Sample[i].SampleLength, j->Sample[i].LoopBegin, j->Sample[i].LoopEnd, j->Sample[i].C5Speed);
- #endif
-
- sam_samptr = pack_igetl(f);
-
- j->Sample[i].VibratoSpeed = pack_getc(f);
- j->Sample[i].VibratoDepth = pack_getc(f);
- j->Sample[i].VibratoRate = pack_getc(f);
- j->Sample[i].VibratoWaveForm = pack_getc(f);
-
- #ifdef DEBUG_SAMPLES
- printf("SusLpB: %i, SusLpE: %i, VibSp: %i, VibDep: %i, VibWav: %i, VibRat: %i\n", j->Sample[i].SustainLoopBegin, j->Sample[i].SustainLoopEnd, j->Sample[i].VibratoSpeed, j->Sample[i].VibratoDepth, j->Sample[i].VibratoWaveForm, j->Sample[i].VibratoRate);
- #endif
-
- if (j->Sample[i].Flag & 1 == 0)
- continue;
-
- pack_fclose(f);
- f = pack_fopen(file, "rb");
- pack_fseek(f, sam_samptr);
-
- int len = j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1);
-
- #ifdef DEBUG_SAMPLES
- printf("Len: %i, Size: %i KB\n", j->Sample[i].SampleLength, len/1024);
- #endif
-
- SAMPLE *sam = create_sample(j->Sample[i].Flag & 2 ? 16 : 8, j->Sample[i].Flag & 4 ? TRUE : FALSE, j->Sample[i].C5Speed, j->Sample[i].SampleLength);
-
- if (j->Sample[i].Flag & 8) { // If the sample is packed, then we must unpack it
- if (j->Sample[i].Flag & 2)
- decompress16(f, sam->data, j->Sample[i].SampleLength, tver2);
- else
- decompress8(f, sam->data, j->Sample[i].SampleLength, tver2);
- } else {
- pack_fread(sam->data, len, f);
- }
-
- if (j->Sample[i].Flag & SAMPLE_USELOOP) {
- sam->loop_start = j->Sample[i].LoopBegin;
- sam->loop_end = j->Sample[i].LoopEnd;
- }
-
- j->Sample[i].Sample = sam;
-
- void *dat = sam->data;
-
- if (convert & 2) { //Change the byte order for 16-bit samples:
- if (sam->bits == 16) {
- for (int k=0; k<len; k+=2) {
- int l = ((char*)dat)[k];
- ((char*)dat)[k] = ((char*)dat)[k+1];
- ((char*)dat)[k+1] = l;
-
- }
- }
- else {
- for (int k=0; k<len; k+=2) {
- int l = ((char*)dat)[k];
- ((char*)dat)[k] = ((char*)dat)[k+1];
- ((char*)dat)[k+1] = l;
-
- }
- }
- }
- if (convert & 1) { //Convert to unsigned
- if (sam->bits == 8) {
- for (int k=0; k<len; k++) {
- ((char*)dat)[k] ^= 0x80;
- }
- }
- else {
- for (int k=0; k<(len>>1); k++) {
- ((short*)dat)[k] ^= 0x8000;
- }
- }
- }
- }
-
- if (j->NumPatterns)
- j->Pattern = (MODULUS_PATTERN*)malloc(sizeof(MODULUS_PATTERN) * j->NumPatterns);
- unsigned char *buf = (unsigned char*)alloca(65536);
- unsigned char *cmask = (unsigned char*)alloca(64),
- *cnote = (unsigned char*)alloca(64),
- *cinstrument = (unsigned char*)alloca(64),
- *cvol = (unsigned char*)alloca(64),
- *ccom = (unsigned char*)alloca(64),
- *ccomval = (unsigned char*)alloca(64);
-
- for (int i=0; i<j->NumPatterns; i++) {
- int numnotes = 0, len, pos = 0, mask = 0, chn = 0;
-
- memset(cmask, 0, 64);
- memset(cnote, 0, 64);
- memset(cinstrument, 0, 64);
- memset(cvol, 0, 64);
- memset(ccom, 0, 64);
- memset(ccomval, 0, 64);
-
- pack_fclose(f);
- f = pack_fopen(file, "rb");
- pack_fseek(f, patoffs[i]);
-
- len = pack_igetw(f);
- j->Pattern[i].NumRows = pack_igetw(f);
-
- pack_fseek(f, 4);
- pack_fread(buf, len, f);
-
- while (pos < len) {
- int b = buf[pos];
- pos++;
- if (!b) { //If end of row:
- numnotes++;
- continue;
- }
- chn = (b - 1) & 63;
-
- if (b & 128) {
- mask = buf[pos];
- pos++;
- cmask[chn] = mask;
- }
- else
- mask = cmask[chn];
-
- if (mask)
- numnotes++;
- if (mask & 1)
- pos++;
- if (mask & 2)
- pos++;
- if (mask & 4)
- pos++;
- if (mask & 8)
- pos+=2; //Guessing here
- }
- j->Pattern[i].NumNotes = numnotes;
- j->Pattern[i].Note = (MODULUS_NOTE*)malloc(sizeof(MODULUS_NOTE) * numnotes);
- memset(j->Pattern[i].Note, 0, sizeof(MODULUS_NOTE) * numnotes);
-
- pos = 0;
- memset(cmask, 0, 64);
- mask = 0;
- numnotes = 0;
- while (pos < len) {
- int b = buf[pos];
- #ifdef DEBUG_PATTERNS
- printf("NumNote: %i ", numnotes);
- #endif
-
- pos++;
- if (!b) { //If end of row:
- j->Pattern[i].Note[numnotes].Channel = -1;
- numnotes++;
- #ifdef DEBUG_PATTERNS
- printf("Channel: -1\n");
- #endif
- continue;
- }
- chn = (b - 1) & 63;
-
- if (b & 128) {
- mask = buf[pos];
- pos++;
- cmask[chn] = mask;
- }
- else
- mask = cmask[chn];
- #ifdef DEBUG_PATTERNS
- printf("Channel: %i Mask: %i ", chn, mask);
- #endif
-
- if (mask)
- j->Pattern[i].Note[numnotes].Channel = chn;
-
- if (mask & 1) {
- j->Pattern[i].Note[numnotes].Note = buf[pos];
- j->Pattern[i].Note[numnotes].Mask |= 1;
- cnote[chn] = buf[pos];
- #ifdef DEBUG_PATTERNS
- printf("Note: %i ", buf[pos]);
- #endif
- pos++;
- }
- if (mask & 2) {
- j->Pattern[i].Note[numnotes].Instrument = buf[pos];
- j->Pattern[i].Note[numnotes].Mask |= 2;
- cinstrument[chn] = buf[pos];
- #ifdef DEBUG_PATTERNS
- printf("Inst: %i ", buf[pos]);
- #endif
- pos++;
- }
- if (mask & 4) {
- if (buf[pos] <= 64 || (buf[pos] >= 128 && buf[pos] <= 192))
- if (buf[pos] <= 64) {
- j->Pattern[i].Note[numnotes].Volume = buf[pos];
- j->Pattern[i].Note[numnotes].Mask |= 4;
- }
- else {
- j->Pattern[i].Note[numnotes].Panning = buf[pos] - 128;
- j->Pattern[i].Note[numnotes].Mask |= 8;
- }
- #ifdef DEBUG_PATTERNS
- printf("Vol: %i ", buf[pos]);
- #endif
- cvol[chn] = buf[pos];
- pos++;
- }
- if (mask & 8) {
- j->Pattern[i].Note[numnotes].Command = buf[pos];
- j->Pattern[i].Note[numnotes].CommandValue = buf[pos+1];
- j->Pattern[i].Note[numnotes].Mask |= 16;
- ccom[chn] = buf[pos];
- ccomval[chn] = buf[pos+1];
- #ifdef DEBUG_PATTERNS
- printf("Com: %i CommArg: %i ", buf[pos], buf[pos+1]);
- #endif
- pos+=2;
- }
- if (mask & 16) {
- j->Pattern[i].Note[numnotes].Note = cnote[chn];
- j->Pattern[i].Note[numnotes].Mask |= 1;
- #ifdef DEBUG_PATTERNS
- printf("LNote: %i ", cnote[chn]);
- #endif
- }
- if (mask & 32) {
- j->Pattern[i].Note[numnotes].Instrument = cinstrument[chn];
- j->Pattern[i].Note[numnotes].Mask |= 2;
- #ifdef DEBUG_PATTERNS
- printf("LInst: %i ", cinstrument[chn]);
- #endif
- }
- if (mask & 64) {
- if (cvol[chn] <= 64 || (cvol[chn] >= 128 && cvol[chn] <= 192))
- if (cvol[chn] <= 64) {
- j->Pattern[i].Note[numnotes].Volume = cvol[chn];
- j->Pattern[i].Note[numnotes].Mask |= 4;
- }
- else {
- j->Pattern[i].Note[numnotes].Panning = cvol[chn] - 128;
- j->Pattern[i].Note[numnotes].Mask |= 8;
- }
- #ifdef DEBUG_PATTERNS
- printf("LVol: %i ", cvol[chn]);
- #endif
- }
- if (mask & 128) {
- j->Pattern[i].Note[numnotes].Command = ccom[chn];
- j->Pattern[i].Note[numnotes].CommandValue = ccomval[chn];
- j->Pattern[i].Note[numnotes].Mask |= 16;
- #ifdef DEBUG_PATTERNS
- printf("LCom: %i LComArg: %i ", ccom[chn], ccomval[chn]);
- #endif
- }
- #ifdef DEBUG_PATTERNS
- printf("\n");
- #endif
- if (mask)
- numnotes++;
- #ifdef DEBUG_PATTERNS
- rest(1000);
- #endif
- }
- }
- if (insoffs)
- free(insoffs);
- if (samoffs)
- free(samoffs);
- if (patoffs)
- free(patoffs);
-
- return j;
-}
+#ifdef FORTIFY +#include "fortify.h" +#endif +#include <stdio.h> +#ifdef MSS +#include "mss.h" +#endif + +#include <string.h> + +#include "allegro.h" +#include "modulus.h" +#include "typedef.hpp" + +int detect_it(char *f) { + int sig; + PACKFILE *fn = pack_fopen(f, "rb"); + + if (fn == NULL) + return FALSE; + + sig = pack_mgetl(fn); + if (sig != AL_ID('I','M','P','M')) { + pack_fclose(fn); + return FALSE; + } + pack_fclose(fn); + + return TRUE; +} + +MODULUS *create_it() { + MODULUS *m = (MODULUS*)malloc(sizeof(MODULUS)); + if (!m) + return NULL; + memset(m, 0, sizeof(MODULUS)); + return m; +} + +void destroy_it(MODULUS *j) { + + if (song->Music == j) + stop_it(); + + //remove patterns: + for (int i=0; i<j->NumPatterns; i++) { + free(j->Pattern[i].Note); + } + if (j->Pattern) + free(j->Pattern); + //remove instruments; + if (j->Instrument) + free(j->Instrument); + //remove samples; + for (int i=0; i<j->NumSamples; i++) { + destroy_sample(j->Sample[i].Sample); + } + if (j->Sample) + free(j->Sample); + //remove orders: + if (j->Order) + free(j->Order); + //remove channels: + for (int i=0; i<64; i++) { + if (j->Channel[i].VChannel) { + MODULUS_VCHANNEL *vchn = song->Music->Channel[i].VChannel; + MODULUS_VCHANNEL *prev = NULL; + + if (!vchn) + continue; + + for (;;) { + deallocate_voice(vchn->voice); + + prev = vchn; + vchn = vchn->next; + free(prev); + + if (!vchn) + break; + } + } + } + free(j); +} + +//#define DEBUG_IT_SIZE + +int get_module_size(MODULUS *j) { + int a, b, c, d = 0, e; + a = sizeof(MODULUS) + j->NumOrders; + b = j->NumInstruments * sizeof(MODULUS_INSTRUMENT); + c = j->NumSamples * sizeof(MODULUS_SAMPLE); + + for (int i=0; i<j->NumSamples; i++) + d += j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1); + + e = 4 + sizeof(MODULUS_PATTERN) * j->NumPatterns; + + for (int i=0; i<j->NumPatterns; i++) + e += j->Pattern[i].NumNotes * sizeof(MODULUS_NOTE); + #ifdef DEBUG_IT_SIZE + printf("Base: %i, Instruments(%i): %i, Samples(%i): %i, Data: %i, Patterns(%i): %i\n", a, j->NumInstruments, b, j->NumSamples, c, d, j->NumPatterns, e); + #endif + + return a+b+c+d+e; +} + +#define MAX_IT_CHN 64 + +//#define DEBUG_HEADER +//#define DEBUG_INSTRUMENTS +//#define DEBUG_SAMPLES +//#define DEBUG_PATTERNS + +static dword *sourcebuf = NULL; +static dword *sourcepos = NULL; +static byte rembits = 0; + +int readblock(PACKFILE *f) { + long size; + int c = pack_igetw(f); + if (c == -1) + return 0; + size = c; + + sourcebuf = (dword*)malloc(size+4); + if (!sourcebuf) + return 0; + + c = pack_fread(sourcebuf, size, f); + if (c < 1) { + free(sourcebuf); + sourcebuf = NULL; + return 0; + } + sourcepos = sourcebuf; + rembits = 32; + return 1; +} + +void freeblock() { + if (sourcebuf) + free(sourcebuf); + sourcebuf = NULL; +} + +dword readbits(char b) { + dword val; + if (b <= rembits) { + val = *sourcepos & ((1 << b) - 1); + *sourcepos >>= b; + rembits -= b; + } + else { + dword nbits = b - rembits; + val = *sourcepos; + sourcepos++; + val |= ((*sourcepos & ((1 << nbits) - 1)) << rembits); + *sourcepos >>= nbits; + rembits = 32 - nbits; + } + return val; +} + +void decompress8(PACKFILE *f, void *data, int len, int tver) { + char *destbuf = (char*)data; + char *destpos = destbuf; + int blocklen, blockpos; + byte bitwidth; + word val; + char d1, d2; + + memset(destbuf, 0, len); + + while (len>0) { + //Read a block of compressed data: + if (!readblock(f)) + return; + //Set up a few variables + blocklen = (len < 0x8000) ? len : 0x8000; //Max block length is 0x8000 bytes + blockpos = 0; + bitwidth = 9; + d1 = d2 = 0; + //Start the decompression: + while (blockpos < blocklen) { + //Read a value: + val = readbits(bitwidth); + //Check for bit width change: + + if (bitwidth < 7) { //Method 1: + if (val == (1 << (bitwidth - 1))) { + val = readbits(3) + 1; + bitwidth = (val < bitwidth) ? val : val + 1; + continue; + } + } + else if (bitwidth < 9) { //Method 2 + byte border = (0xFF >> (9 - bitwidth)) - 4; + + if (val > border && val <= (border + 8)) { + val -= border; + bitwidth = (val < bitwidth) ? val : val + 1; + continue; + } + } + else if (bitwidth == 9) { //Method 3 + if (val & 0x100) { + bitwidth = (val + 1) & 0xFF; + continue; + } + } + else { //Illegal width, abort ? + freeblock(); + return; + } + + //Expand the value to signed byte: + char v; //The sample value: + if (bitwidth < 8) { + byte shift = 8 - bitwidth; + v = (val << shift); + v >>= shift; + } + else + v = (char)val; + + //And integrate the sample value + //(It always has to end with integration doesn't it ? ;-) + d1 += v; + d2 += d1; + + //Store ! + *destpos = ((tver == 0x215) ? d2 : d1); + destpos++; + blockpos++; + } + freeblock(); + len -= blocklen; + } + return; +} + +void decompress16(PACKFILE *f, void *data, int len, int tver) { + //make the output buffer: + short *destbuf = (short*)data; + short *destpos = destbuf; + int blocklen, blockpos; + byte bitwidth; + long val; + short d1, d2; + + memset(destbuf, 0, len); + + while (len>0) { + //Read a block of compressed data: + if (!readblock(f)) + return; + //Set up a few variables + blocklen = (len < 0x4000) ? len : 0x4000; // Max block length is 0x4000 bytes + blockpos = 0; + bitwidth = 17; + d1 = d2 = 0; + //Start the decompression: + while (blockpos < blocklen) { + val = readbits(bitwidth); + //Check for bit width change: + + if (bitwidth < 7) { //Method 1: + if (val == (1 << (bitwidth - 1))) { + val = readbits(4) + 1; + bitwidth = (val < bitwidth) ? val : val + 1; + continue; + } + } + else if (bitwidth < 17) { //Method 2 + word border = (0xFFFF >> (17 - bitwidth)) - 8; + + if (val > border && val <= (border + 16)) { + val -= border; + bitwidth = val < bitwidth ? val : val + 1; + continue; + } + } + else if (bitwidth == 17) { //Method 3 + if (val & 0x10000) { + bitwidth = (val + 1) & 0xFF; + continue; + } + } + else { //Illegal width, abort ? + freeblock(); + return; + } + + //Expand the value to signed byte: + short v; //The sample value: + if (bitwidth < 16) { + byte shift = 16 - bitwidth; + v = (val << shift); + v >>= shift; + } + else + v = (short)val; + + //And integrate the sample value + //(It always has to end with integration doesn't it ? ;-) + d1 += v; + d2 += d1; + + //Store ! + *destpos = ((tver == 0x215) ? d2 : d1); + destpos++; + blockpos++; + } + freeblock(); + len -= blocklen; + } + return; +} + +MODULUS *load_it(char *file) { + PACKFILE *f; + MODULUS *j = create_it(); + int tver, tver2, flag, msglen, msgoffs; + int *insoffs = NULL, *samoffs = NULL, *patoffs = NULL; + + if (!j) + return NULL; + + if (!detect_it(file)) + return NULL; + + f = pack_fopen(file, "rb"); + + if (!f) { + #ifdef DEBUG_HEADER + printf("Error Opening!\n"); + #endif + return NULL; + } + + pack_fseek(f, 30); + pack_igetw(f); //I have no idea... + + j->NumOrders = pack_igetw(f); + j->NumInstruments = pack_igetw(f); + j->NumSamples = pack_igetw(f); + j->NumPatterns = pack_igetw(f); + + #ifdef DEBUG_HEADER + printf("Loading IT: %i Orders %i Instruments, %i Samples, %i Patterns\n", j->NumOrders, j->NumInstruments, j->NumSamples, j->NumPatterns); + #endif + + tver = pack_igetw(f); + j->Version = tver2 = pack_igetw(f); + + #ifdef DEBUG_HEADER + printf("Tracker ver: %X, %X\n", tver, tver2); + #endif + + j->Flags = pack_igetw(f); + flag = pack_igetw(f); + + j->GlobalVolume = pack_getc(f); + j->MixVolume = pack_getc(f); + j->Speed = pack_getc(f); + j->Tempo = pack_getc(f); + j->PanningSeperation = pack_getc(f); + + #ifdef DEBUG_HEADER + printf("Global Volume: %i, Mixing Volume: %i, Speed: %i, Tempo: %i, PanSep: %i\n", j->GlobalVolume, j->MixVolume, j->Speed, j->Tempo, j->PanningSeperation); + #endif + + pack_getc(f); //Damn....I need more info on this. + + msglen = pack_igetw(f); + msgoffs = pack_igetl(f); + + pack_fseek(f, 4); + + #ifdef DEBUG_HEADER + printf("Channel Pan:"); + #endif + + for (int i=0; i<MAX_IT_CHN; i++) { + j->Channel[i].Pan = pack_getc(f); + #ifdef DEBUG_HEADER + printf(" %i", j->Channel[i].Pan); + #endif + } + #ifdef DEBUG_HEADER + printf("\nChannel Vol:"); + #endif + for (int i=0; i<MAX_IT_CHN; i++) { + j->Channel[i].Volume = pack_getc(f); + #ifdef DEBUG_HEADER + printf(" %i", j->Channel[i].Volume); + #endif + } + #ifdef DEBUG_HEADER + printf("\n"); + #endif + + j->Order = (unsigned char *)malloc(j->NumOrders); + pack_fread(j->Order, j->NumOrders, f); + + if (j->NumInstruments) + insoffs = (int*)malloc(4 * j->NumInstruments); + if (j->NumSamples) + samoffs = (int*)malloc(4 * j->NumSamples); + if (j->NumPatterns) + patoffs = (int*)malloc(4 * j->NumPatterns); + + pack_fread(insoffs, 4 * j->NumInstruments, f); + pack_fread(samoffs, 4 * j->NumSamples, f); + pack_fread(patoffs, 4 * j->NumPatterns, f); + + if (flag&1) { //Song message attached + //Ignore. + } + if (flag & 4) { //skip something: + short u; + char dummy[8]; + u = pack_igetw(f); + for (int i=0; i<u; u++) + pack_fread(dummy, 8, f); + } + if (flag & 8) { //MIDI commands ??? + char dummy[33]; + for (int i=0; i<9+16+128; i++) + pack_fread(dummy, 32, f); + + } + + if (j->NumInstruments) + j->Instrument = (MODULUS_INSTRUMENT*)malloc(sizeof(MODULUS_INSTRUMENT) * j->NumInstruments); + #ifdef DEBUG_INSTRUMENTS + if (!j->Instrument) + printf("No Mem for Instruments!\n"); + #endif + + + for (int i=0; i<j->NumInstruments; i++) { + pack_fclose(f); + f = pack_fopen(file, "rb"); + #ifdef DEBUG_INSTRUMENTS + if (!f) + printf("Error Opening!\n"); + #endif + pack_fseek(f, insoffs[i] + 17); + + j->Instrument[i].NewNoteAction = pack_getc(f); + j->Instrument[i].DuplicateCheckType = pack_getc(f); + j->Instrument[i].DuplicateCheckAction = pack_getc(f); + j->Instrument[i].FadeOut = pack_igetw(f); + j->Instrument[i].PitchPanSeperation = pack_getc(f); + j->Instrument[i].PitchPanCenter = pack_getc(f); + j->Instrument[i].GlobalVolume = pack_getc(f); + j->Instrument[i].DefaultPan = pack_getc(f); + #ifdef DEBUG_INSTRUMENTS + printf("I%02i @ 0x%X, NNA %i, DCT %i, DCA %i, FO %i, PPS %i, PPC %i, GVol %i, DPan %i\n", i, insoffs[i], j->Instrument[i].NewNoteAction, j->Instrument[i].DuplicateCheckType, j->Instrument[i].DuplicateCheckAction, j->Instrument[i].FadeOut, j->Instrument[i].PitchPanSeperation, j->Instrument[i].PitchPanCenter, j->Instrument[i].GlobalVolume, j->Instrument[i].DefaultPan); + #endif + + pack_fseek(f, 38); + + for (int k=0; k<120; k++) { + j->Instrument[i].NoteNote[k] = pack_getc(f); + j->Instrument[i].NoteSample[k] = pack_getc(f) - 1; + } + + j->Instrument[i].VolumeEnvelope.Flag = pack_getc(f); + j->Instrument[i].VolumeEnvelope.NumNodes = pack_getc(f); + j->Instrument[i].VolumeEnvelope.LoopBegin = pack_getc(f); + j->Instrument[i].VolumeEnvelope.LoopEnd = pack_getc(f); + j->Instrument[i].VolumeEnvelope.SustainLoopBegin = pack_getc(f); + j->Instrument[i].VolumeEnvelope.SustainLoopEnd = pack_getc(f); + for (int k=0; k<j->Instrument[i].VolumeEnvelope.NumNodes; k++) { + j->Instrument[i].VolumeEnvelope.NodeY[k] = pack_getc(f); + j->Instrument[i].VolumeEnvelope.NodeTick[k] = pack_igetw(f); + } + pack_fseek(f, 75 - j->Instrument[i].VolumeEnvelope.NumNodes * 3); + + j->Instrument[i].PanningEnvelope.Flag = pack_getc(f); + j->Instrument[i].PanningEnvelope.NumNodes = pack_getc(f); + j->Instrument[i].PanningEnvelope.LoopBegin = pack_getc(f); + j->Instrument[i].PanningEnvelope.LoopEnd = pack_getc(f); + j->Instrument[i].PanningEnvelope.SustainLoopBegin = pack_getc(f); + j->Instrument[i].PanningEnvelope.SustainLoopEnd = pack_getc(f); + for (int k=0; k<j->Instrument[i].PanningEnvelope.NumNodes; k++) { + j->Instrument[i].PanningEnvelope.NodeY[k] = pack_getc(f); + j->Instrument[i].PanningEnvelope.NodeTick[k] = pack_igetw(f); + } + pack_fseek(f, 75 - j->Instrument[i].PanningEnvelope.NumNodes * 3); + + j->Instrument[i].PitchEnvelope.Flag = pack_getc(f); + j->Instrument[i].PitchEnvelope.NumNodes = pack_getc(f); + j->Instrument[i].PitchEnvelope.LoopBegin = pack_getc(f); + j->Instrument[i].PitchEnvelope.LoopEnd = pack_getc(f); + j->Instrument[i].PitchEnvelope.SustainLoopBegin = pack_getc(f); + j->Instrument[i].PitchEnvelope.SustainLoopEnd = pack_getc(f); + for (int k=0; k<j->Instrument[i].PitchEnvelope.NumNodes; k++) { + j->Instrument[i].PitchEnvelope.NodeY[k] = pack_getc(f); + j->Instrument[i].PitchEnvelope.NodeTick[k] = pack_igetw(f); + } + } + + if (j->NumSamples) + j->Sample = (MODULUS_SAMPLE*)malloc(sizeof(MODULUS_SAMPLE) * j->NumSamples); + + #ifdef DEBUG_SAMPLES + if (!j->Sample) + printf("No Mem for Samples!\n"); + #endif + + for (int i=0; i<j->NumSamples; i++) { + int sam_samptr, convert; + + pack_fclose(f); + f = pack_fopen(file, "rb"); + #ifdef DEBUG_SAMPLES + if (!f) + printf("Error opening!\n"); + #endif + + pack_fseek(f, samoffs[i] + 17); + + j->Sample[i].GlobalVolume = pack_getc(f); + j->Sample[i].Flag = pack_getc(f); + j->Sample[i].Volume = pack_getc(f); + + #ifdef DEBUG_SAMPLES + printf("S%02i @ 0x%X, Vol: %i/%i, Flag: %i", i, samoffs[i], j->Sample[i].GlobalVolume, j->Sample[i].Volume, j->Sample[i].Flag); + #endif + + pack_fseek(f, 26); + + convert = pack_getc(f); + pack_getc(f); //Panning ? + + j->Sample[i].SampleLength = pack_igetl(f); + j->Sample[i].LoopBegin = pack_igetl(f); + j->Sample[i].LoopEnd = pack_igetl(f); + j->Sample[i].C5Speed = pack_igetl(f); + j->Sample[i].SustainLoopBegin = pack_igetl(f); + j->Sample[i].SustainLoopEnd = pack_igetl(f); + + #ifdef DEBUG_SAMPLES + printf(", SLen: %i, LpB: %i, LpE: %i, C5S: %i\n", j->Sample[i].SampleLength, j->Sample[i].LoopBegin, j->Sample[i].LoopEnd, j->Sample[i].C5Speed); + #endif + + sam_samptr = pack_igetl(f); + + j->Sample[i].VibratoSpeed = pack_getc(f); + j->Sample[i].VibratoDepth = pack_getc(f); + j->Sample[i].VibratoRate = pack_getc(f); + j->Sample[i].VibratoWaveForm = pack_getc(f); + + #ifdef DEBUG_SAMPLES + printf("SusLpB: %i, SusLpE: %i, VibSp: %i, VibDep: %i, VibWav: %i, VibRat: %i\n", j->Sample[i].SustainLoopBegin, j->Sample[i].SustainLoopEnd, j->Sample[i].VibratoSpeed, j->Sample[i].VibratoDepth, j->Sample[i].VibratoWaveForm, j->Sample[i].VibratoRate); + #endif + + if (j->Sample[i].Flag & 1 == 0) + continue; + + pack_fclose(f); + f = pack_fopen(file, "rb"); + pack_fseek(f, sam_samptr); + + int len = j->Sample[i].SampleLength * (j->Sample[i].Flag & 2 ? sizeof(short) : 1) * (j->Sample[i].Flag & 4 ? 2: 1); + + #ifdef DEBUG_SAMPLES + printf("Len: %i, Size: %i KB\n", j->Sample[i].SampleLength, len/1024); + #endif + + SAMPLE *sam = create_sample(j->Sample[i].Flag & 2 ? 16 : 8, j->Sample[i].Flag & 4 ? TRUE : FALSE, j->Sample[i].C5Speed, j->Sample[i].SampleLength); + + if (j->Sample[i].Flag & 8) { // If the sample is packed, then we must unpack it + if (j->Sample[i].Flag & 2) + decompress16(f, sam->data, j->Sample[i].SampleLength, tver2); + else + decompress8(f, sam->data, j->Sample[i].SampleLength, tver2); + } else { + pack_fread(sam->data, len, f); + } + + if (j->Sample[i].Flag & SAMPLE_USELOOP) { + sam->loop_start = j->Sample[i].LoopBegin; + sam->loop_end = j->Sample[i].LoopEnd; + } + + j->Sample[i].Sample = sam; + + void *dat = sam->data; + + if (convert & 2) { //Change the byte order for 16-bit samples: + if (sam->bits == 16) { + for (int k=0; k<len; k+=2) { + int l = ((char*)dat)[k]; + ((char*)dat)[k] = ((char*)dat)[k+1]; + ((char*)dat)[k+1] = l; + + } + } + else { + for (int k=0; k<len; k+=2) { + int l = ((char*)dat)[k]; + ((char*)dat)[k] = ((char*)dat)[k+1]; + ((char*)dat)[k+1] = l; + + } + } + } + if (convert & 1) { //Convert to unsigned + if (sam->bits == 8) { + for (int k=0; k<len; k++) { + ((char*)dat)[k] ^= 0x80; + } + } + else { + for (int k=0; k<(len>>1); k++) { + ((short*)dat)[k] ^= 0x8000; + } + } + } + } + + if (j->NumPatterns) + j->Pattern = (MODULUS_PATTERN*)malloc(sizeof(MODULUS_PATTERN) * j->NumPatterns); + unsigned char *buf = (unsigned char*)alloca(65536); + unsigned char *cmask = (unsigned char*)alloca(64), + *cnote = (unsigned char*)alloca(64), + *cinstrument = (unsigned char*)alloca(64), + *cvol = (unsigned char*)alloca(64), + *ccom = (unsigned char*)alloca(64), + *ccomval = (unsigned char*)alloca(64); + + for (int i=0; i<j->NumPatterns; i++) { + int numnotes = 0, len, pos = 0, mask = 0, chn = 0; + + memset(cmask, 0, 64); + memset(cnote, 0, 64); + memset(cinstrument, 0, 64); + memset(cvol, 0, 64); + memset(ccom, 0, 64); + memset(ccomval, 0, 64); + + pack_fclose(f); + f = pack_fopen(file, "rb"); + pack_fseek(f, patoffs[i]); + + len = pack_igetw(f); + j->Pattern[i].NumRows = pack_igetw(f); + + pack_fseek(f, 4); + pack_fread(buf, len, f); + + while (pos < len) { + int b = buf[pos]; + pos++; + if (!b) { //If end of row: + numnotes++; + continue; + } + chn = (b - 1) & 63; + + if (b & 128) { + mask = buf[pos]; + pos++; + cmask[chn] = mask; + } + else + mask = cmask[chn]; + + if (mask) + numnotes++; + if (mask & 1) + pos++; + if (mask & 2) + pos++; + if (mask & 4) + pos++; + if (mask & 8) + pos+=2; //Guessing here + } + j->Pattern[i].NumNotes = numnotes; + j->Pattern[i].Note = (MODULUS_NOTE*)malloc(sizeof(MODULUS_NOTE) * numnotes); + memset(j->Pattern[i].Note, 0, sizeof(MODULUS_NOTE) * numnotes); + + pos = 0; + memset(cmask, 0, 64); + mask = 0; + numnotes = 0; + while (pos < len) { + int b = buf[pos]; + #ifdef DEBUG_PATTERNS + printf("NumNote: %i ", numnotes); + #endif + + pos++; + if (!b) { //If end of row: + j->Pattern[i].Note[numnotes].Channel = -1; + numnotes++; + #ifdef DEBUG_PATTERNS + printf("Channel: -1\n"); + #endif + continue; + } + chn = (b - 1) & 63; + + if (b & 128) { + mask = buf[pos]; + pos++; + cmask[chn] = mask; + } + else + mask = cmask[chn]; + #ifdef DEBUG_PATTERNS + printf("Channel: %i Mask: %i ", chn, mask); + #endif + + if (mask) + j->Pattern[i].Note[numnotes].Channel = chn; + + if (mask & 1) { + j->Pattern[i].Note[numnotes].Note = buf[pos]; + j->Pattern[i].Note[numnotes].Mask |= 1; + cnote[chn] = buf[pos]; + #ifdef DEBUG_PATTERNS + printf("Note: %i ", buf[pos]); + #endif + pos++; + } + if (mask & 2) { + j->Pattern[i].Note[numnotes].Instrument = buf[pos]; + j->Pattern[i].Note[numnotes].Mask |= 2; + cinstrument[chn] = buf[pos]; + #ifdef DEBUG_PATTERNS + printf("Inst: %i ", buf[pos]); + #endif + pos++; + } + if (mask & 4) { + if (buf[pos] <= 64 || (buf[pos] >= 128 && buf[pos] <= 192)) + if (buf[pos] <= 64) { + j->Pattern[i].Note[numnotes].Volume = buf[pos]; + j->Pattern[i].Note[numnotes].Mask |= 4; + } + else { + j->Pattern[i].Note[numnotes].Panning = buf[pos] - 128; + j->Pattern[i].Note[numnotes].Mask |= 8; + } + #ifdef DEBUG_PATTERNS + printf("Vol: %i ", buf[pos]); + #endif + cvol[chn] = buf[pos]; + pos++; + } + if (mask & 8) { + j->Pattern[i].Note[numnotes].Command = buf[pos]; + j->Pattern[i].Note[numnotes].CommandValue = buf[pos+1]; + j->Pattern[i].Note[numnotes].Mask |= 16; + ccom[chn] = buf[pos]; + ccomval[chn] = buf[pos+1]; + #ifdef DEBUG_PATTERNS + printf("Com: %i CommArg: %i ", buf[pos], buf[pos+1]); + #endif + pos+=2; + } + if (mask & 16) { + j->Pattern[i].Note[numnotes].Note = cnote[chn]; + j->Pattern[i].Note[numnotes].Mask |= 1; + #ifdef DEBUG_PATTERNS + printf("LNote: %i ", cnote[chn]); + #endif + } + if (mask & 32) { + j->Pattern[i].Note[numnotes].Instrument = cinstrument[chn]; + j->Pattern[i].Note[numnotes].Mask |= 2; + #ifdef DEBUG_PATTERNS + printf("LInst: %i ", cinstrument[chn]); + #endif + } + if (mask & 64) { + if (cvol[chn] <= 64 || (cvol[chn] >= 128 && cvol[chn] <= 192)) + if (cvol[chn] <= 64) { + j->Pattern[i].Note[numnotes].Volume = cvol[chn]; + j->Pattern[i].Note[numnotes].Mask |= 4; + } + else { + j->Pattern[i].Note[numnotes].Panning = cvol[chn] - 128; + j->Pattern[i].Note[numnotes].Mask |= 8; + } + #ifdef DEBUG_PATTERNS + printf("LVol: %i ", cvol[chn]); + #endif + } + if (mask & 128) { + j->Pattern[i].Note[numnotes].Command = ccom[chn]; + j->Pattern[i].Note[numnotes].CommandValue = ccomval[chn]; + j->Pattern[i].Note[numnotes].Mask |= 16; + #ifdef DEBUG_PATTERNS + printf("LCom: %i LComArg: %i ", ccom[chn], ccomval[chn]); + #endif + } + #ifdef DEBUG_PATTERNS + printf("\n"); + #endif + if (mask) + numnotes++; + #ifdef DEBUG_PATTERNS + rest(1000); + #endif + } + } + if (insoffs) + free(insoffs); + if (samoffs) + free(samoffs); + if (patoffs) + free(patoffs); + + return j; +} diff --git a/plugins/dumb/dumb-kode54/src/tools/it/modulus.h b/plugins/dumb/dumb-kode54/src/tools/it/modulus.h index b17d6ff6..e7fd5c91 100644 --- a/plugins/dumb/dumb-kode54/src/tools/it/modulus.h +++ b/plugins/dumb/dumb-kode54/src/tools/it/modulus.h @@ -1,193 +1,193 @@ -
-#define MUSIC_IT AL_ID('I','M','P','M')
-
-typedef struct MODULUS_MUSIC_INFO {
- char Name[29];
- int Type;
-} MODULUS_MUSIC_INFO;
-
-#define ENVELOPE_ON 1
-#define ENVELOPE_LOOP_ON 2
-#define ENVELOPE_SUSTAINLOOP 4
-
-typedef struct MODULUS_ENVELOPE {
- unsigned char Flag,
- NumNodes,
- LoopBegin, LoopEnd, SustainLoopBegin, SustainLoopEnd; //in nodes.
- char NodeY[25];
- short NodeTick[25];
-} MODULUS_ENVELOPE;
-
-typedef struct MODULUS_VENVELOPE {
- char CurNode;
- unsigned char CurTick;
- char End;
- //float CVolume;
- MODULUS_ENVELOPE *Envelope;
-} MODULUS_VENVELOPE;
-
-#define NNA_NOTECUT 1
-#define NNA_NOTECONTINUE 2
-#define NNA_NOTEOFF 3
-#define NNA_NOTEFADE 4
-
-#define DCT_OFF 0
-#define DCT_NOTE 1
-#define DCT_SAMPLE 2
-#define DCT_INSTRUMENT 3
-
-#define DCA_CUT 0
-#define DCA_NOTEOFF 1
-#define DCA_NOTEFADE 2
-
-typedef struct MOULUS_INSTRUMENT {
- unsigned char Flag;
- char VolumeLoopNodeStart, VolumeLoopNodeEnd;
- char SustainLoopNodeStart, SustainLoopNodeEnd;
- char DuplicateCheckType;
- char DuplicateCheckAction;
- char NewNoteAction;
- int FadeOut;
-
- unsigned char PitchPanSeperation, //0->64, Bit7: Don't use
- PitchPanCenter; //Note, from C-0 to B-9
- unsigned char GlobalVolume, //0->128
- DefaultPan; //0->64, Bit7: Don't use
-
-
- unsigned char NoteSample[120];
- unsigned char NoteNote[120];
-
- MODULUS_ENVELOPE VolumeEnvelope, PanningEnvelope, PitchEnvelope;
-} MODULUS_INSTRUMENT;
-
-#define SAMPLE_HASSAMPLE 1
-#define SAMPLE_16BIT 2
-#define SAMPLE_STEREO 4
-#define SAMPLE_USELOOP 16
-#define SAMPLE_USESUSTAINLOOP 32
-#define SAMPLE_PINGPONGLOOP 64
-#define SAMPLE_PINGPONGSUSTAINLOOP 128
-
-#define VIBRATO_SINE 0
-#define VIBRATO_RAMPDOWN 1
-#define VIBRATO_SQUARE 2
-#define VIBRATO_RANDOM 3
-
-typedef struct MODULUS_SAMPLE {
- unsigned char GlobalVolume; //0->64
- unsigned char Flag;
- unsigned char Volume;
- int SampleLength; //in samples, not bytes !
- int LoopBegin, LoopEnd; //in samples
- int SustainLoopBegin, SustainLoopEnd;
- int C5Speed; //Number of bytes/sec for C-5
-
- SAMPLE *Sample;
-
- char VibratoSpeed; //0->64
- char VibratoDepth; //0->64
- char VibratoWaveForm;
- char VibratoRate; //0->64
-} MODULUS_SAMPLE;
-
-typedef struct MODULUS_NOTE {
- char Mask; //If Bit0: Note, Bit1: Instrument, Bit2: Volume, Bit3: Panning, Bit4: Command
- char Channel; //if -1, then end of row.
- unsigned char Note;
- char Instrument;
- unsigned char Volume, Panning;
- unsigned char Command, CommandValue;
-} MODULUS_NOTE;
-
-typedef struct MODULUS_PATTERN {
- int NumRows;
- int NumNotes;
- MODULUS_NOTE *Note;
-} MODULUS_PATTERN;
-
-typedef struct MODULUS_VCHANNEL {
- MODULUS_SAMPLE *Sample; //NULL is unused
- char voice;
- char ChannelVolume;
- char NoteOn;
- char NNA;
- short FadeOutCount, FadeOut;
- float MixVolume, MixPan;
- MODULUS_VENVELOPE *VVolumeEnvelope, *VPanningEnvelope, *VPitchEnvelope;
- MODULUS_VCHANNEL *next, *prev;
-} MODULUS_VCHANNEL;
-
-typedef struct MODULUS_CHANNEL {
- unsigned char Volume; //0->64
- unsigned char Pan; //0->32->64, 100 = surround, Bit7: Disable
- char LastNote, LastInstrument, LastSample;
- MODULUS_VCHANNEL *VChannel;
-} MODULUS_CHANNEL;
-
-#define FLAG_STEREO 1
-#define FLAG_USEINSTRUMENTS 4
-#define FLAG_LINEARSLIDES 8
-#define FLAG_OLDEFFECT 16
-
-typedef struct MODULUS {
- MODULUS_INSTRUMENT *Instrument;
- MODULUS_SAMPLE *Sample;
- MODULUS_PATTERN *Pattern;
-
- int NumOrders;
- int NumInstruments;
- int NumSamples;
- int NumPatterns;
- int Flags;
- short Version;
- char GlobalVolume;
- char MixVolume;
- unsigned char Speed, Tempo;
- char PanningSeperation;
-
- unsigned char *Order;
-
- MODULUS_CHANNEL Channel[64];
-
-} MODULUS;
-
-#define COMMAND_SET_SONG_SPEED 1
-#define COMMAND_JUMP_TO_ORDER 2
-#define COMMAND_PATTERN_BREAK_TO_ROW 3
-#define COMMAND_SET_CHANNEL_VOLUME 13
-#define COMMAND_SET_SONG_TEMPO 20
-#define COMMAND_SET_GLOBAL_VOLUME 22
-
-typedef struct MODULUS_PLAY {
- MODULUS *Music;
- int Loop, Tick;
- int CurOrder, CurPattern, CurPos;
- int Command, CommandVal0, CommandVal1, CommandVal2;
- int pos;
-} MODULUS_PLAY;
-extern MODULUS_PLAY *song;
-
-extern int IT_Play_Method;
-
-MODULUS *load_it(char*);
-int get_module_size(MODULUS *);
-
-int play_it(MODULUS *j, int loop);
-void install_modulus();
-void set_mix_volume(int i);
-
-void stop_it();
-int is_music_done();
-void destroy_it(MODULUS *j);
-
-//Should be internal:
-extern MODULUS_PLAY *song;
-extern int note_freq[120];
-
-extern void MOD_Interrupt(...);
-extern int MOD_Poller(void*);
-
-#define IT_TIMER 0
-#define IT_POLL 1
-
+ +#define MUSIC_IT AL_ID('I','M','P','M') + +typedef struct MODULUS_MUSIC_INFO { + char Name[29]; + int Type; +} MODULUS_MUSIC_INFO; + +#define ENVELOPE_ON 1 +#define ENVELOPE_LOOP_ON 2 +#define ENVELOPE_SUSTAINLOOP 4 + +typedef struct MODULUS_ENVELOPE { + unsigned char Flag, + NumNodes, + LoopBegin, LoopEnd, SustainLoopBegin, SustainLoopEnd; //in nodes. + char NodeY[25]; + short NodeTick[25]; +} MODULUS_ENVELOPE; + +typedef struct MODULUS_VENVELOPE { + char CurNode; + unsigned char CurTick; + char End; + //float CVolume; + MODULUS_ENVELOPE *Envelope; +} MODULUS_VENVELOPE; + +#define NNA_NOTECUT 1 +#define NNA_NOTECONTINUE 2 +#define NNA_NOTEOFF 3 +#define NNA_NOTEFADE 4 + +#define DCT_OFF 0 +#define DCT_NOTE 1 +#define DCT_SAMPLE 2 +#define DCT_INSTRUMENT 3 + +#define DCA_CUT 0 +#define DCA_NOTEOFF 1 +#define DCA_NOTEFADE 2 + +typedef struct MOULUS_INSTRUMENT { + unsigned char Flag; + char VolumeLoopNodeStart, VolumeLoopNodeEnd; + char SustainLoopNodeStart, SustainLoopNodeEnd; + char DuplicateCheckType; + char DuplicateCheckAction; + char NewNoteAction; + int FadeOut; + + unsigned char PitchPanSeperation, //0->64, Bit7: Don't use + PitchPanCenter; //Note, from C-0 to B-9 + unsigned char GlobalVolume, //0->128 + DefaultPan; //0->64, Bit7: Don't use + + + unsigned char NoteSample[120]; + unsigned char NoteNote[120]; + + MODULUS_ENVELOPE VolumeEnvelope, PanningEnvelope, PitchEnvelope; +} MODULUS_INSTRUMENT; + +#define SAMPLE_HASSAMPLE 1 +#define SAMPLE_16BIT 2 +#define SAMPLE_STEREO 4 +#define SAMPLE_USELOOP 16 +#define SAMPLE_USESUSTAINLOOP 32 +#define SAMPLE_PINGPONGLOOP 64 +#define SAMPLE_PINGPONGSUSTAINLOOP 128 + +#define VIBRATO_SINE 0 +#define VIBRATO_RAMPDOWN 1 +#define VIBRATO_SQUARE 2 +#define VIBRATO_RANDOM 3 + +typedef struct MODULUS_SAMPLE { + unsigned char GlobalVolume; //0->64 + unsigned char Flag; + unsigned char Volume; + int SampleLength; //in samples, not bytes ! + int LoopBegin, LoopEnd; //in samples + int SustainLoopBegin, SustainLoopEnd; + int C5Speed; //Number of bytes/sec for C-5 + + SAMPLE *Sample; + + char VibratoSpeed; //0->64 + char VibratoDepth; //0->64 + char VibratoWaveForm; + char VibratoRate; //0->64 +} MODULUS_SAMPLE; + +typedef struct MODULUS_NOTE { + char Mask; //If Bit0: Note, Bit1: Instrument, Bit2: Volume, Bit3: Panning, Bit4: Command + char Channel; //if -1, then end of row. + unsigned char Note; + char Instrument; + unsigned char Volume, Panning; + unsigned char Command, CommandValue; +} MODULUS_NOTE; + +typedef struct MODULUS_PATTERN { + int NumRows; + int NumNotes; + MODULUS_NOTE *Note; +} MODULUS_PATTERN; + +typedef struct MODULUS_VCHANNEL { + MODULUS_SAMPLE *Sample; //NULL is unused + char voice; + char ChannelVolume; + char NoteOn; + char NNA; + short FadeOutCount, FadeOut; + float MixVolume, MixPan; + MODULUS_VENVELOPE *VVolumeEnvelope, *VPanningEnvelope, *VPitchEnvelope; + MODULUS_VCHANNEL *next, *prev; +} MODULUS_VCHANNEL; + +typedef struct MODULUS_CHANNEL { + unsigned char Volume; //0->64 + unsigned char Pan; //0->32->64, 100 = surround, Bit7: Disable + char LastNote, LastInstrument, LastSample; + MODULUS_VCHANNEL *VChannel; +} MODULUS_CHANNEL; + +#define FLAG_STEREO 1 +#define FLAG_USEINSTRUMENTS 4 +#define FLAG_LINEARSLIDES 8 +#define FLAG_OLDEFFECT 16 + +typedef struct MODULUS { + MODULUS_INSTRUMENT *Instrument; + MODULUS_SAMPLE *Sample; + MODULUS_PATTERN *Pattern; + + int NumOrders; + int NumInstruments; + int NumSamples; + int NumPatterns; + int Flags; + short Version; + char GlobalVolume; + char MixVolume; + unsigned char Speed, Tempo; + char PanningSeperation; + + unsigned char *Order; + + MODULUS_CHANNEL Channel[64]; + +} MODULUS; + +#define COMMAND_SET_SONG_SPEED 1 +#define COMMAND_JUMP_TO_ORDER 2 +#define COMMAND_PATTERN_BREAK_TO_ROW 3 +#define COMMAND_SET_CHANNEL_VOLUME 13 +#define COMMAND_SET_SONG_TEMPO 20 +#define COMMAND_SET_GLOBAL_VOLUME 22 + +typedef struct MODULUS_PLAY { + MODULUS *Music; + int Loop, Tick; + int CurOrder, CurPattern, CurPos; + int Command, CommandVal0, CommandVal1, CommandVal2; + int pos; +} MODULUS_PLAY; +extern MODULUS_PLAY *song; + +extern int IT_Play_Method; + +MODULUS *load_it(char*); +int get_module_size(MODULUS *); + +int play_it(MODULUS *j, int loop); +void install_modulus(); +void set_mix_volume(int i); + +void stop_it(); +int is_music_done(); +void destroy_it(MODULUS *j); + +//Should be internal: +extern MODULUS_PLAY *song; +extern int note_freq[120]; + +extern void MOD_Interrupt(...); +extern int MOD_Poller(void*); + +#define IT_TIMER 0 +#define IT_POLL 1 + |