mirror of
https://github.com/Fledge68/WiiFlow_Lite.git
synced 2024-11-01 17:15:06 +01:00
1709 lines
43 KiB
C
1709 lines
43 KiB
C
/*
|
|
* Copyright (c) 2002, 2003, 2004, 2005, 2007 by Christian Nowak <chnowak@web.de>
|
|
* Last update: 20th October, 2007
|
|
*/
|
|
|
|
#include "effects.h"
|
|
#include "modplay_core.h"
|
|
|
|
static u32 mod_finetunes[16] = {
|
|
|
|
7895,7941,7985,8046,8107,8169,8232,8280,
|
|
8363,8413,8463,8529,8581,8651,8723,8757
|
|
};
|
|
|
|
static u16 wavetab[4][64] = {
|
|
|
|
{ /* Sine */
|
|
(u16)0, (u16)24, (u16)49, (u16)74, (u16)97, (u16)120, (u16)141, (u16)161,
|
|
(u16)180, (u16)197, (u16)212, (u16)224, (u16)235, (u16)244, (u16)250, (u16)253,
|
|
(u16)255, (u16)253, (u16)250, (u16)244, (u16)235, (u16)224, (u16)212, (u16)197,
|
|
(u16)180, (u16)161, (u16)141, (u16)120, (u16)97, (u16)74, (u16)49, (u16)24,
|
|
(u16)0, (u16)-24, (u16)-49, (u16)-74, (u16)-97, (u16)-120,(u16)-141,(u16)-161,
|
|
(u16)-180,(u16)-197,(u16)-212,(u16)-224,(u16)-235,(u16)-244,(u16)-250,(u16)-253,
|
|
(u16)-255,(u16)-253,(u16)-250,(u16)-244,(u16)-235,(u16)-224,(u16)-212,(u16)-197,
|
|
(u16)-180,(u16)-161,(u16)-141,(u16)-120,(u16)-97, (u16)-74, (u16)-49, (u16)-24
|
|
}, { /* Ramp down */
|
|
|
|
(u16)255, (u16)247, (u16)239, (u16)231, (u16)223, (u16)215, (u16)207, (u16)199,
|
|
(u16)191, (u16)183, (u16)175, (u16)167, (u16)159, (u16)151, (u16)143, (u16)135,
|
|
(u16)127, (u16)119, (u16)111, (u16)103, (u16)95, (u16)87, (u16)79, (u16)71,
|
|
(u16)63, (u16)55, (u16)47, (u16)39, (u16)31, (u16)23, (u16)15, (u16)7,
|
|
(u16)-1, (u16)-9, (u16)-17, (u16)-25, (u16)-33, (u16)-41, (u16)-49, (u16)-57,
|
|
(u16)-65, (u16)-73, (u16)-81, (u16)-89, (u16)-97, (u16)-105,(u16)-113,(u16)-121,
|
|
(u16)-129,(u16)-137,(u16)-145,(u16)-153,(u16)-161,(u16)-169,(u16)-177,(u16)-185,
|
|
(u16)-193,(u16)-201,(u16)-209,(u16)-217,(u16)-225,(u16)-233,(u16)-241,(u16)-249
|
|
}, { /* Square wave */
|
|
|
|
(u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255,
|
|
(u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255,
|
|
(u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255,
|
|
(u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255, (u16)255,
|
|
(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,
|
|
(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,
|
|
(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,
|
|
(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255,(u16)-255
|
|
}, { /* Random */
|
|
|
|
(u16)-26, (u16)-251,(u16)-198,(u16)-46, (u16)-96, (u16)198, (u16)168, (u16)228,
|
|
(u16)-49, (u16)-153,(u16)-236,(u16)-174,(u16)-37, (u16)61, (u16)187, (u16)120,
|
|
(u16)56, (u16)-197,(u16)248, (u16)-58, (u16)-204,(u16)172, (u16)58, (u16)253,
|
|
(u16)-155,(u16)57, (u16)62, (u16)-62, (u16)60, (u16)-137,(u16)-101,(u16)-184,
|
|
(u16)66, (u16)-160,(u16)160, (u16)-29, (u16)-91, (u16)243, (u16)175, (u16)-175,
|
|
(u16)149, (u16)97, (u16)3, (u16)-113,(u16)7, (u16)249, (u16)-241,(u16)-247,
|
|
(u16)110, (u16)-180,(u16)-139,(u16)-20, (u16)246, (u16)-86, (u16)-80, (u16)-134,
|
|
(u16)219, (u16)117, (u16)-143,(u16)-226,(u16)-166,(u16)120, (u16)-47, (u16)29
|
|
}
|
|
};
|
|
|
|
|
|
/*****************************************************************************
|
|
* Pro/Soundtracker Effects *
|
|
*****************************************************************************/
|
|
|
|
|
|
/**** EFFECT_NONE */
|
|
static int effect_None_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_None_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_None_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/**** EFFECT_ST00 - Arpeggio */
|
|
static int effect_ST00_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
mod->channels[channel].effects[ecol].arpeggio_base = mod->channels[channel].st3_period;
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST00_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
u8 note, dnote;
|
|
u8 octave;
|
|
u8 semitone;
|
|
|
|
if (!mod->channels[channel].sample)
|
|
return 0;
|
|
|
|
note = mod->channels[channel].last_note;
|
|
dnote = ((note >> 4) * 12) + (note & 0x0f);
|
|
dnote += mod->channels[channel].sample->relative_note;
|
|
dnote = ((dnote / 12) << 4) | (dnote % 12);
|
|
|
|
octave = dnote >> 4;
|
|
semitone = dnote & 0x0f;
|
|
|
|
if (mod->channels[channel].effects[ecol].arpeggio_count == 0) {
|
|
|
|
MODFILE_SetNote(mod, channel,
|
|
mod->channels[channel].instrument->note[(octave << 4) | semitone],
|
|
mod->channels[channel].sample->middle_c,
|
|
mod->channels[channel].sample->finetune);
|
|
} else if (mod->channels[channel].effects[ecol].arpeggio_count == 1) {
|
|
|
|
semitone += mod->channels[channel].effects[ecol].cur_operand >> 4;
|
|
if (semitone > 11) {
|
|
|
|
semitone -= 12;
|
|
octave++;
|
|
}
|
|
MODFILE_SetNote(mod, channel,
|
|
mod->channels[channel].instrument->note[(octave << 4) | semitone],
|
|
mod->channels[channel].sample->middle_c,
|
|
mod->channels[channel].sample->finetune);
|
|
} else if (mod->channels[channel].effects[ecol].arpeggio_count == 2) {
|
|
|
|
semitone += mod->channels[channel].effects[ecol].cur_operand & 0x0f;
|
|
if (semitone > 11) {
|
|
|
|
semitone -= 12;
|
|
octave++;
|
|
}
|
|
MODFILE_SetNote(mod, channel,
|
|
mod->channels[channel].instrument->note[(octave << 4) | semitone],
|
|
mod->channels[channel].sample->middle_c,
|
|
mod->channels[channel].sample->finetune);
|
|
}
|
|
|
|
if (++mod->channels[channel].effects[ecol].arpeggio_count > 2)
|
|
mod->channels[channel].effects[ecol].arpeggio_count = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST00_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
u8 dnote, note;
|
|
|
|
if (!mod->channels[channel].sample ||
|
|
!mod->channels[channel].instrument)
|
|
return 0;
|
|
|
|
note = mod->channels[channel].last_note;
|
|
dnote = ((note >> 4) * 12) + (note & 0x0f);
|
|
dnote += mod->channels[channel].sample->relative_note;
|
|
dnote = ((dnote / 12) << 4) | (dnote % 12);
|
|
|
|
MODFILE_SetNote(mod, channel,
|
|
mod->channels[channel].instrument->note[dnote],
|
|
mod->channels[channel].sample->middle_c,
|
|
mod->channels[channel].sample->finetune);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_ST10 - Portamento Up */
|
|
static int effect_ST10_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST10_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period -= 4 * (u32)mod->channels[channel].effects[ecol].cur_operand;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST10_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_ST20 - Portamento Down */
|
|
static int effect_ST20_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST20_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period += 4 * (u32)mod->channels[channel].effects[ecol].cur_operand;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST20_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_ST30 - Tone Portamento */
|
|
static int effect_ST30_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (note->operand[ecol] == 0)
|
|
mod->channels[channel].effects[ecol].cur_operand =
|
|
mod->channels[channel].effects[ecol].toneporta_bak;
|
|
else
|
|
mod->channels[channel].effects[ecol].toneporta_bak = note->operand[ecol];
|
|
|
|
return EFFECT_DONOTCHANGEPERIOD |
|
|
EFFECT_DONOTRESETSAMPLEPOS;
|
|
}
|
|
|
|
static int effect_ST30_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
if (mod->channels[channel].st3_period > mod->channels[channel].effects[ecol].toneporta_dest) {
|
|
|
|
mod->channels[channel].st3_period -= 4 * (u32)mod->channels[channel].effects[ecol].cur_operand;
|
|
|
|
if ((mod->channels[channel].st3_period < mod->channels[channel].effects[ecol].toneporta_dest) ||
|
|
(mod->channels[channel].st3_period & 0x80000000))
|
|
mod->channels[channel].st3_period = mod->channels[channel].effects[ecol].toneporta_dest;
|
|
} else if (mod->channels[channel].st3_period < mod->channels[channel].effects[ecol].toneporta_dest) {
|
|
|
|
mod->channels[channel].st3_period += 4 * (u32)mod->channels[channel].effects[ecol].cur_operand;
|
|
|
|
if (mod->channels[channel].st3_period > mod->channels[channel].effects[ecol].toneporta_dest)
|
|
mod->channels[channel].st3_period = mod->channels[channel].effects[ecol].toneporta_dest;
|
|
}
|
|
MODFILE_SetPeriod(mod, channel, mod->channels[channel].st3_period);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST30_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_ST40 - Vibrato */
|
|
static int effect_ST40_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
u8 operand;
|
|
|
|
if (note->operand[ecol] != 0)
|
|
mod->channels[channel].effects[ecol].vibrato_bak = note->operand[ecol];
|
|
|
|
operand = mod->channels[channel].effects[ecol].vibrato_bak;
|
|
mod->channels[channel].effects[ecol].cur_operand = operand;
|
|
|
|
if (operand & 0x0f)
|
|
mod->channels[channel].effects[ecol].vibrato_depth = operand & 0x0f;
|
|
if (operand & 0xf0)
|
|
mod->channels[channel].effects[ecol].vibrato_freq = (operand >> 4) & 0x0f;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST40_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
s32 wavetabval = (s32)(s16)
|
|
wavetab[mod->channels[channel].effects[ecol].vibrato_wave & 3]
|
|
[mod->channels[channel].effects[ecol].vibrato_sintabpos];
|
|
|
|
s32 periodofs = ((s32)(wavetabval * 4 *
|
|
(s32)(s16)mod->channels[channel].effects[ecol].vibrato_depth)) >> 7;
|
|
|
|
MODFILE_SetPeriodOfs(mod, channel, periodofs);
|
|
|
|
mod->channels[channel].effects[ecol].vibrato_sintabpos += mod->channels[channel].effects[ecol].vibrato_freq;
|
|
mod->channels[channel].effects[ecol].vibrato_sintabpos &= 63;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST40_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
MODFILE_SetPeriodOfs(mod, channel, 0);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STa0 - Volume Slide */
|
|
static int effect_STa0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void doSTVolumeSlide(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->channels[channel].effects[ecol].cur_operand & 0xf0) { /* Up */
|
|
|
|
MODFILE_AddVolume(mod, channel, mod->channels[channel].effects[ecol].cur_operand >> 4);
|
|
} else
|
|
if (mod->channels[channel].effects[ecol].cur_operand & 0x0f) { /* Down */
|
|
|
|
MODFILE_SubVolume(mod, channel, mod->channels[channel].effects[ecol].cur_operand & 0x0f);
|
|
}
|
|
}
|
|
|
|
static int effect_STa0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
doSTVolumeSlide(mod, channel, ecol);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STa0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_ST50 - Tone Portamento + Volume Slide */
|
|
static int effect_ST50_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
/* effect_ST30_Start(mod, channel, ecol, note);*/
|
|
effect_STa0_Start(mod, channel, ecol, note);
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST50_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
effect_ST30_Process(mod, channel, ecol);
|
|
effect_STa0_Process(mod, channel, ecol);
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST50_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
effect_ST30_Stop(mod, channel, ecol);
|
|
effect_STa0_Stop(mod, channel, ecol);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_ST60 - Vibrato + Volume Slide */
|
|
static int effect_ST60_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
/* effect_ST40_Start(mod, channel, ecol, note);*/
|
|
effect_STa0_Start(mod, channel, ecol, note);
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST60_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
effect_ST40_Process(mod, channel, ecol);
|
|
effect_STa0_Process(mod, channel, ecol);
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST60_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
effect_ST40_Stop(mod, channel, ecol);
|
|
effect_STa0_Stop(mod, channel, ecol);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_ST70 - Tremolo */
|
|
static int effect_ST70_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
u8 operand;
|
|
|
|
if (note->operand[ecol] == 0)
|
|
mod->channels[channel].effects[ecol].cur_operand =
|
|
mod->channels[channel].effects[ecol].tremolo_bak;
|
|
else
|
|
mod->channels[channel].effects[ecol].tremolo_bak = note->operand[ecol];
|
|
|
|
operand = mod->channels[channel].effects[ecol].cur_operand;
|
|
|
|
mod->channels[channel].effects[ecol].tremolo_base = mod->channels[channel].voiceInfo.volume;
|
|
|
|
if (operand & 0x0f)
|
|
mod->channels[channel].effects[ecol].tremolo_depth = operand & 0x0f;
|
|
if (operand & 0xf0)
|
|
mod->channels[channel].effects[ecol].tremolo_freq = (operand >> 4) & 0x0f;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST70_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
u16 v;
|
|
s16 delta = wavetab[mod->channels[channel].effects[ecol].tremolo_wave & 3][mod->channels[channel].effects[ecol].tremolo_sintabpos];
|
|
delta *= mod->channels[channel].effects[ecol].tremolo_depth;
|
|
delta >>= 7;
|
|
|
|
v = mod->channels[channel].effects[ecol].tremolo_base + delta;
|
|
|
|
if (v > 64)
|
|
v = 64;
|
|
if (v & 0xff80)
|
|
v = 0;
|
|
|
|
mod->channels[channel].voiceInfo.volume = v;
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
mod->channels[channel].effects[ecol].tremolo_sintabpos += mod->channels[channel].effects[ecol].tremolo_freq;
|
|
mod->channels[channel].effects[ecol].tremolo_sintabpos &= 63;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST70_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
mod->channels[channel].voiceInfo.volume = mod->channels[channel].effects[ecol].tremolo_base;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_ST80 - Panning */
|
|
static int effect_ST80_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
mod->channels[channel].voiceInfo.panning = note->operand[ecol];
|
|
return EFFECT_DONOTCHANGEPANNING;
|
|
}
|
|
|
|
static int effect_ST80_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST80_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_ST90 - Sample Offset */
|
|
static int effect_ST90_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
/* return EFFECT_DONOTRESETSAMPLEPOS;*/
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST90_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter == 0) {
|
|
|
|
MIXER_TYPE ofs;
|
|
|
|
ofs = ((MIXER_TYPE)mod->channels[channel].effects[ecol].cur_operand) << (8 + MIXER_SHIFT);
|
|
if (ofs > ((MIXER_TYPE)mod->channels[channel].sample->sampleInfo.length) << MIXER_SHIFT)
|
|
mod->channels[channel].voiceInfo.playpos =
|
|
((MIXER_TYPE)mod->channels[channel].sample->sampleInfo.length) << MIXER_SHIFT;
|
|
else
|
|
mod->channels[channel].voiceInfo.playpos = ofs;
|
|
|
|
mod->channels[channel].voiceInfo.forward = TRUE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_ST90_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STb0 - Position Jump */
|
|
static int effect_STb0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
mod->play_position = note->operand[ecol];
|
|
mod->pattern_line = 0;
|
|
|
|
return EFFECT_DONOTADVANCEPATTERN;
|
|
}
|
|
|
|
static int effect_STb0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STb0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STc0 - Set Volume */
|
|
static int effect_STc0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (note->operand[ecol] > 64)
|
|
mod->channels[channel].voiceInfo.volume = 64;
|
|
else
|
|
mod->channels[channel].voiceInfo.volume = note->operand[ecol];
|
|
|
|
return EFFECT_DONOTCHANGEVOLUME;
|
|
}
|
|
|
|
static int effect_STc0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STc0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STd0 - Pattern Break */
|
|
static int effect_STd0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
do {
|
|
|
|
mod->play_position++;
|
|
if (mod->play_position >= mod->songlength)
|
|
mod->play_position = 0;
|
|
} while (mod->playlist[mod->play_position] >= 0xfe);
|
|
|
|
mod->pattern_line = note->operand[ecol];
|
|
|
|
return EFFECT_DONOTADVANCEPATTERN;
|
|
}
|
|
|
|
static int effect_STd0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STd0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STe1 - Fineslide Up */
|
|
static int effect_STe1_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period -= 4 * (u32)mod->channels[channel].effects[ecol].cur_operand;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe1_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe1_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STe2 - Fineslide Down */
|
|
static int effect_STe2_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period += 4 * (u32)mod->channels[channel].effects[ecol].cur_operand;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe2_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe2_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STe4 - Vibrato Control*/
|
|
static int effect_STe4_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
mod->channels[channel].effects[ecol].vibrato_wave = note->operand[ecol] & 0x07;
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe4_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe4_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STe5 - Set Finetune */
|
|
static int effect_STe5_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (mod->channels[channel].sample)
|
|
mod->channels[channel].sample->middle_c =
|
|
mod_finetunes[mod->channels[channel].effects[ecol].cur_operand & 0x0f];
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe5_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->channels[channel].sample)
|
|
mod->channels[channel].sample->middle_c =
|
|
mod_finetunes[mod->channels[channel].effects[ecol].cur_operand & 0x0f];
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe5_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STe6 - Pattern Loop */
|
|
static int effect_STe6_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
BOOL doPatternLoop = FALSE;
|
|
int retVal = 0;
|
|
|
|
if ((note->operand[ecol] & 0x0f) == 0)
|
|
mod->patternloop_to = mod->pattern_line;
|
|
else {
|
|
|
|
doPatternLoop = TRUE;
|
|
if (mod->patternloop_count == 0) {
|
|
|
|
mod->patternloop_count = note->operand[ecol] & 0x0f;
|
|
} else {
|
|
|
|
if (--mod->patternloop_count == 0)
|
|
doPatternLoop = FALSE;
|
|
}
|
|
}
|
|
|
|
if (doPatternLoop) {
|
|
|
|
mod->pattern_line = mod->patternloop_to;
|
|
retVal = EFFECT_DONOTADVANCEPATTERN;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
static int effect_STe6_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe6_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STe7 - Tremolo Control */
|
|
static int effect_STe7_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
mod->channels[channel].effects[ecol].tremolo_wave = note->operand[ecol] & 0x07;
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe7_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe7_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STe8 - Panning */
|
|
static int effect_STe8_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
mod->channels[channel].voiceInfo.panning =
|
|
((mod->channels[channel].effects[ecol].cur_operand & 0x0f) + 1) * 16;
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe8_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe8_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STe9 - Retrig Note */
|
|
static int effect_STe9_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe9_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
if ((mod->speedcounter %
|
|
(int)mod->channels[channel].effects[ecol].cur_operand) == 0)
|
|
MODFILE_TriggerNote(mod, channel,
|
|
mod->channels[channel].last_note,
|
|
mod->channels[channel].last_instrument,
|
|
0xff, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STe9_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STea - Fine Volume Up */
|
|
static int effect_STea_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
u8 operand;
|
|
|
|
operand = mod->channels[channel].effects[ecol].cur_operand;
|
|
if (operand != 0)
|
|
mod->channels[channel].effects[ecol].finevolslideup_bak = operand;
|
|
else
|
|
operand = mod->channels[channel].effects[ecol].finevolslideup_bak;
|
|
|
|
MODFILE_AddVolume(mod, channel, operand);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STea_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STea_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STeb - Fine Volume Down */
|
|
static int effect_STeb_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
u8 operand;
|
|
|
|
operand = mod->channels[channel].effects[ecol].cur_operand;
|
|
if (operand != 0)
|
|
mod->channels[channel].effects[ecol].finevolslidedown_bak = operand;
|
|
else
|
|
operand = mod->channels[channel].effects[ecol].finevolslidedown_bak;
|
|
|
|
MODFILE_SubVolume(mod, channel, operand);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STeb_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STeb_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STec - Note Cut */
|
|
static int effect_STec_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STec_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
if (mod->speedcounter == mod->channels[channel].effects[ecol].cur_operand)
|
|
mod->channels[channel].voiceInfo.volume = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STec_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STed - Note Delay */
|
|
static int effect_STed_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
mod->channels[channel].effects[ecol].notedelay_note = note;
|
|
|
|
return EFFECT_DONOTTRIGGERNOTE;
|
|
}
|
|
|
|
static int effect_STed_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
MOD_Note *note = mod->channels[channel].effects[ecol].notedelay_note;
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
if (mod->speedcounter == mod->channels[channel].effects[ecol].cur_operand) {
|
|
|
|
MODFILE_TriggerNote(mod, channel, note->note, note->instrument, note->volume, note->effect);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STed_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STee - Pattern Delay */
|
|
static int effect_STee_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STee_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter == 0) {
|
|
|
|
mod->patterndelay = mod->channels[channel].effects[ecol].cur_operand * mod->speed;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STee_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STef - Invert Loop */
|
|
static int effect_STef_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STef_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STef_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STf0 - Set Speed */
|
|
static int effect_STf0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (note->operand[ecol] > 0) {
|
|
|
|
if (note->operand[ecol] < 0x20)
|
|
mod->speed = note->operand[ecol];
|
|
else
|
|
MODFILE_SetBPM(mod, note->operand[ecol]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STf0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STf0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_STg0 - Goto Line */
|
|
static int effect_STg0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
mod->play_position = note->operand[ecol];
|
|
mod->pattern_line = note->operand[ecol + 1];
|
|
|
|
return EFFECT_DONOTADVANCEPATTERN;
|
|
}
|
|
|
|
static int effect_STg0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_STg0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Extended Module Effects *
|
|
*****************************************************************************/
|
|
|
|
/**** EFFECT_XM01 - Portamento Up */
|
|
static int effect_XM01_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (note->operand[ecol] == 0)
|
|
mod->channels[channel].effects[ecol].cur_operand =
|
|
mod->channels[channel].effects[ecol].porta_bak;
|
|
else
|
|
mod->channels[channel].effects[ecol].porta_bak = note->operand[ecol];
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XM01_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period -= 4 * (u32)mod->channels[channel].effects[ecol].cur_operand;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XM01_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_XM02 - Portamento Down */
|
|
static int effect_XM02_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (note->operand[ecol] == 0)
|
|
mod->channels[channel].effects[ecol].cur_operand =
|
|
mod->channels[channel].effects[ecol].porta_bak;
|
|
else
|
|
mod->channels[channel].effects[ecol].porta_bak = note->operand[ecol];
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XM02_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period += 4 * (u32)mod->channels[channel].effects[ecol].cur_operand;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XM02_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_XM10 - Global Volume */
|
|
static int effect_XM10_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (note->operand[ecol] > 64)
|
|
mod->cur_master_volume = 64;
|
|
else
|
|
mod->cur_master_volume = note->operand[ecol];
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XM10_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XM10_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_XM11 - Global Volume Slide */
|
|
static int effect_XM11_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (note->operand[ecol] != 0)
|
|
mod->channels[channel].effects[ecol].gvolslide_bak = note->operand[ecol];
|
|
|
|
mod->channels[channel].effects[ecol].cur_operand =
|
|
mod->channels[channel].effects[ecol].gvolslide_bak;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XM11_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
u8 operand = mod->channels[channel].effects[ecol].cur_operand;
|
|
|
|
if (operand & 0x0f) {
|
|
|
|
if ((operand & 0x0f) > mod->cur_master_volume)
|
|
mod->cur_master_volume = 0;
|
|
else
|
|
mod->cur_master_volume -= operand & 0x0f;
|
|
} else {
|
|
|
|
if ((operand >> 4) + mod->cur_master_volume > 64)
|
|
mod->cur_master_volume = 64;
|
|
else
|
|
mod->cur_master_volume += operand >> 4;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XM11_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_XM19 - Panning Slide */
|
|
static int effect_XM19_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (note->operand[ecol] != 0)
|
|
mod->channels[channel].effects[ecol].panslide_bak = note->operand[ecol];
|
|
|
|
mod->channels[channel].effects[ecol].cur_operand =
|
|
mod->channels[channel].effects[ecol].panslide_bak;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XM19_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
u8 operand = mod->channels[channel].effects[ecol].cur_operand;
|
|
|
|
if (operand & 0xf0) { /* Right */
|
|
|
|
if (mod->channels[channel].voiceInfo.panning > 255 - (operand >> 4))
|
|
mod->channels[channel].voiceInfo.panning = 255;
|
|
else
|
|
mod->channels[channel].voiceInfo.panning += operand >> 4;
|
|
} else
|
|
if (operand & 0x0f) { /* Left */
|
|
|
|
if (mod->channels[channel].voiceInfo.panning < (operand & 0x0f))
|
|
mod->channels[channel].voiceInfo.panning = 0;
|
|
else
|
|
mod->channels[channel].voiceInfo.panning -= operand & 0x0f;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XM19_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_XMa0 - Volume Slide */
|
|
static int effect_XMa0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (note->operand[ecol] != 0)
|
|
mod->channels[channel].effects[ecol].volslide_bak = note->operand[ecol];
|
|
|
|
mod->channels[channel].effects[ecol].cur_operand =
|
|
mod->channels[channel].effects[ecol].volslide_bak;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XMa0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
doSTVolumeSlide(mod, channel, ecol);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_XMa0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
* Screamtracker 3 Effects *
|
|
*****************************************************************************/
|
|
|
|
|
|
/**** EFFECT_S3Ma0 - Set Speed */
|
|
static int effect_S3Ma0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (note->operand[ecol] > 0) {
|
|
|
|
mod->speed = note->operand[ecol];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Ma0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Ma0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_S3Md0 - Volume Slide */
|
|
static int effect_S3Md0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
u8 operand;
|
|
|
|
if (note->operand[ecol] != 0)
|
|
mod->channels[channel].effects[ecol].volslide_bak = note->operand[ecol];
|
|
|
|
mod->channels[channel].effects[ecol].cur_operand = operand =
|
|
mod->channels[channel].effects[ecol].volslide_bak;
|
|
|
|
if ((operand & 0x0f) == 0x0f) { /* Fine up */
|
|
|
|
MODFILE_AddVolume(mod, channel, operand >> 4);
|
|
} else
|
|
if ((operand & 0xf0) == 0xf0) { /* Fine down */
|
|
|
|
MODFILE_SubVolume(mod, channel, operand & 0x0f);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Md0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
u8 operand = mod->channels[channel].effects[ecol].cur_operand;
|
|
|
|
if ((((operand & 0xf0) != 0xf0) &&
|
|
((operand & 0x0f) != 0x0f)) || (operand == 0xf0) || (operand == 0x0f)) {
|
|
|
|
if (mod->channels[channel].effects[ecol].cur_operand & 0x0f) { /* Down */
|
|
|
|
MODFILE_SubVolume(mod, channel, mod->channels[channel].effects[ecol].cur_operand & 0x0f);
|
|
} else
|
|
if (mod->channels[channel].effects[ecol].cur_operand & 0xf0) { /* Up */
|
|
|
|
MODFILE_AddVolume(mod, channel, mod->channels[channel].effects[ecol].cur_operand >> 4);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Md0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_S3Me0 - Slide Down */
|
|
static int effect_S3Me0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
u8 operand;
|
|
|
|
if (note->operand[ecol] != 0)
|
|
mod->channels[channel].effects[ecol].porta_bak = note->operand[ecol];
|
|
|
|
mod->channels[channel].effects[ecol].cur_operand = operand =
|
|
mod->channels[channel].effects[ecol].porta_bak;
|
|
|
|
if ((operand & 0xf0) == 0xf0) { /* Fine Slide Down */
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period += (operand & 0x0f) * 4;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
} else
|
|
if ((operand & 0xf0) == 0xe0) { /* Extra Fine Slide Down */
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period += operand & 0x0f;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Me0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
u8 operand = mod->channels[channel].effects[ecol].cur_operand;
|
|
|
|
if (((operand & 0xf0) != 0xf0) &&
|
|
((operand & 0xf0) != 0xe0)) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period += 4 * (u32)mod->channels[channel].effects[ecol].cur_operand;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Me0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_S3Mfe - Slide Up */
|
|
static int effect_S3Mf0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
u8 operand;
|
|
|
|
if (note->operand[ecol] != 0)
|
|
mod->channels[channel].effects[ecol].porta_bak = note->operand[ecol];
|
|
|
|
mod->channels[channel].effects[ecol].cur_operand = operand =
|
|
mod->channels[channel].effects[ecol].porta_bak;
|
|
|
|
if ((operand & 0xf0) == 0xf0) { /* Fine Slide Up */
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period -= (operand & 0x0f) * 4;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
} else
|
|
if ((operand & 0xf0) == 0xe0) { /* Extra Fine Slide Up */
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period -= operand & 0x0f;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Mf0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
u8 operand = mod->channels[channel].effects[ecol].cur_operand;
|
|
|
|
if (((operand & 0xf0) != 0xf0) &&
|
|
((operand & 0xf0) != 0xe0)) {
|
|
|
|
if (mod->speedcounter != 0) {
|
|
|
|
u32 period = mod->channels[channel].st3_period;
|
|
period -= 4 * (u32)mod->channels[channel].effects[ecol].cur_operand;
|
|
MODFILE_SetPeriod(mod, channel, period);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Mf0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_S3Mk0 - Vibrato + Volume Slide */
|
|
static int effect_S3Mk0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
/* effect_ST40_Start(mod, channel, ecol, note);*/
|
|
effect_S3Md0_Start(mod, channel, ecol, note);
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Mk0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
effect_ST40_Process(mod, channel, ecol);
|
|
effect_S3Md0_Process(mod, channel, ecol);
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Mk0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
effect_ST40_Stop(mod, channel, ecol);
|
|
effect_S3Md0_Stop(mod, channel, ecol);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_S3Ml0 - Tone Portamento + Volume Slide */
|
|
static int effect_S3Ml0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
/* effect_ST30_Start(mod, channel, ecol, note);*/
|
|
effect_S3Md0_Start(mod, channel, ecol, note);
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Ml0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
effect_ST30_Process(mod, channel, ecol);
|
|
effect_S3Md0_Process(mod, channel, ecol);
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Ml0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
effect_ST30_Stop(mod, channel, ecol);
|
|
effect_S3Md0_Stop(mod, channel, ecol);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_S3Mq0 - Retrig + Volume Slide */
|
|
static int effect_S3Mq0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
u8 operand = mod->channels[channel].effects[ecol].cur_operand;
|
|
|
|
if (operand != 0)
|
|
mod->channels[channel].effects[ecol].retrig_bak = operand;
|
|
else
|
|
operand = mod->channels[channel].effects[ecol].retrig_bak;
|
|
|
|
mod->channels[channel].effects[ecol].cur_operand = operand;
|
|
mod->channels[channel].effects[ecol].retrig_count = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Mq0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
mod->channels[channel].effects[ecol].retrig_count++;
|
|
if (mod->speedcounter != 0) {
|
|
|
|
if (mod->channels[channel].effects[ecol].retrig_count >=
|
|
(mod->channels[channel].effects[ecol].cur_operand & 0x0f)) {
|
|
|
|
if (mod->channels[channel].effects[ecol].retrig_count >=
|
|
(mod->channels[channel].effects[ecol].cur_operand & 0x0f))
|
|
mod->channels[channel].effects[ecol].retrig_count = 0;
|
|
|
|
/* Volume slide */
|
|
if (mod->channels[channel].effects[ecol].cur_operand & 0xf0) {
|
|
|
|
switch ((mod->channels[channel].effects[ecol].cur_operand >> 4) & 0x0f) {
|
|
|
|
case 0:
|
|
case 8:
|
|
break;
|
|
case 1:
|
|
MODFILE_SubVolume(mod, channel, 1);
|
|
break;
|
|
case 2:
|
|
MODFILE_SubVolume(mod, channel, 2);
|
|
break;
|
|
case 3:
|
|
MODFILE_SubVolume(mod, channel, 4);
|
|
break;
|
|
case 4:
|
|
MODFILE_SubVolume(mod, channel, 8);
|
|
break;
|
|
case 5:
|
|
MODFILE_SubVolume(mod, channel, 16);
|
|
break;
|
|
case 6: {
|
|
u8 tmpvol = mod->channels[channel].voiceInfo.volume;
|
|
tmpvol = (tmpvol * 2) / 3;
|
|
mod->channels[channel].voiceInfo.volume = tmpvol;
|
|
break;
|
|
}
|
|
case 7:
|
|
mod->channels[channel].voiceInfo.volume >>= 1;
|
|
break;
|
|
case 9:
|
|
MODFILE_AddVolume(mod, channel, 1);
|
|
break;
|
|
case 10:
|
|
MODFILE_AddVolume(mod, channel, 2);
|
|
break;
|
|
case 11:
|
|
MODFILE_AddVolume(mod, channel, 4);
|
|
break;
|
|
case 12:
|
|
MODFILE_AddVolume(mod, channel, 8);
|
|
break;
|
|
case 13:
|
|
MODFILE_AddVolume(mod, channel, 16);
|
|
break;
|
|
case 14: {
|
|
u8 tmpvol = mod->channels[channel].voiceInfo.volume;
|
|
tmpvol = (tmpvol * 3) / 2;
|
|
if (tmpvol > 64) tmpvol = 64;
|
|
mod->channels[channel].voiceInfo.volume = tmpvol;
|
|
break;
|
|
}
|
|
case 15:
|
|
mod->channels[channel].voiceInfo.volume *= 2;
|
|
if (mod->channels[channel].voiceInfo.volume > 64)
|
|
mod->channels[channel].voiceInfo.volume = 64;
|
|
break;
|
|
}
|
|
}
|
|
/* Retrigger */
|
|
mod->channels[channel].voiceInfo.playpos = 0;
|
|
mod->channels[channel].voiceInfo.playing = TRUE;
|
|
mod->channels[channel].voiceInfo.forward = TRUE;
|
|
/* MODFILE_TriggerNote(mod, channel,
|
|
mod->channels[channel].last_note,
|
|
mod->channels[channel].last_instrument,
|
|
0xff, 0);*/
|
|
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Mq0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_S3Mr0 - Tremolo */
|
|
static int effect_S3Mr0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
u8 operand;
|
|
|
|
if (note->operand[ecol] == 0)
|
|
mod->channels[channel].effects[ecol].cur_operand =
|
|
mod->channels[channel].effects[ecol].tremolo_bak;
|
|
else
|
|
mod->channels[channel].effects[ecol].tremolo_bak = note->operand[ecol];
|
|
|
|
operand = mod->channels[channel].effects[ecol].cur_operand;
|
|
|
|
mod->channels[channel].effects[ecol].tremolo_base = mod->channels[channel].voiceInfo.volume;
|
|
|
|
if (operand & 0x0f)
|
|
mod->channels[channel].effects[ecol].tremolo_depth = operand & 0x0f;
|
|
if (operand & 0xf0)
|
|
mod->channels[channel].effects[ecol].tremolo_freq = (operand >> 4) & 0x0f;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Mr0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
u16 v;
|
|
s16 delta = wavetab[mod->channels[channel].effects[ecol].tremolo_wave & 3][mod->channels[channel].effects[ecol].tremolo_sintabpos];
|
|
delta *= mod->channels[channel].effects[ecol].tremolo_depth;
|
|
delta >>= 7;
|
|
|
|
v = mod->channels[channel].effects[ecol].tremolo_base + delta;
|
|
|
|
if (v > 64)
|
|
v = 64;
|
|
if (v & 0xff80)
|
|
v = 0;
|
|
|
|
mod->channels[channel].voiceInfo.volume = v;
|
|
|
|
mod->channels[channel].effects[ecol].tremolo_sintabpos += mod->channels[channel].effects[ecol].tremolo_freq;
|
|
mod->channels[channel].effects[ecol].tremolo_sintabpos &= 63;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Mr0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
mod->channels[channel].voiceInfo.volume = mod->channels[channel].effects[ecol].tremolo_base;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**** EFFECT_S3Mt0 - Set Tempo */
|
|
static int effect_S3Mt0_Start(MODFILE *mod, int channel, int ecol, MOD_Note *note) {
|
|
|
|
if (note->operand[ecol] > 0) {
|
|
|
|
MODFILE_SetBPM(mod, note->operand[ecol]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Mt0_Process(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int effect_S3Mt0_Stop(MODFILE *mod, int channel, int ecol) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const MODPLAY_EffectHandler MODPLAY_EffectHandlers[] = {
|
|
|
|
/* Soundtracker */
|
|
{ effect_None_Start, effect_None_Process, effect_None_Stop }, /* EFFECT_NONE */
|
|
{ effect_ST00_Start, effect_ST00_Process, effect_ST00_Stop }, /* EFFECT_ST00 */
|
|
{ effect_ST10_Start, effect_ST10_Process, effect_ST10_Stop }, /* EFFECT_ST10 */
|
|
{ effect_ST20_Start, effect_ST20_Process, effect_ST20_Stop }, /* EFFECT_ST20 */
|
|
{ effect_ST30_Start, effect_ST30_Process, effect_ST30_Stop }, /* EFFECT_ST30 */
|
|
{ effect_ST40_Start, effect_ST40_Process, effect_ST40_Stop }, /* EFFECT_ST40 */
|
|
{ effect_ST50_Start, effect_ST50_Process, effect_ST50_Stop }, /* EFFECT_ST50 */
|
|
{ effect_ST60_Start, effect_ST60_Process, effect_ST60_Stop }, /* EFFECT_ST60 */
|
|
{ effect_ST70_Start, effect_ST70_Process, effect_ST70_Stop }, /* EFFECT_ST70 */
|
|
{ effect_ST80_Start, effect_ST80_Process, effect_ST80_Stop }, /* EFFECT_ST80 */
|
|
{ effect_ST90_Start, effect_ST90_Process, effect_ST90_Stop }, /* EFFECT_ST90 */
|
|
{ effect_STa0_Start, effect_STa0_Process, effect_STa0_Stop }, /* EFFECT_STa0 */
|
|
{ effect_STb0_Start, effect_STb0_Process, effect_STb0_Stop }, /* EFFECT_STb0 */
|
|
{ effect_STc0_Start, effect_STc0_Process, effect_STc0_Stop }, /* EFFECT_STc0 */
|
|
{ effect_STd0_Start, effect_STd0_Process, effect_STd0_Stop }, /* EFFECT_STd0 */
|
|
{ effect_STe1_Start, effect_STe1_Process, effect_STe1_Stop }, /* EFFECT_STe1 */
|
|
{ effect_STe2_Start, effect_STe2_Process, effect_STe2_Stop }, /* EFFECT_STe2 */
|
|
{ effect_STe4_Start, effect_STe4_Process, effect_STe4_Stop }, /* EFFECT_STe4 */
|
|
{ effect_STe5_Start, effect_STe5_Process, effect_STe5_Stop }, /* EFFECT_STe5 */
|
|
{ effect_STe6_Start, effect_STe6_Process, effect_STe6_Stop }, /* EFFECT_STe6 */
|
|
{ effect_STe7_Start, effect_STe7_Process, effect_STe7_Stop }, /* EFFECT_STe7 */
|
|
{ effect_STe8_Start, effect_STe8_Process, effect_STe8_Stop }, /* EFFECT_STe8 */
|
|
{ effect_STe9_Start, effect_STe9_Process, effect_STe9_Stop }, /* EFFECT_STe9 */
|
|
{ effect_STea_Start, effect_STea_Process, effect_STea_Stop }, /* EFFECT_STea */
|
|
{ effect_STeb_Start, effect_STeb_Process, effect_STeb_Stop }, /* EFFECT_STeb */
|
|
{ effect_STec_Start, effect_STec_Process, effect_STec_Stop }, /* EFFECT_STec */
|
|
{ effect_STed_Start, effect_STed_Process, effect_STed_Stop }, /* EFFECT_STed */
|
|
{ effect_STee_Start, effect_STee_Process, effect_STee_Stop }, /* EFFECT_STee */
|
|
{ effect_STef_Start, effect_STef_Process, effect_STef_Stop }, /* EFFECT_STef */
|
|
{ effect_STf0_Start, effect_STf0_Process, effect_STf0_Stop }, /* EFFECT_STf0 */
|
|
{ effect_STg0_Start, effect_STg0_Process, effect_STg0_Stop }, /* EFFECT_STg0 */
|
|
|
|
/* Extended Module */
|
|
{ effect_XM01_Start, effect_XM01_Process, effect_XM01_Stop }, /* EFFECT_XM01 */
|
|
{ effect_XM02_Start, effect_XM02_Process, effect_XM02_Stop }, /* EFFECT_XM02 */
|
|
{ effect_XM10_Start, effect_XM10_Process, effect_XM10_Stop }, /* EFFECT_XM10 */
|
|
{ effect_XM11_Start, effect_XM11_Process, effect_XM11_Stop }, /* EFFECT_XM11 */
|
|
{ effect_XM19_Start, effect_XM19_Process, effect_XM19_Stop }, /* EFFECT_XM19 */
|
|
{ effect_XMa0_Start, effect_XMa0_Process, effect_XMa0_Stop }, /* EFFECT_XMa0 */
|
|
|
|
/* S3M */
|
|
{ effect_S3Ma0_Start, effect_S3Ma0_Process, effect_S3Ma0_Stop }, /* EFFECT_S3Ma0 */
|
|
{ effect_S3Md0_Start, effect_S3Md0_Process, effect_S3Md0_Stop }, /* EFFECT_S3Md0 */
|
|
{ effect_S3Me0_Start, effect_S3Me0_Process, effect_S3Me0_Stop }, /* EFFECT_S3Me0 */
|
|
{ effect_S3Mf0_Start, effect_S3Mf0_Process, effect_S3Mf0_Stop }, /* EFFECT_S3Mfe */
|
|
{ effect_S3Mk0_Start, effect_S3Mk0_Process, effect_S3Mk0_Stop }, /* EFFECT_S3Mk0 */
|
|
{ effect_S3Ml0_Start, effect_S3Ml0_Process, effect_S3Ml0_Stop }, /* EFFECT_S3Ml0 */
|
|
{ effect_S3Mq0_Start, effect_S3Mq0_Process, effect_S3Mq0_Stop }, /* EFFECT_S3Mq0 */
|
|
{ effect_S3Mr0_Start, effect_S3Mr0_Process, effect_S3Mr0_Stop }, /* EFFECT_S3Mr0 */
|
|
{ effect_S3Mt0_Start, effect_S3Mt0_Process, effect_S3Mt0_Stop }, /* EFFECT_S3Mt0 */
|
|
|
|
{ NULL, NULL, NULL }
|
|
};
|