#6581 - wizardgsz - Thu May 29, 2003 8:12 pm
Thank you very much, guys. Hi really greet everyone gave an answer to my previous post!
Let me explain my request.
I'm going to code my own XM-player and I'm searching for good references (ie. mod players and docs, GBA specific stuff and not - I found a great C=64 XM player yeeaah!).
Today I've got an experimental player/mixer skeleton working (badly)... but how many troubles! :(
I'm not searching for speed or assembly code, I'd like to fix myself the
code I cut&pasted - I'm going to describe how I got my GBA playing... again, badly;-)
At first
========
At first I used various sources (mikmod and fmod docs mainly) handling
modules playback routines filling a mono single buffer (GBA implementing
details later) with songs being played at wrong rates/frequencies, FASTER AS I DECREMENT THE (RE)SAMPLING FREQ.
My "sound culture" is really poor (as my english) and I soon realized I've
to code it using double buffering techniques hoping it resolves my playback
problem. Unfortunately I cannot set up it properly:(
This is the preamble, so let's go with details.
Ehm excuse me if I got laborious...
GBA registers (DSound, timers, DMA)
===================================
I got sound so, likely, the sound registers setup is exact...
I'm using Timer0 for DSound to count mixing freq as stated worldwide, I'm
using also Timer1 to count mixing buffer overflows (interrupt), no VBlank
IRQ method...
* Timer1 at 0x10000 - the number of samples to play and enable it with irq
generation and cascade from Timer 0
* Timer0 enable for directsound at playback (resampling) frequency 0x10000 - (cpuFreq / playbackFreq)
* DMA1 to DS-A FIFO (source inc, dest inc, start fifo, repeat, 32bit)
* DMA2 to DS-B FIFO
* On Timer1 interrupts (ie mixing buffer overflows)
a- stop DMAs
b- swap mixing buffers
c- restart/reinit DMAs
Everything should be ok as I read so many posts/listings doing it the same
way but who knows;)
The mod player
==============
And what about song module-handling? Probably I am just missing something here (while cut&pasting from other source code).
* Pattern playback
The row/order/break/jump/loop handling taken from listings I mentioned above and should be exact.
* Effects
I don't handle any effect (except for pattern and tempo settings)
* Tempo setup
I use the following formula to compute samples per beat:
(playbackFreq * 5) / (BPM * 2)
ie.
playbackFreq / (BPM * 2 / 5)
but I do not reset any GBA register, shouldn't I (timer??)?
* The worker / sound poll function
This is were the song being mainly updated, frame-by-frame. The skeleton is the one you already should know, it mixes MIXBUFLEN samples at a time, in pseudo code:
The tricky code, my doubts
==========================
Hopefully I wrote this piece of code avoiding omissions.
I doubt the tempo settings are treated properly, I dread to think I should
change some DSound/timer register while setting up new BMP values...
The way I use the mixing buffers (MixerBufferLeft/Right above) is probably
incorrect also, I reset pointers to them frame-by-frame within the "sound
poll" function (fun Update()), is it the way I have to proceed?
And now?
========
Thanks again to everybody, I'd really appreciate your help.
Anyhow hear you soon, bye bye.
Last edited by wizardgsz on Mon Jun 23, 2003 2:25 pm; edited 1 time in total
Let me explain my request.
I'm going to code my own XM-player and I'm searching for good references (ie. mod players and docs, GBA specific stuff and not - I found a great C=64 XM player yeeaah!).
Today I've got an experimental player/mixer skeleton working (badly)... but how many troubles! :(
I'm not searching for speed or assembly code, I'd like to fix myself the
code I cut&pasted - I'm going to describe how I got my GBA playing... again, badly;-)
At first
========
At first I used various sources (mikmod and fmod docs mainly) handling
modules playback routines filling a mono single buffer (GBA implementing
details later) with songs being played at wrong rates/frequencies, FASTER AS I DECREMENT THE (RE)SAMPLING FREQ.
My "sound culture" is really poor (as my english) and I soon realized I've
to code it using double buffering techniques hoping it resolves my playback
problem. Unfortunately I cannot set up it properly:(
This is the preamble, so let's go with details.
Ehm excuse me if I got laborious...
GBA registers (DSound, timers, DMA)
===================================
I got sound so, likely, the sound registers setup is exact...
I'm using Timer0 for DSound to count mixing freq as stated worldwide, I'm
using also Timer1 to count mixing buffer overflows (interrupt), no VBlank
IRQ method...
* Timer1 at 0x10000 - the number of samples to play and enable it with irq
generation and cascade from Timer 0
* Timer0 enable for directsound at playback (resampling) frequency 0x10000 - (cpuFreq / playbackFreq)
* DMA1 to DS-A FIFO (source inc, dest inc, start fifo, repeat, 32bit)
* DMA2 to DS-B FIFO
* On Timer1 interrupts (ie mixing buffer overflows)
a- stop DMAs
b- swap mixing buffers
c- restart/reinit DMAs
Everything should be ok as I read so many posts/listings doing it the same
way but who knows;)
The mod player
==============
And what about song module-handling? Probably I am just missing something here (while cut&pasting from other source code).
* Pattern playback
The row/order/break/jump/loop handling taken from listings I mentioned above and should be exact.
* Effects
I don't handle any effect (except for pattern and tempo settings)
* Tempo setup
I use the following formula to compute samples per beat:
(playbackFreq * 5) / (BPM * 2)
ie.
playbackFreq / (BPM * 2 / 5)
but I do not reset any GBA register, shouldn't I (timer??)?
* The worker / sound poll function
This is were the song being mainly updated, frame-by-frame. The skeleton is the one you already should know, it mixes MIXBUFLEN samples at a time, in pseudo code:
Code: |
function Update() begin u32 tickdata; u32 samples_to_mix; u32 numsamples = MIXBUFLEN; // Set up buffers for the sound to be mixed into s8 * left = "MixerBufferLeft"; s8 * right = "MixerBufferRight"; // Keep looping until we've filled the buffer tickdata = 0; samples_to_mix = numsamples; while ( samples_to_mix ) { u32 thiscount; // Only move on to the next tick if we finished mixing the last if ( "PlayingSong"->mixer_samplesleft == 0 ) { // general song pattern handling // row/order // tick0 and inbetween fx "UpdateTick( PlayingSong )" // Set the number of samples to mix in this chunk "PlayingSong"->mixer_samplesleft = "PlayingSong"->mixer_samplespertick; } // Ok, so we know that we gotta mix 'mixer_samplesleft' // samples into this buffer, see how much room we actually got thiscount = "PlayingSong"->mixer_samplesleft; if ( thiscount > samples_to_mix ) thiscount = samples_to_mix; // Make a note that we've added this amount "PlayingSong"->mixer_samplesleft -= thiscount; samples_to_mix -= thiscount; // Now mix it! "Mix( &left[ tickdata ], &right[ tickdata ], thiscount )" tickdata += thiscount; } end function Update(); // using 16.16 fixed point math (FRAC_BITS = 16) function Mix( s8 * left, s8 * right, u32 numsamples ) begin "clear numsamples bytes of left/right buffers" // Loop through each channel and process note data "for each channel" { u32 samples_to_mix; // Set up for the mix loop s8 * mixed = "left/right according to pan settings" const s8 * sample = "sample data according to channel being mixed" fixedpoint nLength = "16.16 sample length" fixedpoint nLoopStart = "16.16 sample repeat offset" fixedpoint nLoopLength = ... fixedpoint nLoopEnd = ... fixedpoint freq = freq[ channel ]; fixedpoint pos = start[ channel ]; fixedpoint deltapos = fixedpoint( freq / playbackFreq ); fixedpoint mixpos = 0; // Make sure I'm actually playing something // ... samples_to_mix = numsamples; while ( samples_to_mix ) { u32 thiscount, i; // If I'm a looping sample then I need to check // if it's time to loop back. I also need to figure out // how many samples I can mix before I need to loop again // omissis... // inner loop for (i=thiscount; i!=0; i--) { // omitting volume handling... mixed[ mixpos++ ] += sample[ pos >> FRAC_BITS ]; pos += deltapos; } // inner loop end } // Save current position start[ channel ] = pos; } end function Mix(); |
The tricky code, my doubts
==========================
Hopefully I wrote this piece of code avoiding omissions.
I doubt the tempo settings are treated properly, I dread to think I should
change some DSound/timer register while setting up new BMP values...
The way I use the mixing buffers (MixerBufferLeft/Right above) is probably
incorrect also, I reset pointers to them frame-by-frame within the "sound
poll" function (fun Update()), is it the way I have to proceed?
And now?
========
Thanks again to everybody, I'd really appreciate your help.
Anyhow hear you soon, bye bye.
Last edited by wizardgsz on Mon Jun 23, 2003 2:25 pm; edited 1 time in total