Author Topic: Tracker stress tests  (Read 23285 times)

Knurek

  • Posts: 534
Tracker stress tests
« on: 5 Sep '07 - 09:05 »
Could any of you share some tracker replay routine stress tests?

There were those IT ones I've linked before (http://rigelseven.com/downloads/) and I do know of a few Protracker ones (Ultimate Beeper by Groo (sample loading routine), Light & Sound part 4 by Dreamer (loops & pattern breaks)), but I'd like to have a few more (maybe something with that facked Protracker EFx command, some module that highlights Protracker/Fastracker replay differences).
Would be nice to have some Fastracker 2/Screamtracker 3 ones as well (Leśnik's XMs are a good start, the guy did some funky things in some tunes).

Any other suggestions?

saga

  • Posts: 2301
Re: Tracker stress tests
« Reply #1 on: 5 Sep '07 - 15:32 »
about EFx: urea geller by reed has some of them... also have a look here, we had some discussion about efx :)
« Last Edit: 12 Oct '09 - 13:15 by saga »

Fraggie

  • Posts: 714
Re: Tracker stress tests
« Reply #2 on: 6 Sep '07 - 09:09 »
I just had a quick look at original ProTracker replay sources and I can confirm that Protracker 1.0 had different EFx effect than later ProTrackers - FunkIt (or FunkRepeat) instead of IvertLoop. I wonder which effect XMPlay handles...?

Ian @ un4seen

  • Administrator
  • Posts: 21861
Re: Tracker stress tests
« Reply #3 on: 6 Sep '07 - 13:33 »
XMPlay treats EFx as "FunkIt" (when in PT1 mode).

Actually, looking at the code just now, I think EFx is treated as "Invert Loop".

Looking at the ProTracker 1.0 and 1.1 playback code, XMPlay is doing what PT1.1 does. It's a bit confusing, as the PT1.1 source labels/etc still say "funk", but it is inverting the loop data. I'm not sure what the PT1.0 code is meant to be doing :D
« Last Edit: 6 Sep '07 - 15:16 by Ian @ un4seen »

Sam_Zen

  • Posts: 113
Re: Tracker stress tests
« Reply #4 on: 7 Sep '07 - 06:31 »
According to the XM codelist coming with FastTracker II :
EF - Set active macro
So it's not surprising this could be interpreted differently in players.

Knurek

  • Posts: 534
Re: Tracker stress tests
« Reply #5 on: 7 Sep '07 - 08:02 »
According to the XM codelist coming with FastTracker II :
EF - Set active macro
So it's not surprising this could be interpreted differently in players.

Yeah, MPT has another different EFx command as well.

raina

  • Posts: 1163
Re: Tracker stress tests
« Reply #6 on: 7 Sep '07 - 08:22 »
According to the XM codelist coming with FastTracker II :
EF - Set active macro
So it's not surprising this could be interpreted differently in players.

Actually, from the Fasttracker II documentation:

Quote
EFx - Funk it! (not implemented)

saga

  • Posts: 2301
Re: Tracker stress tests
« Reply #7 on: 22 Jan '09 - 18:00 »
Looking at the ProTracker 1.0 and 1.1 playback code, XMPlay is doing what PT1.1 does. It's a bit confusing, as the PT1.1 source labels/etc still say "funk", but it is inverting the loop data. I'm not sure what the PT1.0 code is meant to be doing :D
[/quote]
Can you explain what "Invert Loop" actually does? I tried to find it out by doing a bit of research and looking at the PT sourcecode, but unfortunately, I don't understand what the ASM code does. Do you have C(++) sourcecode for the EFx command? :)

Fraggie

  • Posts: 714
Re: Tracker stress tests
« Reply #8 on: 24 Jan '09 - 16:00 »
I can answer that. :)

"Invert loop" effect replaces (!) sample data bytes within loop with their bitwise complement (NOT). The parameter sets speed of altering the samples. This effectively trashes the sample data. Because of that this effect was supposed to be removed in the very next ProTracker versions, but it actually survived until ProTracker 3.0 was never removed.

It should go something like this (called every tick)...
Code: [Select]
il_speed = parameter_of_EFx;
...
il_table = {0,5,6,7,8,10,11,13,16,19,22,26,32,43,64,128};

il_delay += il_table[il_speed];

if (current_sample_has_loop && (il_delay >= 128))
{
  il_delay = 0;

  if (++il_pos > current_sample_loop_length)
    il_pos = 0;

  current_sample_pcm[current_sample_loop_start + il_pos] = ~current_sample_pcm[current_sample_loop_start + il_pos];
}

This is EFx implementation since ProTracker 1.1A. Prior to this version this effect is called "Funk Repeat" and it moves loop of the instrument (just the loop information - sample data is not altered). The parameter is the speed of moving the loop.

It should go something like this (called every tick)...
Code: [Select]
fr_speed = parameter_of_EFx;

...

fr_table = {0,5,6,7,8,10,11,13,16,19,22,26,32,43,64,128};

fr_delay += fr_table[fr_speed];

if (current_sample_has_loop && (fr_delay >= 128))
{
  fr_delay = 0;

  current_sample_loop_start += current_sample_loop_length;

  if (current_sample_loop_start > current_sample_length)
    current_sample_loop_start = original_current_sample_loop_start;
}

As Ian mentioned, to make things more confusing ProTracker replay routines kept "Funk" label names for "Invert Loop" effect.

Both implementations work best with very short loops, so they are usable mostly for "chiptunes".
« Last Edit: 25 Jan '09 - 09:49 by Fraggie »

saga

  • Posts: 2301
Re: Tracker stress tests
« Reply #9 on: 25 Jan '09 - 11:22 »
Wow, thanks for the code :D I'll see what I can do with it... Is there a way to implement it without destroying all samples? :D

Fraggie

  • Posts: 714
Re: Tracker stress tests
« Reply #10 on: 25 Jan '09 - 16:46 »
Well it wouldn't matter for a player. But for a tracker I suppose a copy of the originally loaded sample could be used for playing.

saga

  • Posts: 2301
Re: Tracker stress tests
« Reply #11 on: 25 Jan '09 - 18:17 »
Well, I'm trying to get it working in modplug tracker, so... :)

saga

  • Posts: 2301
Re: Tracker stress tests
« Reply #12 on: 23 Oct '09 - 22:18 »
Sorry for digging up this old thread yet again, but..
Ian, are you sure that XMPlay's implementation of "Invert Loop" is correct? Because I think it's not. It seems like you apply the effect only on the row where the EFx command is; however, it seems like it has to be applied on any row (and only on the sample the EFx command occured with) until an EF0 command is found. OpenMPT's new implementation seems to be more "balls-on" here.

Ian @ un4seen

  • Administrator
  • Posts: 21861
Re: Tracker stress tests
« Reply #13 on: 26 Oct '09 - 14:28 »
XMPlay applies the EFx effect (when in PT1 mode) on every non-0 tick of every row (and the 0 tick of the EFx row), but also on every sample played in the channel until an EF0 is encountered to disable it. Do you have an example file to highlight where it's going wrong? Saves hunting :)

saga

  • Posts: 2301
Re: Tracker stress tests
« Reply #14 on: 26 Oct '09 - 23:01 »
Yes, I actually have two recording of tunes playing in ProTracker.
mp3s
original mods:
reed - urea geller (channel 4)
emax-doz (channels 2 and 3) - the mp3 for this one is starting to get really interesting at 0:46.

I'm actually not quite sure which one is closer actually, XMPlay or OpenMPT, but the OpenMPT code is actually what I have found out together with two other people by literally translating the PT code to C.
« Last Edit: 25 May '10 - 23:07 by saga »

Ian @ un4seen

  • Administrator
  • Posts: 21861
Re: Tracker stress tests
« Reply #15 on: 27 Oct '09 - 18:08 »
Your processing (InvertLoop) looks basically the same as what XMPlay does, so I guess any difference must be in when the processing is done. As I say, XMPlay does it on the tick of the EFx effect and then every non-0 tick of every row. When are you doing it?

saga

  • Posts: 2301
Re: Tracker stress tests
« Reply #16 on: 28 Oct '09 - 09:22 »
Ok, I'm not leaving out the first tick, so I will try if this will sound much different.

8bitbubsy

  • Guest
Re: Tracker stress tests
« Reply #17 on: 28 Oct '09 - 10:01 »
Code: [Select]
FunkIt TST.L Counter
BNE Return2
MOVE.B n_cmdlo(A6),D0
AND.B #$0F,D0
LSL.B #4,D0
AND.B #$0F,n_glissfunk(A6)
OR.B D0,n_glissfunk(A6)
TST.B D0
BEQ Return2
UpdateFunk
MOVEM.L A0/D1,-(SP)
MOVEQ #0,D0
MOVE.B n_glissfunk(A6),D0
LSR.B #4,D0
BEQ funkend
LEA FunkTable(PC),A0
MOVE.B (A0,D0.W),D0
ADD.B D0,n_funkoffset(A6)
BTST #7,n_funkoffset(A6)
BEQ funkend
CLR.B n_funkoffset(A6)
MOVE.L n_loopstart(A6),D0
MOVEQ #0,D1
MOVE.W n_replen(A6),D1
ADD.L D1,D0
ADD.L D1,D0
MOVE.L n_wavestart(A6),A0
ADDQ.L #1,A0
CMP.L D0,A0
BLO.S funkok
MOVE.L n_loopstart(A6),A0
funkok MOVE.L A0,n_wavestart(A6)
MOVEQ #-1,D0
SUB.B (A0),D0
MOVE.B D0,(A0)
funkend MOVEM.L (SP)+,A0/D1
RTS

FunkIt   TST.L   Counter
   BNE   Return2

if (mod_tick != 0) goto return2;
return2 is a label with a "RTS return to subroutine" instruction in the protracker source code.


FunkIt is called *whenever* EFx is found. UpdateFunk is called in every tick in do_note:
Code: [Select]
chkefx2 BSR UpdateFunk <-- Run the updatefunk routine, skipping the "FunkIt" part
[..] check for other effects here. UpdateFunk is run *no matter* if funkspeed == 0,
UpdateFunk checks if speed == 0, else goto return2


8bitbubsy

  • Posts: 7
Re: Tracker stress tests
« Reply #18 on: 28 Oct '09 - 10:14 »
(Ignore my previous post)

Quote from: ProTracker ASM code
FunkIt   TST.L   Counter
   BNE   Return2

in C:
if (mod_tick != 0) return; // thus n_funkspeed is eventually only changed on tick 0

FunkIt is called *whenever* EFx is found in ch->param.
Also, UpdateFunk() is called *as well* when EFx is found, if param != 0!

UpdateFunk is also called in every tick in do_note:
Quote from: ProTracker ASM code
chkefx2   BSR   UpdateFunk

Something like this (pseudo):
Code: [Select]
const unsigned char FunkTable[] = {
  0,5,6,7,8,10,11,13,16,19,22,26,32,43,64,128
};

unsigned char n_funkspeed = 0, n_funkdelay = 0;
unsigned short n_funkoffset = 0; // On .MOD, max sample length = 65535 - therefore short

void UpdateFunk();

void UpdateEffects(CHANNEL* ch)
{
  UpdateFunk();
  switch (ch->param)
  {
    case EFx:
    {
      if (mod_tick == 0)
      {
n_funkspeed = ch->param & 0x0f;
        UpdateFunk();
      }
    }
  }
}

void UpdateFunk()
{
  if (n_funkspeed == 0) return;

  n_funkdelay += FunkTable[n_funkspeed];
  if (n_funkdelay < 128) return; // Wait more
  n_funkdelay = 0;

  if (++n_funkoffset >= (s->loopstart + s->looplen)) n_funkoffset = 0;

  if (s->looplen > 0)
    s->data[s->loopstart + n_funkoffset] = ~s->data[s->loopstart + n_funkoffset];
    // Where s->data points to module->sample_data[instrument_number_got_from_EFx->offset]
}
« Last Edit: 28 Oct '09 - 11:52 by 8bitbubsy »

Ian @ un4seen

  • Administrator
  • Posts: 21861
Re: Tracker stress tests
« Reply #19 on: 28 Oct '09 - 13:00 »
I had another look at the PT source to confirm things, and I'm fairly sure that XMPlay is handling EFx the same as it does. You seem to have "UpdateFunk" sorted, but I think a couple of other things may not be quite right. Note that in the "PlayVoice" routine the "n_wavestart" variable (which is the "invert" position) is reset whenever a sample is started, ie. it doesn't only apply to the sample playing at the time of the EFx effect. Also, under "IntMusic", "CheckEffects" (which calls "UpdateFunk") is not called on tick 0 (except when in a pattern delay).

8bitbubsy

  • Posts: 7
Re: Tracker stress tests
« Reply #20 on: 28 Oct '09 - 18:31 »
@ Ian
Nice!

Can you try to translate that to C for me? My implementation of invertloop seems to be a bit different than on protracker -- I guess this is why.
In pseudo of course  :D

Ian @ un4seen

  • Administrator
  • Posts: 21861
Re: Tracker stress tests
« Reply #21 on: 29 Oct '09 - 16:31 »
Your "InvertLoop" function looks fine to me, apart from the "pEFxSample" stuff (it should be working with the current sample). The rest of it could look something like this...

Code: [Select]
if (tick==0 && !in_pattern_delay) {
if (row_instrument!=0) {
invert_pos=loop_start; // 0 in your case as you're adding the loop start in InvertLoop
}
if (row_effect==EFx) {
invert_speed=x;
InvertLoop();
}
} else {
InvertLoop();
}

8bitbubsy

  • Posts: 7
Re: Tracker stress tests
« Reply #22 on: 29 Oct '09 - 22:12 »
No, your code is wrong. I downloaded the latest XMPlay, chose the PT1 play method... Your InvertLoop implementation is all but genuine. I've spent many hours listening to this effect in PT1 and PT2 on my Amigas. emax-doz.mod and emax-fli.mod sounds nonsense on the EFx parts in your player.

Correct way:

1: After each InvertLoop() call, the remaining n_wavestart is used as a "sample offset" for PlayVoice (on the EFx enabled channel), e.g. you shorten the loop point. When n_wavestart reaches n_loopend, you set it to n_loopstart again.
2: You should use global variables, so when EF is enabled, those variables count for all EFx enabled channels. (e.g. no individual vars for each channel)
3. As long as EFx is enabled, it pulses all the time until it finds EF0. No "sample number" or such shall interrupt the n_delay variable.
4. Listen to the MP3 saga supplied, that's from me recording through PT2 on my Amiga 1200 with phono cables. That's the genuine way. The song played there is channel 2 and 3 of "emax-doz.mod".

Although my implementation still is not 100% genuine, it's five times more than yours. No offense, Ian!
« Last Edit: 29 Oct '09 - 22:47 by 8bitbubsy »

saga

  • Posts: 2301
Re: Tracker stress tests
« Reply #23 on: 30 Oct '09 - 06:33 »
emax-fli.mod for your convenience. :)

Ian @ un4seen

  • Administrator
  • Posts: 21861
Re: Tracker stress tests
« Reply #24 on: 30 Oct '09 - 14:03 »
4. Listen to the MP3 saga supplied, that's from me recording through PT2...

Oh, you're comparing with PT2? Please note that XMPlay attempts to emulate PT1 (when "MOD playback mode" is set to "PT1"). Perhaps that would explain the difference then. I'm looking at the v1.2 source, and I can't find any evidence of what you claim in that. What source code version are you looking it?