Tuesday, May 25, 2010

Als de klok thuis tikt ...

Howdy. You've noticed the small bullet point on improper music replay on my latest "todo" post, haven't you ? That means more cscope-powered lunch times ahead, and I've just had one of them. I must add that, while I've been coding or hacking around players for tracked music for over 10 years now, I've got virtually no experience of the .MOD format itself and very little background on the .XM format. S3M and IT were what I worked with until I opted for 0xtob's libNTXM as the media player for GEDS. So my documentation of the current player state got stuck on question such as "Is there a 'volume column' at all in .MOD files ?" Screenshot from Wikipedia suggests it hasnt, and format 'specs' from wotsit confirms.

J'ai choisi la libNTXM d'0xtob pour sonoriser les aventures de Bilou, il y a bien 2 ans, maintenant. Pourtant mon expérience du fasttracker II est virtuellement nulle, et ma connaissance des .MOD (les fichiers produits par son précurseur) franchement aléatoire. Un exemple ? Hier, j'aurais été incapable de vous dire s'il y avait ou non une colonne dédiée au volume dans un .mod. Dans un .S3M, ça oui : c'est le format que mon "modplayer" en assembleur pour DOS prenait. Dans .IT aussi -- c'est le format que mon frère a utilisé le plus pour ses productions. Eh bien, il n'y en a pas en .MOD. Tout au plus un effet "set volume" (Cxx) et quelques variantes (portamento + vol slide, etc.

    _____byte 1_____  _byte2__  ______byte 3_______  _byte4_
/ / / /
0000 0000-00000000 0000 0000-00000000
| | | |
Upper four 12 bits for Lower four Effect command.
bits of sam- note period. bits of sam-
ple number. ple number.
LibNTXM code is not a maze, but it has to work around the glitchy sound hardware of the nintendoDS: NDS sound hardware doesn't allow us to alter the volume directly (if we do, it produce sound glitches), so we have to perform fading from the current volume value to the next one, requiring some actions to take place ahead of time. So you'll encounter things such as
 if(state.tick_ms >= song->getMsPerTick() - FADE_OUT_MS) {
// we are shortly before the next tick. (As long as a fade would take)


As a consequences, EFFECT_SET_VOLUME (Cxx), EFFECT_VOLUME_SLIDE (Axx) or EFFECT_E_NOTE_CUT (ECx) do not directly affect the channel volume, but record a request to set the volume in effstate.channel_setvol_requested, altering state.channel_fade_target_volume jointly. So what happens to the "volume column" of an S3M (yes, it had it when converted into an XM ?)


Pourquoi ce regain d'intérêt soudain pour libNTXM ? eh bien parce que le "mod" que je voudrais utiliser pour Apple Assault ne passe pas correctement sur DS. Je soupçonne fort "mon" player de ne pas tenir compte des changements de volume. Je creuse donc les sources, mais le code n'est pas d'une lisibilité exemplaire. En cause, le fait qu'il est nécessaire de baisser progressivement le volume d'un canal audio de la DS avant de changer le son en cours... faute de quoi, un "tic" se fait entendre. Le code de "EFFECT_SET_VOLUME", "EFFECT_VOLUME_SLIDE" et autre "NOTE_CUT" (que je connais sous leur 'nom' dans scream tracker, pour simplifier) va donc indiquer son "intention de modifier le volume" de sorte que le player puisse commencer le changement de volume suffisamment en avance ... De plus, le code de gestion des effets est découpé en 2 parties: ce qui s'exécute sur le premier "tic" d'une ligne et ce qui s'exécute sur tous les autres tics.
// Separate volume column effects from the volume column
// and put them into the effcts column instead


if((vol >= 0x10) && (vol <= 0x50)) {
u16 volume = (vol-16)*2;
if(volume>=MAX_VOLUME) volume = MAX_VOLUME;
ptn[chn][row].volume = volume;
} else if(vol==0) {
ptn[chn][row].volume = NO_VOLUME;
} else if(vol>=0x60) {

// It's an effect!
// decoded into ptn[chn][row].effect2
// and ptn[chn][row].effect2_param
// see XMTransport::load() for details.

}

Another thing I'll have to keep in mind while hacking around is that ProTracker effects (and i guess, their XM derivatives) are only supposed to be executed on non-row ticks. At least, that's the case for volume slide and portamento to note, and that explains many if (tick==0) return; in libmikmod's code. I blogged that a few years ago. That explains the separation between handleEffects() and handleTickEffects() in libntxm. Hence the name of this post: ticks are the ultimate measure of time in MOD-inspired formats. Final note for today: in .MOD and .XM, the same "Fxx" command is used to set speed (#of ticks per row, 0..31) and tempo (that is, BPM, 32..255)

next time: update of Player::playRow so that it affects volume in the same way as playNote(..., chn->cell.volume,...) does when note==EMPTY_NOTE. Stay tuneD.


Bref. Je vais devoir m'assurer que l'équivalent du code de "set_volume" existe lorsqu'une "cellule" contenant du volume mais pas de note (sinon playNote(...) aurait fait son boulot :P)

1 comment:

cyborgjeff said...

Me souvenait plus trop comment cela se passait sous Fast Tracker, je pense que je jouais assez peu à changer le volume via ce soft là enfait...