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 > Sounds

#121148 - Crs - Fri Mar 09, 2007 3:00 pm

Greets,

Having started reading up on NDS dev, I have read that ARM7 deals with sound processing. Is it possible to pass a pointer of an array containing raw sound data from ARM9 to ARM7 and have the ARM7 play it?

((Sorry I can't test anything at the moment, just thought I'd ask))

Thanks!
_________________
www.hazardball.com

#121156 - 0xtob - Fri Mar 09, 2007 4:36 pm

Yep, and that's also how the libnds sound functions do it.
_________________
http://blog.dev-scene.com/0xtob | http://nitrotracker.tobw.net | http://dsmi.tobw.net

#121215 - Crs - Sat Mar 10, 2007 9:00 am

Thanks thats very good to know :)
_________________
www.hazardball.com

#122165 - gho - Sat Mar 17, 2007 2:59 pm

Hi,

I would like to use the FIFO mechanism to let the ARM7 play PSG sounds controlled by ARM9 code.


So far, I set up a structure for the ARM9 and the ARM7 like this:

Code:
typedef struct snd_data {
      u8 channel;
      u8 vol;
      u8 pan;
      u8 duty;
      int freq;
      } psgPlayData, *ptrPsgPlay;


For the ARM7 I have a function, that tells the PSG what to do:

Code:
void playSound(u8 channel, u8 vol, u8 pan, u8 duty, int freq) {

SCHANNEL_TIMER(channel) = SOUND_FREQ(freq << 3);
SCHANNEL_CR(channel) = SOUND_VOL(vol) | SOUND_PAN(pan) | SCHANNEL_WAVEDUTY(duty) | SOUND_FORMAT_PSG | SCHANNEL_ENABLE;

}




For playing a sound the idea is to fill in the structure on the ARM9 side

Code:
psgPlayData test, *ptrPsgPlay;
   ptrPsgPlay=&test;
   
   test.channel=14;
   test.vol=127;
   test.pan=64;
   test.duty=4;
   test.freq=440;


and pass the information to the ARM7 using the FIFO.

Here is my problem: I have no idea, how to get the information in the ARM9 structure over to the ARM7 section. Probably somehow by placing the pointer to the structure on the FIFO? How is this done, and how to "catch" the pointer on the ARM7 side?

Thanks!

#122187 - HyperHacker - Sat Mar 17, 2007 8:00 pm

You have to enable the FIFO on both ends, then write the pointer to that struct into it on ARM9. On ARM7, in your interrupt handler, check the FIFO Not Empty bit, and as long as it's set, keep reading words from the FIFO and doing whatever with them. You'll need some way of indicating that the pointer you just passed points to a snd_data struct; the ideal way to do this is to send a number before the pointer that tells what it's used for.

Just be careful with this; don't point to a local variable, as the ARM7 may not process the message until your function returns, and the pointer will no longer be valid!
_________________
I'm a PSP hacker now, but I still <3 DS.

#122190 - gho - Sat Mar 17, 2007 8:11 pm

Thanks, I will try that out. I get a bit confused by pointers.

#122195 - 0xtob - Sat Mar 17, 2007 8:27 pm

Also beware of caching problems. Before putting the pointer into the queue, make sure the data is written into RAM by flushing the cache for the sound struct using

DC_FlushRange(const void *base, u32 size);
_________________
http://blog.dev-scene.com/0xtob | http://nitrotracker.tobw.net | http://dsmi.tobw.net

#122196 - simonjhall - Sat Mar 17, 2007 8:27 pm

I never like using the fifo, so my IPC stuff starts up by trashing a piece of memory that I don't care about and know the address beforehand (0x2000000)

Here's my IPC startup

ARM7: spin on 0x2000000 not being zero
ARM9: I set 0x2000000 to zero
ARM7: spin on 0x2000000 being zero
ARM9: I malloc space for my IPC struct. I then take the address of this new struct and write it into 0x2000000
ARM9: spin on 0x2000000 not being zero
ARM7: 0x2000000 is now no longer zero, so read the data out of that address and use it as a pointer to my new IPC struct
ARM7: set 0x2000000 to zero
ARM9: restore the original value that was at 0x2000000

Sha-zam - both your processors now have a common block of memory that they both know about. No FIFO nor interrupt hoo-ha needed!

Don't forget to OR the address you get back from malloc with 0x400000 to make sure it's uncached.

When you want to pass a message from one processor to another (eg 7->9), do this:
7: is the struct in use? If so, spin until it's not
7: lock the struct, so the other processor can't use it
7: write the data
7: set the struct's 'ready to be processed' member to true
7: spin on struct being ready to be processed == true
9's vertical blank: if ready to be processed flag = true, process data
9's vertical blank: set ready to be processed to false
7: unlock the struct

So basically, your struct will also need a 'locked' member and a 'ready to be processed' member. Send messages from the 'main thread' of one processor and pick up the results by polling for the ready flag on the other processor (I do it in the hblank)
_________________
Big thanks to everyone who donated for Quake2

#122361 - gho - Sun Mar 18, 2007 10:14 pm

Wow, thanks, it works!

I initialized the snd_data struct outside of the ARM9 main function to make it global (thanks HyperHacker, that was crucial).

Code:
psgPlayData test, *ptrPsgPlay;


and place the pointer on the FIFO queue after flushing like this :

Code:

DC_FlushAll(); //a bit unelegant
REG_IPC_FIFO_TX =   (int) ptrPsgPlay;




On the ARM7 side I have set up a handler for IRQ_FIFO_NOT_EMPTY, which reads the value from the queue:


Code:
void FIFOHandler(void) {

psgPlayData *ptrPsgPlay;
u8 channel;
u8 vol;
u8 pan;
u8 duty;
int freq;
 

    ptrPsgPlay= (psgPlayData *) REG_IPC_FIFO_RX;
      
    channel=(*ptrPsgPlay).channel;
    vol=(*ptrPsgPlay).vol;
    pan=(*ptrPsgPlay).pan;
    duty=(*ptrPsgPlay).duty;
    freq=(*ptrPsgPlay).freq;
      
    playSound(channel, vol, pan, duty, freq);
    
}

.

The casts were a bit tricky, my C is a bit rusted, and I don't understand pointers very well.

Changing PSG behaviour can now simply be done from ARM9 by writing values into the psgPlayData struct.

Exciting! One step closer to a one channel PSG-Tracker. Thanks again all!

Edit:
Flushing before placing the pointer is also crucial to get it to run on hardware. Thanks 0xtob.