void process_fx(struct context_data *ctx, struct channel_data *xc, int chn, uint8 note, uint8 fxt, uint8 fxp, int fnum) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct flow_control *f = &p->flow; int h, l; switch (fxt) { case FX_ARPEGGIO: fx_arpeggio: if (fxp != 0) { xc->arpeggio.val[0] = 0; xc->arpeggio.val[1] = MSN(fxp); xc->arpeggio.val[2] = LSN(fxp); xc->arpeggio.size = 3; } break; case FX_S3M_ARPEGGIO: EFFECT_MEMORY(fxp, xc->arpeggio.memory); goto fx_arpeggio; #ifndef LIBXMP_CORE_PLAYER case FX_OKT_ARP3: if (fxp != 0) { xc->arpeggio.val[0] = -MSN(fxp); xc->arpeggio.val[1] = 0; xc->arpeggio.val[2] = LSN(fxp); xc->arpeggio.size = 3; } break; case FX_OKT_ARP4: if (fxp != 0) { xc->arpeggio.val[0] = 0; xc->arpeggio.val[1] = LSN(fxp); xc->arpeggio.val[2] = 0; xc->arpeggio.val[3] = -MSN(fxp); xc->arpeggio.size = 4; } break; case FX_OKT_ARP5: if (fxp != 0) { xc->arpeggio.val[0] = LSN(fxp); xc->arpeggio.val[1] = LSN(fxp); xc->arpeggio.val[2] = 0; xc->arpeggio.size = 3; } break; #endif case FX_PORTA_UP: /* Portamento up */ EFFECT_MEMORY(fxp, xc->freq.memory); if (HAS_QUIRK(QUIRK_FINEFX) && (fnum == 0 || !HAS_QUIRK(QUIRK_ITVPOR))) { switch (MSN(fxp)) { case 0xf: fxp &= 0x0f; goto fx_f_porta_up; case 0xe: fxp &= 0x0f; fxp |= 0x10; goto fx_xf_porta; } } SET(PITCHBEND); if (fxp != 0) { xc->freq.slide = -fxp; if (HAS_QUIRK(QUIRK_UNISLD)) xc->porta.memory = fxp; } else if (xc->freq.slide > 0) { xc->freq.slide *= -1; } break; case FX_PORTA_DN: /* Portamento down */ EFFECT_MEMORY(fxp, xc->freq.memory); if (HAS_QUIRK(QUIRK_FINEFX) && (fnum == 0 || !HAS_QUIRK(QUIRK_ITVPOR))) { switch (MSN(fxp)) { case 0xf: fxp &= 0x0f; goto fx_f_porta_dn; case 0xe: fxp &= 0x0f; fxp |= 0x20; goto fx_xf_porta; } } SET(PITCHBEND); if (fxp != 0) { xc->freq.slide = fxp; if (HAS_QUIRK(QUIRK_UNISLD)) xc->porta.memory = fxp; } else if (xc->freq.slide < 0) { xc->freq.slide *= -1; } break; case FX_TONEPORTA: /* Tone portamento */ if (HAS_QUIRK(QUIRK_IGSTPOR)) { if (note == 0 && xc->porta.dir == 0) break; } if (!IS_VALID_INSTRUMENT(xc->ins)) break; do_toneporta(m, xc, note); EFFECT_MEMORY_SETONLY(fxp, xc->porta.memory); if (fxp != 0) { if (HAS_QUIRK(QUIRK_UNISLD)) /* IT compatible Gxx off */ xc->freq.memory = fxp; xc->porta.slide = fxp; } SET(TONEPORTA); break; case FX_VIBRATO: /* Vibrato */ EFFECT_MEMORY_SETONLY(fxp, xc->vibrato.memory); SET(VIBRATO); SET_LFO_NOTZERO(&xc->vibrato.lfo, LSN(fxp) << 2, MSN(fxp)); break; case FX_FINE_VIBRATO: /* Fine vibrato */ EFFECT_MEMORY_SETONLY(fxp, xc->vibrato.memory); SET(VIBRATO); SET_LFO_NOTZERO(&xc->vibrato.lfo, LSN(fxp), MSN(fxp)); break; case FX_TONE_VSLIDE: /* Toneporta + vol slide */ if (!IS_VALID_INSTRUMENT(xc->ins)) break; do_toneporta(m, xc, note); SET(TONEPORTA); goto fx_volslide; case FX_VIBRA_VSLIDE: /* Vibrato + vol slide */ SET(VIBRATO); goto fx_volslide; case FX_TREMOLO: /* Tremolo */ EFFECT_MEMORY_SETONLY(fxp, xc->tremolo.memory); SET(TREMOLO); SET_LFO_NOTZERO(&xc->tremolo.lfo, LSN(fxp), MSN(fxp)); break; case FX_SETPAN: /* Set pan */ xc->pan.val = fxp; break; case FX_OFFSET: /* Set sample offset */ SET(OFFSET); if (fxp) { xc->offset_val = xc->offset = fxp << 8; } else { xc->offset_val = xc->offset; } break; case FX_VOLSLIDE: /* Volume slide */ fx_volslide: /* S3M file volume slide note: * DFy Fine volume down by y (...) If y is 0, the command will * be treated as a volume slide up with a value of f (15). * If a DFF command is specified, the volume will be slid * up. */ if (HAS_QUIRK(QUIRK_FINEFX)) { h = MSN(fxp); l = LSN(fxp); if (l == 0xf && h != 0) { xc->vol.memory = fxp; fxp >>= 4; goto fx_f_vslide_up; } else if (h == 0xf && l != 0) { xc->vol.memory = fxp; fxp &= 0x0f; goto fx_f_vslide_dn; } }
void process_fx(struct context_data *ctx, struct channel_data *xc, int chn, struct xmp_event *e, int fnum) { struct player_data *p = &ctx->p; struct module_data *m = &ctx->m; struct xmp_module *mod = &m->mod; struct flow_control *f = &p->flow; uint8 note, fxp, fxt; int h, l; /* key_porta is IT only */ if (m->read_event_type != READ_EVENT_IT) { xc->key_porta = xc->key; } note = e->note; if (fnum == 0) { fxt = e->fxt; fxp = e->fxp; } else { fxt = e->f2t; fxp = e->f2p; } switch (fxt) { case FX_ARPEGGIO: fx_arpeggio: if (fxp != 0) { xc->arpeggio.val[0] = 0; xc->arpeggio.val[1] = MSN(fxp); xc->arpeggio.val[2] = LSN(fxp); xc->arpeggio.size = 3; } break; case FX_S3M_ARPEGGIO: EFFECT_MEMORY(fxp, xc->arpeggio.memory); goto fx_arpeggio; #ifndef LIBXMP_CORE_PLAYER case FX_OKT_ARP3: if (fxp != 0) { xc->arpeggio.val[0] = -MSN(fxp); xc->arpeggio.val[1] = 0; xc->arpeggio.val[2] = LSN(fxp); xc->arpeggio.size = 3; } break; case FX_OKT_ARP4: if (fxp != 0) { xc->arpeggio.val[0] = 0; xc->arpeggio.val[1] = LSN(fxp); xc->arpeggio.val[2] = 0; xc->arpeggio.val[3] = -MSN(fxp); xc->arpeggio.size = 4; } break; case FX_OKT_ARP5: if (fxp != 0) { xc->arpeggio.val[0] = LSN(fxp); xc->arpeggio.val[1] = LSN(fxp); xc->arpeggio.val[2] = 0; xc->arpeggio.size = 3; } break; #endif case FX_PORTA_UP: /* Portamento up */ EFFECT_MEMORY(fxp, xc->freq.memory); if (HAS_QUIRK(QUIRK_FINEFX) && (fnum == 0 || !HAS_QUIRK(QUIRK_ITVPOR))) { switch (MSN(fxp)) { case 0xf: fxp &= 0x0f; goto fx_f_porta_up; case 0xe: fxp &= 0x0f; fxp |= 0x10; goto fx_xf_porta; } } SET(PITCHBEND); if (fxp != 0) { xc->freq.slide = -fxp; if (HAS_QUIRK(QUIRK_UNISLD)) xc->porta.memory = fxp; } else if (xc->freq.slide > 0) { xc->freq.slide *= -1; } break; case FX_PORTA_DN: /* Portamento down */ EFFECT_MEMORY(fxp, xc->freq.memory); if (HAS_QUIRK(QUIRK_FINEFX) && (fnum == 0 || !HAS_QUIRK(QUIRK_ITVPOR))) { switch (MSN(fxp)) { case 0xf: fxp &= 0x0f; goto fx_f_porta_dn; case 0xe: fxp &= 0x0f; fxp |= 0x20; goto fx_xf_porta; } } SET(PITCHBEND); if (fxp != 0) { xc->freq.slide = fxp; if (HAS_QUIRK(QUIRK_UNISLD)) xc->porta.memory = fxp; } else if (xc->freq.slide < 0) { xc->freq.slide *= -1; } break; case FX_TONEPORTA: /* Tone portamento */ if (HAS_QUIRK(QUIRK_IGSTPOR)) { if (note == 0 && xc->porta.dir == 0) break; } if (!IS_VALID_INSTRUMENT(xc->ins)) break; do_toneporta(m, xc, note); EFFECT_MEMORY_SETONLY(fxp, xc->porta.memory); if (fxp != 0) { if (HAS_QUIRK(QUIRK_UNISLD)) /* IT compatible Gxx off */ xc->freq.memory = fxp; xc->porta.slide = fxp; } SET(TONEPORTA); break; case FX_VIBRATO: /* Vibrato */ EFFECT_MEMORY_SETONLY(fxp, xc->vibrato.memory); SET(VIBRATO); SET_LFO_NOTZERO(&xc->vibrato.lfo, LSN(fxp) << 2, MSN(fxp)); break; case FX_FINE_VIBRATO: /* Fine vibrato */ EFFECT_MEMORY_SETONLY(fxp, xc->vibrato.memory); SET(VIBRATO); SET_LFO_NOTZERO(&xc->vibrato.lfo, LSN(fxp), MSN(fxp)); break; case FX_TONE_VSLIDE: /* Toneporta + vol slide */ if (!IS_VALID_INSTRUMENT(xc->ins)) break; do_toneporta(m, xc, note); SET(TONEPORTA); goto fx_volslide; case FX_VIBRA_VSLIDE: /* Vibrato + vol slide */ SET(VIBRATO); goto fx_volslide; case FX_TREMOLO: /* Tremolo */ EFFECT_MEMORY_SETONLY(fxp, xc->tremolo.memory); SET(TREMOLO); SET_LFO_NOTZERO(&xc->tremolo.lfo, LSN(fxp), MSN(fxp)); break; case FX_SETPAN: /* Set pan */ /* From OpenMPT PanOff.xm: * "Another chapter of weird FT2 bugs: Note-Off + Note Delay * + Volume Column Panning = Panning effect is ignored." */ if (!HAS_QUIRK(QUIRK_FT2BUGS) /* If not FT2 */ || fnum == 0 /* or not vol column */ || e->note != XMP_KEY_OFF /* or not keyoff */ || e->fxt != FX_EXTENDED /* or not delay */ || MSN(e->fxp) != EX_DELAY) { xc->pan.val = fxp; xc->pan.surround = 0; } break; case FX_OFFSET: /* Set sample offset */ EFFECT_MEMORY(fxp, xc->offset.memory); SET(OFFSET); if (note) { xc->offset.val &= xc->offset.val & ~0xffff; xc->offset.val |= fxp << 8; xc->offset.val2 = fxp << 8; } if (e->ins) { xc->offset.val2 = fxp << 8; } break; case FX_VOLSLIDE: /* Volume slide */ fx_volslide: /* S3M file volume slide note: * DFy Fine volume down by y (...) If y is 0, the command will * be treated as a volume slide up with a value of f (15). * If a DFF command is specified, the volume will be slid * up. */ if (HAS_QUIRK(QUIRK_FINEFX)) { h = MSN(fxp); l = LSN(fxp); if (l == 0xf && h != 0) { xc->vol.memory = fxp; fxp >>= 4; goto fx_f_vslide_up; } else if (h == 0xf && l != 0) { xc->vol.memory = fxp; fxp &= 0x0f; goto fx_f_vslide_dn; } }