gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Audio > Playing MOD files

#36803 - gbawiz - Wed Mar 02, 2005 12:10 am

Hello,
I have now been able to produce some mod music from my GBA playing mod files.
I have a question about the pattern jumping and speed.

When the modplayer encounters a row which states the effect as 'jump to order 'n' ' Do I jump on next tick or next row?
A similar problem occurs when using 'pattern break'

The GBA vblank rate is 60hz and setting the speed at the default speed of 6 ticksdelay is too fast and have to adjust to 7 which is too slow, I believe the mod files I have are based on the 50hz setting.

How do I implement the speed set command?
i.e if the speed is set below 31 then I just use that number as the tickdelay but when above 31 it is considered to be a BPM setting.
How is this converted into an appropriate tickdelay or using 60hz.

Thanks

#36807 - DekuTree64 - Wed Mar 02, 2005 1:17 am

Yay, lots of easy questions (which are also good ones since nobody seems to document such specific little details...).

gbawiz wrote:
When the modplayer encounters a row which states the effect as 'jump to order 'n' ' Do I jump on next tick or next row?

Should jump on the next row. The way I do it is with a 'next row' variable, which is normally set to row+1, and then have the effect change that.

Quote:
The GBA vblank rate is 60hz and setting the speed at the default speed of 6 ticksdelay is too fast and have to adjust to 7 which is too slow

Yep, that's a tricky problem, but can be solved.

Quote:
How do I implement the speed set command?

if (param < 32) speed = param;
else tempo = param;

Quote:
How is this converted into an appropriate tickdelay or using 60hz.

songHz = tempo*2/5

Then to solve the problem above of getting the timing right, you need to decouple the song ticking from the VBlank, and do it based on samples played. Once you have the song Hz there, you only need to divide by the VBlank frequency, 60Hz, to get the song updates per frame. THen multiply by the samples per frame (304 if you're using 18157Hz) to get the samples per MOD tick:

samplesPerTick = songHz * 304 / 60

Then you just mix samplesPerTick samples, update the MOD, mix that many more, and so on.

Check my article for a detailed explanation.

Quote:
Thanks

You're welcome :) One of these days I might finish that article with all the details on these things. The player sounds fine on almost all MODs, just that I haven't tackled my old most hated (and feared) effect glissando, and I won't be able to live with myself if I admit defeat to it and leave it unsupported like I have in the past.
And just to note incase you read the article and start to get ideas, the player turned out to sound pretty bad when sliding Hz frequencies, so I switched it to use periods all the time. Could still be done with Hz by making the frequencies fixed-point, but not really worth it, and it was pretty trivial to change it.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#36872 - gbawiz - Wed Mar 02, 2005 6:55 pm

Quote:
Then to solve the problem above of getting the timing right, you need to decouple the song ticking from the VBlank, and do it based on samples played. Once you have the song Hz there, you only need to divide by the VBlank frequency, 60Hz, to get the song updates per frame. THen multiply by the samples per frame (304 if you're using 18157Hz) to get the samples per MOD tick:


samplesPerTick = songHz * 304 / 60

Then you just mix samplesPerTick samples, update the MOD, mix that many more, and so on.


The setup which I have just now is every vblank, the tick is incremented.
If it reaches the modspeed (default 6) then the row is updated and tick reset to 0.

this plays the mod but it can be too fast even when the speed is correct, this being due to the 60hz GBA vlblank instead of the 50hz.
Deku, you mentioned you need to decouple the song ticking from the VBlank.
Does this mean that you use a timer to update the mod, instead of the VBLANK?

Thanks again for advice :)

#36882 - tepples - Wed Mar 02, 2005 9:39 pm

gbawiz wrote:
Deku, you mentioned you need to decouple the song ticking from the VBlank.
Does this mean that you use a timer to update the mod, instead of the VBLANK?

Not necessarily. In GSM Player, the decode destination is always 160 samples (per the GSM Full Rate spec), but the playback source is always 304 samples (for 18 kHz playback). It uses an extra buffer to hold a block of decoded data.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#36890 - gbawiz - Thu Mar 03, 2005 1:25 am

Hello,

About the speed and tempo,
if the defaults are set as speed 6 and tempo 125, which one will be used?
i.e. are both speed and tempo settings needed/used, or just one if so which one?
I was wondering if for example I set the speed to zero, will the song still play at the specified tempo?

Thanks again in advance

#36895 - tepples - Thu Mar 03, 2005 3:31 am

song_hz is always based on tempo; speed determines only the number of ticks per row.

If you don't want to fool around with ring-buffering techniques, then compose all your songs with speed=150 and have the engine assume speed=150. I used a technique like this for TOD's music engine.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#37038 - gbawiz - Sat Mar 05, 2005 2:49 pm

Hello,
I have been looking at this method of updating the mixbuffer for a mod player but find that I run into problems.
The sound is grainy and it extends the time taken, past the vblank duration.

Code:
void sndupdate()
{
   unsigned int samplesleft=BUFFERSIZE;
   while(samplesleft > 0){

      if(sam_until_modtick == 0 && modstate==ACTIVE){
         mod_update();
         sam_until_modtick=sam_per_modtick;
      }//endif

      if(sam_until_modtick < samplesleft && modstate==ACTIVE){
         mixer(cur_mixbuf,sam_until_modtick);
         samplesleft-=sam_until_modtick;
         sam_until_modtick=0;
      }//endif

      else{
         mixer(cur_mixbuf,samplesleft);
         sam_until_modtick-=samplesleft;
         samplesleft=0;
      }//endelse

   }//endwhile

}//end sndupdate procedure


Before, I just updated modtick on every VBLANK. and called the mixing routine also every VBLANK to mix the full buffersize (304).
The above has no lengthy calculations and should not make much difference to the outcome of the modplayer, what am I doing wrong?

Thanks in advance