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 > Dynamic channel allocation?

#164396 - Ruben - Thu Oct 30, 2008 1:46 pm

Hi (again).

OK, so I've finally got the mixer's reverb setting working fine, and now I'm starting to make the music player... and ALREADY came across an obstacle~~

xD

Anyway... so does anyone here know a good way to do dynamic channel allocation? As in MIDI/IT style, where not every music channel corresponds to that sound channel.

#164435 - Ruben - Sat Nov 01, 2008 11:50 am

OK, I'd better re-word that before the post gets deleted for being so darn STUPID! :P

Anyone know of a "good" way to implement dynamic channel allocation, and then being able to do stuff to the allocated channel, where more than 1 note can be present?

#164437 - kusma - Sat Nov 01, 2008 12:07 pm

Sure, free-lists (linked list of unused elements) is a nice way of managing limited resources. The problematic thing is knowing what to do when you run out of resources. Stealing a channel is a tricky thing, and I've done it for a soft-synth I've done. What I did was to try to pick the channel with the lower volume that was played "a while ago" (what this might mean depends on your player. For me it was when the envelope was not in the attack-state). I used a couple of other heuristics as well. Note that for module-type formats, this might not be clever enough, since a lot of notes are dependent on the previous ones.

#164438 - Ruben - Sat Nov 01, 2008 12:22 pm

kusma wrote:
Sure, free-lists (linked list of unused elements) is a nice way of managing limited resources. The problematic thing is knowing what to do when you run out of resources. Stealing a channel is a tricky thing, and I've done it for a soft-synth I've done. What I did was to try to pick the channel with the lower volume that was played "a while ago" (what this might mean depends on your player. For me it was when the envelope was not in the attack-state). I used a couple of other heuristics as well. Note that for module-type formats, this might not be clever enough, since a lot of notes are dependent on the previous ones.


Hehe, yeah, I've got a whole other thing sorted for module-type formats.

Quote:
What I did was to try to pick the channel with the lower volume that was played "a while ago" (what this might mean depends on your player. For me it was when the envelope was not in the attack-state)

Yeah, I suppose that's easy enough to do. Get channel data, check if on attack, if not, compare to last stored volume, if less than store, continue through all channels.

And what exactly do you mean by "free-lists?" Do you mean like, say, a u32 variable keeping track of all the active channels, 1 per bit? Or do you mean something more complicated like a pointer to channel with status and stuff?

#164439 - kusma - Sat Nov 01, 2008 12:33 pm

Ruben wrote:
Yeah, I suppose that's easy enough to do. Get channel data, check if on attack, if not, compare to last stored volume, if less than store, continue through all channels.

Actually, I just gave a priority-value to each channel by setting the different bits to different settings based on the channel-state. That way, you don't really need to code any logic, you just bitwise OR together a series of heuristic values, and sort the channels to find the one to pick.

Quote:
And what exactly do you mean by "free-lists?" Do you mean like, say, a u32 variable keeping track of all the active channels, 1 per bit? Or do you mean something more complicated like a pointer to channel with status and stuff?

A linked list of free channels. Whenever you allocate one, you just take the first element, and set the global free-pointer to the next free one. It's a pretty common thing to do for fixed-size memory allocators.

#164440 - Ruben - Sat Nov 01, 2008 12:38 pm

Quote:
A linked list of free channels. Whenever you allocate one, you just take the first element, and set the global free-pointer to the next free one.

Oh, so you mean like...

Code:
channel *next_channel;
//get a channel
next_channel = fetch_free();


.. Or am I off track? :P