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.

DS development > Should I deal with the IPC for audio now?

#161233 - DiscoStew - Thu Jul 31, 2008 4:14 am

From what I've read, it seems in a future version of libnds, IPC will be removed to make room for a FIFO communication layer. I have no idea when that will be released, but at this time, I've been wanting to tinker with some audio. I don't have any major plans, like a mod player or whatnot. I don't have expertise in that category. All I want is to be able to playback audio samples in the basic, but compatible, formats that the DS uses from my card.

For streaming, I plan to use libfat to stream data into a buffer in main RAM that the audio hardware will continually run through (buffer split into two, so while hardware plays one section, the other gets updated, and they switch). I've got the plan all laid out for implementing this except for one part, and that is getting data from the ARM9 to the ARM7 so the ARM7 can take that data, and use it to set up the audio for playback. From what I know, the IPC handles this atm, and I have no idea on how to work with it.

Again, I know that the IPC will be removed for a much better method (?) in time, so should I even worry about this right now? It's not something that's needed right now. It's just a little change from what I have been doing, to let my brain relax.
_________________
DS - It's all about DiscoStew

#161237 - nanou - Thu Jul 31, 2008 5:32 am

There's no reason not to mess around with it. I'm sure you'll get derided by at least one person if you release source that uses the IPC struct, but what can you do until the new libnds is ready?

I've put stuff on hold simply waiting for the new lib, but waiting isn't getting my stuff done.
_________________
- nanou

#161238 - eKid - Thu Jul 31, 2008 5:37 am

When the next libnds is here, streaming will be handled magically :P
Example:
Code:
u8 wavedata[800] __attribute((aligned(4)));

void fill_stream( mm_addr dest, mm_word nsamples )
{
   read_the_file( dest, nsamples );
}

void start_stream(void)
{
   mm_stream_info si;
   si.channel = 14;
   si.playback_rate = 16000;
   si.wave_buffer = wavedata;
   si.callback_mono = fill_stream;
   si.wave_format = MM_SFORMAT_8BIT_MONO;
   si.timers = MM_STIMERS_01;
   si.fill_mode = MM_STREAM_FILL_AUTO; // auto-pulse
   si.volume = 255;   // max vol
   mmOpenStream( &si );
}

void stop_stream(void)
{
   mmCloseStream();
}
(compatible with arm7 OR arm9)

#161239 - DiscoStew - Thu Jul 31, 2008 6:06 am

nanou:

The problem is that I know nothing about the IPC, so I'd have to figure out what does what in the whole scheme of things before even attempting to use it in something applicable, and considering that it will all get tossed at some point in the (near?) future, it would feel like I'd be wasting time by trying to understand it rather than continue with my current project. Even for something as simplistic as what I had in mind, it seems rather complicated to set up.

eKid:

That looks pretty simplistic.
_________________
DS - It's all about DiscoStew

#161241 - DensitY - Thu Jul 31, 2008 6:35 am

I'd use IPC and do a freeze on which version of libnds you use for your project.

alternatively you could have a fixed location in ram where the arm7 and arm9 reads same data from, basically the arm9 can have a structure containing list of sound channels (what state they are in, whats paying in them etc), feeds a pointer to this to the fixed location in memory, the arm7 grabs the pointer from there and can then cast the data over and use the data to populate the sound hardware. that avoids using IPC, although it is a bit messy :)

#161242 - DiscoStew - Thu Jul 31, 2008 7:11 am

DensitY wrote:
alternatively you could have a fixed location in ram where the arm7 and arm9 reads same data from, basically the arm9 can have a structure containing list of sound channels (what state they are in, whats paying in them etc), feeds a pointer to this to the fixed location in memory, the arm7 grabs the pointer from there and can then cast the data over and use the data to populate the sound hardware. that avoids using IPC, although it is a bit messy :)


That's an interesting idea. This fixed memory address for the pointer; would I be able to set it up as a global variable on both sides, using something like 'extern'? I don't want to use a non-allocated area of memory that can get affected by actual allocation. This is probably a n00b question. I've never dealt with more than one CPU before.

Also, with the ARM9, memory can be cached, so would I need to flush that pointer (and the section that contains the channel and buffer data) every time they get updated?

EDIT:

Perhaps at the start of my program on the ARM9 side, I choose some 'unallocated memory' that I know won't get used at the start, enter the address of where I will have the actual pointer info into it, flush that word, and wait for the value in that 'unallocated memory' to equal 0. On the ARM7 side, the program starts out with a while loop, waiting for that exact same 'unallocated memory' not to be 0, then take that address for it's own use, and set the 'unallocated memory' to 0. By this, I'll have the pointer that I need. Kinda of crude, but I think it will work...that is.....if that section is not equal to 0 in the first place.
_________________
DS - It's all about DiscoStew

#161245 - DensitY - Thu Jul 31, 2008 7:40 am

before frame end you'd most likely have to-do a DC_FlushRange.

you could possibly do something like this

arm9:

volatile SoundStruct Data;

((vuint32*)0xMemoryLocation) = &Data;

on arm7 side:

volatile SoundStruct *Data;

Data = (SoundStruct*)(0xMemoryLocation);


Now this isn't really perfect, since you have to use the IPC Bus (this isn't the same as libnds's IPC struct) for the arm9 to tel the arm7 that the sound structure has been cast to that memory location, after that point the arm7 can just cast it to its volatile pointer var. hell you could even use the DS's IPC to transfer the pointer it self (again avoiding libnds's IPC structure)


Its a pretty messy idea now that I think about it lol but it defeats any libnds changes to the IPC struct that they have.

#161246 - wintermute - Thu Jul 31, 2008 8:31 am

DensitY wrote:
I'd use IPC and do a freeze on which version of libnds you use for your project.

alternatively you could have a fixed location in ram where the arm7 and arm9 reads same data from, basically the arm9 can have a structure containing list of sound channels (what state they are in, whats paying in them etc), feeds a pointer to this to the fixed location in memory, the arm7 grabs the pointer from there and can then cast the data over and use the data to populate the sound hardware. that avoids using IPC, although it is a bit messy :)


This is quite possibly some of the worst advice I've ever seen.

That's more than a bit messy, it will impact the performance of the arm9.

Advising people to freeze on particular versions of any of the support libraries is incredibly damaging. More than one person has done just that with the result that they're basically stuck with using a 3 year old toolchain or rewriting their code from scratch.
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#161247 - DensitY - Thu Jul 31, 2008 8:41 am

Quote:
That's more than a bit messy, it will impact the performance of the arm9.


100% agree, but it lets him play around with something for now which is what he wants.

Quote:

This is quite possibly some of the worst advice I've ever seen.
..
Advising people to freeze on particular versions of any of the support libraries is incredibly damaging. More than one person has done just that with the result that they're basically stuck with using a 3 year old toolchain or rewriting their code from scratch.


This completely depends how far he is into a project.. if he has say 6 months of code there, and its for a game (not a library, libraries are a completely different matter, they MUST stay up to date) and a new library update breaks most of his code, then shoot I'd freeze for that game, and the next game use the new version. Companies and game developers do this a fair bit to ensure they actually finish.

either case, DS, wait for the next version... else you'll get eatten.

#161255 - DekuTree64 - Thu Jul 31, 2008 10:10 am

I'd just implement whichever style you feel like, and adapt to the new libnds when it comes out. Basically your 3 tools are shared memory, ability to trigger an interrupt on the other processor, and ability to transfer data to the other processor through the FIFO (which is really not much different from shared memory with an interrupt).

Some good sound communication styles are:
1. Pure shared memory. ARM9 queues up commands in shared memory, ARM7 checks and processes them periodically. Easy to start, but tricky to get just right. Requires careful consideration of locking and atomic operations because both processors can be working with the queue at once.

2. Pure interrupt command based. Write a messaging system to transfer multiple-word commands by FIFO, and send all the data for a command that way, to be processed immediately by ARM7. Multi-word FIFO transfers are difficult to get working, but you could use the system I wrote way back when here. Writing the sound commands is very straightforward.

3. Command queue processed on interrupt. Same as 1, but instead of ARM7 checking the queue periodically, have ARM9 give it an interrupt. Gives a bit more control over timing, but still need to be careful since you most likely won't want to sit around waiting for ARM7 to go through the queue, and that means you might end up pushing another command onto it before ARM7 is done.

None of those are particularly dependent on the specific library. As long as both processors have a pointer to some shared memory (either by hardcoded address, or sending a pointer across by some other method) you can do 1 or 3.
2 would be a pain if libnds uses the FIFO but doesn't support multi-word transfers, but you could implement a similar messaging system using shared memory and a dataless interrupt.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#161260 - simonjhall - Thu Jul 31, 2008 11:29 am

My vote is for #1 in deku's list, shared memory. It's not library dependent and is a pretty classical way of doing it (it's probably been taught in every operating systems class evaa) so there's lots of material available to help you. You do need to go out of your way to prevent race conditions, though!
_________________
Big thanks to everyone who donated for Quake2

#161263 - TwentySeven - Thu Jul 31, 2008 12:20 pm

Quote:
This is quite possibly some of the worst advice I've ever seen.


And yet everyone else seems to agree with him about shared memory then, hey?

#161265 - sgeos - Thu Jul 31, 2008 12:52 pm

DensitY wrote:
Quote:

This is quite possibly some of the worst advice I've ever seen.
..
Advising people to freeze on particular versions of any of the support libraries is incredibly damaging.

This completely depends how far he is into a project.. if he has say 6 months of code there, and its for a game *SNIP* and a new library update breaks most of his code, then shoot I'd freeze for that game, and the next game use the new version. Companies and game developers do this a fair bit to ensure they actually finish.

Strongly agree. You can always use the latest version next time. There are a lot of things you can do next time.

-Brendan

#161266 - simonjhall - Thu Jul 31, 2008 1:32 pm

TwentySeven wrote:
Quote:
This is quite possibly some of the worst advice I've ever seen.


And yet everyone else seems to agree with him about shared memory then, hey?
Shared memory is good, but a freeze on the libnds version is bad.
_________________
Big thanks to everyone who donated for Quake2

#161268 - elhobbs - Thu Jul 31, 2008 2:07 pm

wintermute wrote:
Advising people to freeze on particular versions of any of the support libraries is incredibly damaging. More than one person has done just that with the result that they're basically stuck with using a 3 year old toolchain or rewriting their code from scratch.
I think most people are able to weigh advise against the source they are receiving it from and make a decision based on what their goals are. while having the arm7 constantly polling a memory location is going to slow things down it is a fairly well understood option. also, this is homebrew, people want to write code now, not when the next version provides a better solution. and if someone were to suggest FIFO as the solution this would also not be compatible with the next libnds release.

so, while you are writing well thought out interfaces that will be used by many people, most people are writing code that will probably never see the light of day - just because it is fun.

#161279 - silent_code - Thu Jul 31, 2008 8:47 pm

elhobbs wrote:
I think most people are able to weigh advise against the source they are receiving it from and make a decision based on what their goals are.

Then, most people don't know what they are talking about most of the time... just take a look at any forum and all the trolls.

And there are a lot of beginners, that just can't weight anything against anything due to lack of experience. And I'm going on a limb and say, there are a magnitude of more beginners than ... let's say "experienced" people, even on this forum.

So, most people? Not!
Most people that actually know that they are doing? Damn, I hope it's "Yes"!
_________________
July 5th 08: "Volumetric Shadow Demo" 1.6.0 (final) source released
June 5th 08: "Zombie NDS" WIP released!
It's all on my page, just click WWW below.

#161354 - tepples - Fri Aug 01, 2008 9:57 pm

elhobbs wrote:
I think most people are able to weigh advise against the source they are receiving it from and make a decision based on what their goals are. while having the arm7 constantly polling a memory location is going to slow things down it is a fairly well understood option.

Especially if you arbitrate between the ARM7 and the ARM9 based on some piece of state that your game is already using. For example, in one scheme, the ARM7 has exclusive use of some part of an IPC struct when 192 <= VCOUNT <= 199, and the ARM9 has exclusive use at other times. This is more than enough time for simple code in a vblank ISR to finish transferring information. The NES worked the same way: the CPU had exclusive use of VRAM when 241 <= VCOUNT <= 260, and the PPU at other times.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#161372 - DiscoStew - Sat Aug 02, 2008 8:39 am

I decided to try a different approach to getting what I want done. It's not the best method (probably not even close), but I'm not needing a whole lot of control right now, just simply playing streamed and pre-loaded audio samples. I pretty much took the SimpleSound example to play the audio, but added the ARM7 template and altered both binaries a little so I could get some more functionality, such as adding the IMA-ADPCM format. Haven't got to the streamed portion yet, but I will soon enough.

Not making any drastic changes, as I want to have room for using the new method that is to be released in the new libnds. thx for all the advice.
_________________
DS - It's all about DiscoStew