/* Extended Module Player * Copyright (C) 1996-1999 Claudio Matsuoka and Hipolito Carraro Jr * * This file is part of the Extended Module Player and is distributed * under the terms of the GNU General Public License. See doc/COPYING * for more information. */ /* * Sun, 31 May 1998 17:50:02 -0600 * Reported by ToyKeeper : * For loop-prevention, I know a way to do it which lets most songs play * fine once through even if they have backward-jumps. Just keep a small * array (256 bytes, or even bits) of flags, each entry determining if a * pattern in the song order has been played. If you get to an entry which * is already non-zero, skip to the next song (assuming looping is off). */ /* * Tue, 6 Oct 1998 21:23:17 +0200 (CEST) * Reported by John v/d Kamp : * scan.c was hanging when it jumps to an invalid restart value. * (Fixed by hipolito) */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "xmpi.h" #include "effects.h" #define S3M_END 0xff #define TIME 6 #define MAX_GVL 0x40 extern int xxo_fstrow[XMP_DEF_MAXORD]; extern struct xmp_ord_info xxo_info[XMP_DEF_MAXORD]; extern int xmp_scan_row, xmp_scan_ord, xmp_scan_num; int xmpi_scan_module () { int prm, gvol_slide, f1, f2, ord, ord2; int row, last_row, break_row, cnt_row; int gvl, bpm, tempo, base_time, chn; int alltmp, clock, clock_rst, medbpm; int loop_chn, loop_flg; int* loop_stk; int* loop_row; char** tab_cnt; struct xxm_event* event; medbpm = xmp_ctl->fetch & XMP_CTL_MEDBPM; tab_cnt = calloc (sizeof (char *), xxh->len); for (ord = xxh->len; ord--;) tab_cnt[ord] = calloc (1, xxo[ord] >= xxh->pat ? 1 : xxp[xxo[ord]]->rows ? xxp[xxo[ord]]->rows : 1); loop_stk = calloc (sizeof (int), xxh->chn); loop_row = calloc (sizeof (int), xxh->chn); loop_chn = loop_flg = 0; memset (xxo_fstrow, 0, XMP_DEF_MAXORD); gvl = xxh->gvl; bpm = xxh->bpm; tempo = (tempo = xmp_ctl->tempo ? xmp_ctl->tempo : xxh->tpo) ? tempo : TIME; base_time = xmp_ctl->rrate; ord2 = ord = -1; gvol_slide = break_row = cnt_row = alltmp = clock_rst = clock = 0; while (42) { if ((uint32)++ord >= xxh->len) { if ((uint32)++ord >= xxh->len) ord = ((uint32)xxh->rst > xxh->len || (uint32)xxo[xxh->rst] >= xxh->pat) ? 0 : xxh->rst; if (xxo[ord] == S3M_END) break; } if ((uint32)xxo[ord] >= xxh->pat) { if (xxo[ord] == S3M_END) ord = xxh->len; continue; } if (tab_cnt[ord][break_row]) break; xxo_info[ord].gvl = gvl; xxo_info[ord].bpm = bpm; xxo_info[ord].tempo = tempo; if (medbpm) xxo_info[ord].time = (clock + 132 * alltmp / 5 / bpm) / 10; else xxo_info[ord].time = (clock + 100 * alltmp / bpm) / 10; if (!xxo_fstrow[ord] && ord) { if (ord == xmp_ctl->start && !(xmp_ctl->fetch & XMP_CTL_LOOP)) { if (medbpm) clock_rst = clock + 132 * alltmp / 5 / bpm; else clock_rst = clock + 100 * alltmp / bpm; } xxo_fstrow[ord] = break_row; } last_row = xxp[xxo[ord]]->rows; for (row = break_row, break_row = 0; row < last_row; row++, cnt_row++) { if (!loop_flg && tab_cnt[ord][row]) { cnt_row--; goto end_module; } tab_cnt[ord][row]++; for (chn = 0; chn < xxh->chn; chn++) { event = &EVENT (xxo[ord], chn, row); f1 = event->fxt; f2 = event->f2t; if (f1 == FX_GLOBALVOL || f2 == FX_GLOBALVOL) { gvl = (f1 == FX_GLOBALVOL) ? event->fxp : event->f2p; gvl = gvl > MAX_GVL ? MAX_GVL : gvl < 0 ? 0 : gvl; } if (f1 == FX_G_VOLSLIDE || f2 == FX_G_VOLSLIDE) { prm = (f1 == FX_G_VOLSLIDE) ? event->fxp : event->f2p; if (prm) gvol_slide = MSN (prm) - LSN (prm); gvl += gvol_slide * (tempo - !(xmp_ctl->fetch & XMP_CTL_VSALL)); } if (f1 == FX_TEMPO || f2 == FX_TEMPO) { prm = (f1 == FX_TEMPO) ? event->fxp : event->f2p; alltmp += cnt_row * tempo * base_time; cnt_row = 0; if (prm) { if (prm <= 0x20) tempo = prm; else { if (medbpm) clock += 132 * alltmp / 5 / bpm; else clock += 100 * alltmp / bpm; alltmp = 0; bpm = prm; } } } if (f1 == FX_S3M_TEMPO || f2 == FX_S3M_TEMPO) { prm = (f1 == FX_S3M_TEMPO) ? event->fxp : event->f2p; alltmp += cnt_row * tempo * base_time; cnt_row = 0; tempo = prm; } if (f1 == FX_JUMP || f2 == FX_JUMP) { ord2 = ((f1 == FX_JUMP) ? event->fxp : event->f2p); last_row = 0; } if (f1 == FX_BREAK || f2 == FX_BREAK) { prm = (f1 == FX_BREAK) ? event->fxp : event->f2p; break_row = 10 * MSN (prm) + LSN (prm); last_row = 0; } if (f1 == FX_EXTENDED || f2 == FX_EXTENDED) { prm = (f1 == FX_EXTENDED) ? event->fxp : event->f2p; if ((prm >> 4) == EX_PATT_DELAY) alltmp += (prm & 0x0f) * tempo * base_time; if ((prm >> 4) == EX_PATTERN_LOOP) { if (prm &= 0x0f) { if (loop_stk[chn]) { if (--loop_stk[chn]) loop_chn = chn + 1; else { loop_flg--; if (xmp_ctl->fetch & XMP_CTL_S3MLOOP) loop_row[chn] = row + 1; } } else { if (loop_row[chn] <= row) { loop_stk[chn] = prm; loop_chn = chn + 1; loop_flg++; } } } else { loop_row[chn] = row; } } } } if (loop_chn) { row = loop_row[--loop_chn] - 1; loop_chn = 0; } } if (ord2 >= 0) { ord = --ord2; ord2 = -1; } alltmp += cnt_row * tempo * base_time; cnt_row = 0; } row = break_row; end_module: xmp_scan_num = xmp_ctl->start > ord? 0: tab_cnt[ord][row]; xmp_scan_row = row; xmp_scan_ord = ord; free (loop_row); free (loop_stk); for (ord = xxh->len; ord--; free (tab_cnt[ord])); free (tab_cnt); clock -= clock_rst; alltmp += cnt_row * tempo * base_time; if (medbpm) return (clock + 132 * alltmp / 5 / bpm) / 10; else return (clock + 100 * alltmp / bpm) / 10; }