diff --git a/dumb/include/internal/it.h b/dumb/include/internal/it.h index 74a08d56..922d9bed 100644 --- a/dumb/include/internal/it.h +++ b/dumb/include/internal/it.h @@ -412,6 +412,8 @@ struct IT_PATTERN #define IT_WAS_AN_OKT 2048 +#define IT_WAS_AN_STM 4096 + #define IT_ORDER_END 255 #define IT_ORDER_SKIP 254 @@ -465,6 +467,7 @@ struct IT_PLAYING_ENVELOPE #define IT_PLAYING_SUSTAINOFF 2 #define IT_PLAYING_FADING 4 #define IT_PLAYING_DEAD 8 +#define IT_PLAYING_REVERSE 16 struct IT_PLAYING { diff --git a/dumb/src/it/itread.c b/dumb/src/it/itread.c index 265bb03a..1f29ad4d 100644 --- a/dumb/src/it/itread.c +++ b/dumb/src/it/itread.c @@ -31,18 +31,71 @@ //#define INVESTIGATE_OLD_INSTRUMENTS - -static int it_seek(DUMBFILE *f, int32 offset) +typedef struct tdumbfile_mem_status { - int32 pos = dumbfile_pos(f); + const unsigned char * ptr; + unsigned offset, size; +} dumbfile_mem_status; - if (pos > offset) +static int dumbfile_mem_skip(void * f, int32 n) +{ + dumbfile_mem_status * s = (dumbfile_mem_status *) f; + s->offset += n; + if (s->offset > s->size) + { + s->offset = s->size; + return 1; + } + + return 0; +} + + + +static int dumbfile_mem_getc(void * f) +{ + dumbfile_mem_status * s = (dumbfile_mem_status *) f; + if (s->offset < s->size) + { + return *(s->ptr + s->offset++); + } + return -1; +} + + + +static int32 dumbfile_mem_getnc(char * ptr, int32 n, void * f) +{ + dumbfile_mem_status * s = (dumbfile_mem_status *) f; + int32 max = s->size - s->offset; + if (max > n) max = n; + if (max) + { + memcpy(ptr, s->ptr + s->offset, max); + s->offset += max; + } + return max; +} + + + +static DUMBFILE_SYSTEM mem_dfs = { + NULL, // open + &dumbfile_mem_skip, + &dumbfile_mem_getc, + &dumbfile_mem_getnc, + NULL // close +}; + + + +static int it_seek(dumbfile_mem_status * s, int32 offset) +{ + if ( (unsigned)offset > s->size ) return -1; - if (pos < offset) - if (dumbfile_skip(f, offset - pos)) - return -1; - + s->offset = offset; + return 0; } @@ -631,7 +684,7 @@ int32 _dumb_it_read_sample_data_adpcm4(IT_SAMPLE *sample, DUMBFILE *f) signed char * ptr, * end; signed char compression_table[16]; if (dumbfile_getnc(compression_table, 16, f) != 16) - return -1; + return -1; ptr = (signed char *) sample->data; delta = 0; @@ -957,13 +1010,58 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) unsigned char *buffer; + unsigned char *file_buffer = NULL; + unsigned int file_size = 0; + int block_size; + + dumbfile_mem_status memdata; + + do + { + void * temp = realloc( file_buffer, file_size + 32768 ); + if ( !temp ) + { + if ( file_buffer ) free( file_buffer ); + return NULL; + } + file_buffer = temp; + block_size = dumbfile_getnc( file_buffer + file_size, 32768, f ); + if ( block_size < 0 ) + { + free( file_buffer ); + return NULL; + } + file_size += block_size; + } + while ( block_size == 32768 ); + + memdata.ptr = file_buffer; + memdata.offset = 0; + memdata.size = file_size; + + f = dumbfile_open_ex(&memdata, &mem_dfs); + + if ( !f ) + { + free( file_buffer ); + return NULL; + } + if (dumbfile_mgetl(f) != IT_SIGNATURE) + { + dumbfile_close(f); + free(file_buffer); return NULL; + } sigdata = malloc(sizeof(*sigdata)); if (!sigdata) + { + dumbfile_close(f); + free(file_buffer); return NULL; + } sigdata->song_message = NULL; sigdata->order = NULL; @@ -1012,12 +1110,16 @@ static sigdata_t *it_load_sigdata(DUMBFILE *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); + dumbfile_close(f); + free(file_buffer); return NULL; } sigdata->order = malloc(sigdata->n_orders); if (!sigdata->order) { _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1025,6 +1127,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument)); if (!sigdata->instrument) { _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } } @@ -1033,6 +1137,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample)); if (!sigdata->sample) { _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } for (n = 0; n < sigdata->n_samples; n++) @@ -1043,6 +1149,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) sigdata->pattern = malloc(sigdata->n_patterns * sizeof(*sigdata->pattern)); if (!sigdata->pattern) { _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } for (n = 0; n < sigdata->n_patterns; n++) @@ -1055,6 +1163,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) component = malloc(769 * sizeof(*component)); if (!component) { _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1099,6 +1209,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) if (dumbfile_error(f)) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1119,6 +1231,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) if (!sigdata->midi) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; // Should we be happy with this outcome in some situations? } @@ -1127,6 +1241,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) if (dumbfile_error(f) || dumbfile_skip(f, 8*i)) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } /* Read embedded MIDI configuration */ @@ -1134,6 +1250,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) if (dumbfile_skip(f, 32*9)) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } for (i = 0; i < 16; i++) { @@ -1142,6 +1260,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) if (dumbfile_getnc(mididata, 32, f) < 32) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } sigdata->midi->SFmacroz[i] = 0; @@ -1197,12 +1317,14 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) sigdata->flags &= IT_REAL_FLAGS; - qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare); + qsort(component, n_components, sizeof(IT_COMPONENT), &it_component_compare); buffer = malloc(65536); if (!buffer) { free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1231,10 +1353,12 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) continue; } - if (it_seek(f, component[n].offset)) { + if (it_seek(&memdata, component[n].offset)) { free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1250,6 +1374,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } sigdata->song_message[message_length] = 0; @@ -1266,6 +1392,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } break; @@ -1275,6 +1403,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } break; @@ -1284,6 +1414,8 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1310,10 +1442,12 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) m = component[n].sampfirst; while (m >= 0) { - if (it_seek(f, component[m].offset)) { + if (it_seek(&memdata, component[m].offset)) { free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } @@ -1321,16 +1455,79 @@ static sigdata_t *it_load_sigdata(DUMBFILE *f) free(buffer); free(component); _dumb_it_unload_sigdata(sigdata); + dumbfile_close(f); + free(file_buffer); return NULL; } m = component[m].sampnext; } - } + } - free(buffer); + for ( n = 0; n < 10; n++ ) + { + if ( dumbfile_getc( f ) == 'X' ) + { + if ( dumbfile_getc( f ) == 'T' ) + { + if ( dumbfile_getc( f ) == 'P' ) + { + if ( dumbfile_getc( f ) == 'M' ) + { + break; + } + } + } + } + } + + if ( !dumbfile_error( f ) && n < 10 ) + { + unsigned int mptx_id = dumbfile_igetl( f ); + while ( !dumbfile_error( f ) && mptx_id != DUMB_ID('M','P','T','S') ) + { + unsigned int size = dumbfile_igetw( f ); + switch (mptx_id) + { + /* TODO: Add instrument extension readers */ + + default: + dumbfile_skip(f, size * sigdata->n_instruments); + break; + } + + mptx_id = dumbfile_igetl( f ); + } + + mptx_id = dumbfile_igetl( f ); + while ( memdata.offset < file_size ) + { + unsigned int size = dumbfile_igetw( f ); + switch (mptx_id) + { + /* TODO: Add more song extension readers */ + + case DUMB_ID('D','T','.','.'): + if ( size == 2 ) + sigdata->tempo = dumbfile_igetw( f ); + else if ( size == 4 ) + sigdata->tempo = dumbfile_igetl( f ); + break; + + default: + dumbfile_skip(f, size); + break; + } + mptx_id = dumbfile_igetl( f ); + } + } + + free(buffer); free(component); + dumbfile_close(f); + free(file_buffer); + _dumb_it_fix_invalid_orders(sigdata); return sigdata; diff --git a/dumb/src/it/itrender.c b/dumb/src/it/itrender.c index e93ea9df..4f3d50df 100644 --- a/dumb/src/it/itrender.c +++ b/dumb/src/it/itrender.c @@ -905,6 +905,15 @@ static void it_pickup_stop_at_end(DUMB_RESAMPLER *resampler, void *data) +static void it_pickup_stop_after_reverse(DUMB_RESAMPLER *resampler, void *data) +{ + (void)data; + + resampler->dir = 0; +} + + + static void it_playing_update_resamplers(IT_PLAYING *playing) { if ((playing->sample->flags & IT_SAMPLE_SUS_LOOP) && !(playing->flags & IT_PLAYING_SUSTAINOFF)) { @@ -925,8 +934,13 @@ static void it_playing_update_resamplers(IT_PLAYING *playing) playing->resampler.pickup = &it_pickup_pingpong_loop; else playing->resampler.pickup = &it_pickup_loop; - } else { - if (playing->sample->flags & IT_SAMPLE_SUS_LOOP) + } else if (playing->flags & IT_PLAYING_REVERSE) { + playing->resampler.start = 0; + playing->resampler.end = playing->sample->length; + playing->resampler.dir = -1; + playing->resampler.pickup = &it_pickup_stop_after_reverse; + } else { + if (playing->sample->flags & IT_SAMPLE_SUS_LOOP) playing->resampler.start = playing->sample->sus_loop_start; else playing->resampler.start = 0; @@ -1572,7 +1586,8 @@ static void it_note_off(IT_PLAYING *playing) static void xm_note_off(DUMB_IT_SIGDATA *sigdata, IT_CHANNEL *channel) { if (channel->playing) { - if (!(sigdata->instrument[channel->instrument-1].volume_envelope.flags & IT_ENVELOPE_ON)) + if (!channel->instrument || channel->instrument > sigdata->n_instruments || + !(sigdata->instrument[channel->instrument-1].volume_envelope.flags & IT_ENVELOPE_ON)) //if (!(entry->mask & IT_ENTRY_INSTRUMENT)) // dunno what that was there for ... channel->volume = 0; @@ -2075,7 +2090,18 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than /*if (entry->effectvalue == 255) if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data)) return 1;*/ - sigrenderer->tick = sigrenderer->speed = entry->effectvalue; + if (sigdata->flags & IT_WAS_AN_STM) + { + int n = entry->effectvalue; + if (n >= 32) + { + sigrenderer->tick = sigrenderer->speed = n; + } + } + else + { + sigrenderer->tick = sigrenderer->speed = entry->effectvalue; + } } else if ((sigdata->flags & (IT_WAS_AN_XM|IT_WAS_A_MOD)) == IT_WAS_AN_XM) { #ifdef BIT_ARRAY_BULLSHIT @@ -2255,11 +2281,11 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than playing = sigrenderer->playing[i]; if (!playing || playing->channel != channel) continue; } - if (channel->playing) { + if (playing) { if ((v & 0xF0) == 0xF0) - channel->playing->slide += (v & 15) << 4; + playing->slide += (v & 15) << 4; else if ((v & 0xF0) == 0xE0) - channel->playing->slide += (v & 15) << 2; + playing->slide += (v & 15) << 2; else if (i < 0 && sigdata->flags & IT_WAS_A_669) channel->portamento += v << 3; else if (i < 0) @@ -2582,7 +2608,7 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than } } break; - case IT_S: + case IT_S: { /* channel->lastS was set in update_pattern_variables(). */ unsigned char effectvalue = channel->lastS; @@ -2742,7 +2768,13 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than channel->playing->panbrello_depth = 0; break; case IT_S_SET_SURROUND_SOUND: - if ((effectvalue & 15) == 1) { + if ((effectvalue & 15) == 15) { + if (channel->playing && channel->playing->sample && + !(channel->playing->sample->flags & (IT_SAMPLE_LOOP | IT_SAMPLE_SUS_LOOP))) { + channel->playing->flags |= IT_PLAYING_REVERSE; + it_playing_reset_resamplers( channel->playing, channel->playing->sample->length - 1 ); + } + } else if ((effectvalue & 15) == 1) { channel->pan = IT_SURROUND; channel->truepan = channel->pan << IT_ENVELOPE_SHIFT; } @@ -4323,9 +4355,12 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) update_effects(sigrenderer); } } else { - speed0: - update_effects(sigrenderer); - update_tick_counts(sigrenderer); + if ( !(sigdata->flags & IT_WAS_AN_STM) || !(sigrenderer->tick & 15)) + { + speed0: + update_effects(sigrenderer); + update_tick_counts(sigrenderer); + } } if (sigrenderer->globalvolume == 0) { @@ -4348,7 +4383,12 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer) process_all_playing(sigrenderer); { - LONG_LONG t = sigrenderer->sub_time_left + ((LONG_LONG)TICK_TIME_DIVIDEND << 16) / sigrenderer->tempo; + LONG_LONG t = ((LONG_LONG)TICK_TIME_DIVIDEND << 16) / sigrenderer->tempo; + if ( sigrenderer->sigdata->flags & IT_WAS_AN_STM ) + { + t /= 16; + } + t += sigrenderer->sub_time_left; sigrenderer->time_left += (int)(t >> 16); sigrenderer->sub_time_left = (int)t & 65535; } diff --git a/dumb/src/it/readmod.c b/dumb/src/it/readmod.c index 15b87147..9d105f12 100644 --- a/dumb/src/it/readmod.c +++ b/dumb/src/it/readmod.c @@ -648,7 +648,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) sigdata->n_patterns = -1; - if ( !( rstrict & 2 ) ) + if ( ( rstrict & 2 ) ) { long total_sample_size; long remain; @@ -674,7 +674,7 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) } else { - for (i = 0; i < sigdata->n_orders; i++) + for (i = 0; i < 128; i++) { if (sigdata->order[i] > sigdata->n_patterns) sigdata->n_patterns = sigdata->order[i]; diff --git a/dumb/src/it/readstm.c b/dumb/src/it/readstm.c index a4b00f79..42f14e53 100644 --- a/dumb/src/it/readstm.c +++ b/dumb/src/it/readstm.c @@ -20,6 +20,7 @@ // IT_STEREO... :o #include #include +#include #include "dumb.h" #include "internal/it.h" @@ -142,9 +143,9 @@ static int it_stm_read_pattern( IT_PATTERN *pattern, DUMBFILE *f, unsigned char entry->mask |= IT_ENTRY_VOLPAN; entry->mask |= IT_ENTRY_EFFECT; switch ( entry->effect ) { - case IT_SET_SPEED: - entry->effectvalue >>= 4; - break; + case IT_SET_SPEED: + /* taken care of in the renderer */ + break; case IT_BREAK_TO_ROW: entry->effectvalue -= (entry->effectvalue >> 4) * 6; @@ -236,16 +237,17 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version) sigdata->n_samples = 31; sigdata->n_pchannels = 4; - sigdata->tempo = 125; - sigdata->mixing_volume = 48; + 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 | IT_STEREO; + sigdata->flags = IT_OLD_EFFECTS | IT_COMPATIBLE_GXX | IT_WAS_AN_S3M | IT_WAS_AN_STM | IT_STEREO; - sigdata->speed = dumbfile_getc(f) >> 4; - if ( sigdata->speed < 1 ) sigdata->speed = 1; - sigdata->n_patterns = dumbfile_getc(f); + n = dumbfile_getc(f); + if ( n < 32 ) n = 32; + sigdata->speed = n; + sigdata->n_patterns = dumbfile_getc(f); sigdata->global_volume = dumbfile_getc(f) << 1; if ( sigdata->global_volume > 128 ) sigdata->global_volume = 128; diff --git a/dumb/src/it/readxm.c b/dumb/src/it/readxm.c index b6607a24..25ca0710 100644 --- a/dumb/src/it/readxm.c +++ b/dumb/src/it/readxm.c @@ -338,7 +338,7 @@ static int it_xm_read_pattern(IT_PATTERN *pattern, DUMBFILE *f, int n_channels, static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data, int y_offset) { - int i, pos; + int i, pos, val; if (envelope->n_nodes > 12) { /* XXX @@ -355,12 +355,13 @@ static int it_xm_make_envelope(IT_ENVELOPE *envelope, const unsigned short *data 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; + val = data[pos++]; + if (val > 64) { + TRACE("XM error: out-of-range envelope node (node_y[%d]=%d)\n", i, val); + /* FT2 seems to simply clip the value */ + val = 64; } - envelope->node_y[i] = (signed char)(data[pos++] + y_offset); + envelope->node_y[i] = (signed char)(val + y_offset); } return 0; diff --git a/src/svnrevision.h b/src/svnrevision.h index 875de87e..da83b2c4 100644 --- a/src/svnrevision.h +++ b/src/svnrevision.h @@ -3,5 +3,5 @@ // This file was automatically generated by the // updaterevision tool. Do not edit by hand. -#define ZD_SVN_REVISION_STRING "4110" -#define ZD_SVN_REVISION_NUMBER 4110 +#define ZD_SVN_REVISION_STRING "4120" +#define ZD_SVN_REVISION_NUMBER 4120