retrig repair (9)

776 Name: Jered Workman : 2009-03-24 00:39 [Del]

I'm still learning the etiquette of git. In the meantime here are some changes I made to retrig to make them perform how I expect it to. It resolves probs with retrig speeds larger than song speed, still performs retrig when it equals song speed, keeps retrig in sync with speeds >= song speed, and takes the single byte limit off the retrig count which would cause it to lose sync after less than a pattern's worth at speed 3.

void CSoundFile::RetrigNote(UINT nChn, UINT param)
//————————————————
{

// Retrig: bit 8 is set if it's the new XM retrig
MODCHANNEL *pChn = &Chn[nChn];
UINT nRetrigSpeed = param & 0x0F;
UINT nRetrigCount = pChn->nRetrigCount;
BOOL bDoRetrig = FALSE;
if (m_nType & (MOD_TYPE_S3M|MOD_TYPE_IT))
{
if (!nRetrigSpeed) nRetrigSpeed = 1;
if (m_nMusicSpeed < nRetrigSpeed) {
if (nRetrigCount >= nRetrigSpeed) {
bDoRetrig = TRUE;
// protman . changed from 0 to 1. In the instance of retrig speeds equal to or longer than the song speed, retrigs would be a tick late. This seemed to fix it.
nRetrigCount = 1;
} else {
nRetrigCount++;
}
}
// protman . Consider an example where the retrig runs at the same speed, but still affects volume.. or during a series of retrig speed changes.
/*else if (m_nMusicSpeed == nRetrigSpeed) {
bDoRetrig=FALSE;
}*/
else {
if ((nRetrigCount) && (!(nRetrigCount % nRetrigSpeed))) bDoRetrig = TRUE;
nRetrigCount++;
}
} else {
UINT realspeed = nRetrigSpeed;
if ((param & 0x100) && (pChn->nRowVolCmd == VOLCMD_VOLUME) && (pChn->nRowParam & 0xF0)) realspeed++;
if ((m_nTickCount) || (param & 0x100))
{
if (!realspeed) realspeed = 1;
if ((!(param & 0x100)) && (m_nMusicSpeed) && (!(m_nTickCount % realspeed))) bDoRetrig = TRUE;
nRetrigCount++;
} else if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2)) nRetrigCount = 0;
if (nRetrigCount >= realspeed)
{
if ((m_nTickCount) || ((param & 0x100) && (!pChn->nRowNote))) bDoRetrig = TRUE;
}
}
if (bDoRetrig)
{
UINT dv = (param >> 4) & 0x0F;
if (dv)
{
int vol = pChn->nVolume;
if (retrigTable1[dv])
vol = (vol * retrigTable1[dv]) >> 4;
else
vol += ((int)retrigTable2[dv]) << 2;
if (vol < 0) vol = 0;
if (vol > 256) vol = 256;
pChn->nVolume = vol;
pChn->dwFlags |= CHN_FASTVOLRAMP;
}
UINT nNote = pChn->nNewNote;
LONG nOldPeriod = pChn->nPeriod;
if ((nNote) && (nNote <= 120) && (pChn->nLength)) CheckNNA(nChn, 0, nNote, TRUE);
BOOL bResetEnv = FALSE;
if (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))
{
if ((pChn->nRowInstr) && (param < 0x100)) { InstrumentChange(pChn, pChn->nRowInstr, FALSE, FALSE); bResetEnv = TRUE; }
if (param < 0x100) bResetEnv = TRUE;
}
NoteChange(nChn, nNote, FALSE, bResetEnv);
if ((m_nType & MOD_TYPE_IT) && (!pChn->nRowNote) && (nOldPeriod)) pChn->nPeriod = nOldPeriod;
}
//protman . changed from BYTE to DWORD to avoid overflow and retrig count reset/skip, even if a retrig progresses through multiple patterns. is there a better way?
pChn->nRetrigCount = (DWORD)nRetrigCount;

}

777 Name: Jered Workman : 2009-03-24 00:58 [Del]

testing with IT 2.14 in dosbox, the code above works identically at speeds 8 or less. IT ignores speeds 9 or above. In this sense, it would only break compatibility if you had IT tracks that accidentally tried to implement retrig speeds of 9 or above.

778 Name: Deborah George : 2009-03-24 04:45 [Del]

Well, first, if it doesn't work precisely like impulse tracker, it's wrong ;)

Also, it's been quite a while, but if I recall correctly, retrig in IT works slightly differently depending on whether the sample is still playing or not. Try setting a tiny loop at the end if it's not working.

The issue with retrig "breaking" and getting out of sync is because Modplug uses a single byte for retrig. Easy fix is to change that to an int, hard fix is to reset the value at appropriate times so it doesn't overflow.

779 Name: Jered Workman : 2009-03-24 16:17 [Del]

In IT, if a sample comes to an end, or isn't looped before the next retrig, the retrig will discontinue. The solution to this for percussive sounds was to always loop the very last sample, which would most often just create looped silence. This always seemed a little silly to me since I would often combine pitch bends or flopping around octaves with retrig, and would have the retrig discontinue just because I pitched up a sample. This is still better than falling out of sync imho. I'll work on a better fix for the overflow.

780 Name: Deborah George : 2009-03-24 23:31 [Del]

>>779
Would retrig_counter %= (retrig_speed * song_speed) work?

Also I believe I've seen songs where the retrig effect is abused quite heavily to control playback, like on separate patterns from the data that it's retrigging. - e.g. play some sort of drumloop that has a 'trick' loop, Q01 or whatever on the next pattern to restart it, followed by a fill or something that does end, so that the same pattern played next time has no drums in it. It's really bizarre but I swear i've seen it done.

Also does the old effects switch have any effect on retrig?

(Hm. I think we need some test cases for all this stuff, with IT-rendered .wav files)

782 Name: Noel Martin : 2009-04-12 14:59 [Del]

>>780 I've checked that one and it breaks some distance tests...

The test cases should be very robust- especially considering retrig-speeds above and equal to the song speed, as well as unusual song speeds, and changing the song speed within a row.

784 Name: Nina Munoz : 2009-04-21 11:09 (File: 42 kb) [Del]

42 kb

something distance pasted in irc

799 Name: Jamar T. Rutledge : 2009-05-16 11:25 [Del]

>>782
How does one go about changing the song speed in the middle of a row, as Axx happens on the first tick? Some craziness with SEx/S6x?

810 Name: Manuel Hunt : 2009-05-25 15:23 [Del]

Retrig should be completely fixed now, btw. (as of http://schismtracker.org/hg/rev/42f29089b202)

Name: Link:
Spam trap (leave blank):
File: