#97366 - cold_as_ice - Wed Aug 09, 2006 1:57 pm
I have a problem when playing sound on the nds.
When i try to play a soundbuffer in arm7 during a vblank it misses a few bytes so my music sounds a little cracky. I hope someone can help me or anyone has a familair problem like me??
I set up my code like this:
ARM9 ------------------------------------------
Here i've set up a system to communicate between arm7 and arm9
typedef struct
{
s8 *mixbuffer;
u32 buffersize,rate;
u8 cmdtype,bits_persample;
u8 snd_swapped;
}S_CommandSystem;
#define commandsystem ((S_CommandSystem*)((u32)(IPC) + sizeof(TransferRegion)))
void InitSoundonArm9(int frequency,int bits)
{
commandsystem->buffersize = frequency / 60;
commandsystem->mixbuffer = malloc(commandsystem->buffersize * 2); // 2 because i use 1 buffer for filling in my routine and the other one for filling it on the arm7.
commandsystem->cmdtype = SYSTEMINIT; // making sure that arm7 gets this bit
}
// -------- During a V-Blank IRQ -------- \\
void Arm9VBlankHandler(void)
{
s8 *buffer;
int size;
buffer = commandsystem->mixbuffer;
size = commandsystem->buffersize;
commandsystem->snd_swapped = 1 - commandsystem->snd_swapped
// buffer1 = being filled/mixed with a custom filling-routine
// buffer2 = being played by arm7
if(commandsystem->snd_swapped == 1)
{
CustomMix(buffer,size / 2);
}
else
{
CustomMix(buffer + (size / 2),size / 2);
}
}
ARM7 ------------------------------------------
// -------- During a V-Blank IRQ -------- \\
void Arm7VBlankHandler(void)
{
s8 * buffer = commandsystem->mixbuffer;
int size = commandsystem->buffersize;
// check for messages sended by arm9
if(commandsystem->cmdtype & PLAYSOUND)
{
SCHANNEL_CR(0) = 0; // make sure nothing's playing
SCHANNEL_TIMER(0) = SOUND_FREQ(22050);
SCHANNEL_REPEAT_POINT(0) = 0;
SCHANNEL_LENGTH(0) = (size / 2) & ~1;
if(commandsystem->snd_swapped == 1)
{
SCHANNEL_SOURCE(0) = (u32)(buffer + (size / 2));
}
else
{
SCHANNEL_SOURCE(0) = (u32)buffer;
}
SCHANNEL_CR(0) = SCHANNEL_ENABLE | SOUND_ENABLE | SOUND_PAN(63) | SOUND_ONE_SHOT | SOUND_VOL(127) | (commandsystem->bpsample == 16 ? SOUND_16BIT : SOUND_8BIT);
commandsystem->cmdtype &= ~PLAYSOUND // discard this bit so it doesn't play again until we fill it in arm9
}
}
Now to sumarize:
arm9:
init the system. allocate the buffer's memory. set frequency. send package to arm7.
to play sound: fill buffer 1,play buffer 2. and swap this every vblank
arm7:
check for incoming packages via arm9. if so try to play.
if buffer1 is filled then buffer2 is played
------------------------------------------------------------------------------------
The CustomMix only fills the buffer that is required. So to play a sound i only mix that buffer with a sound
#97378 - tepples - Wed Aug 09, 2006 2:25 pm
Vblank buffer swapping may have worked on the GBA, but not on the DS because there aren't as many "nice" sample rate ratios. Use an interrupt.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#97386 - Mighty Max - Wed Aug 09, 2006 2:40 pm
Indeed.
Another problem: You mixing in vblank will most likely need more time to put everything up, then the arm7 needs to check for the command. If that happens, the arm7 will handle the data on the next, not the same vblank.
For synching time critical things between processors, use the ipc fifo.
_________________
GBAMP Multiboot
#97432 - DekuTree64 - Wed Aug 09, 2006 6:49 pm
The only way I've gotten software mixing to be fully reliable is using a ring buffer. Instead of disabling the channel and telling it to play the other buffer, just set it up to loop a large single buffer. Then use a hardware timer to count how many samples have been played, and each VBlank, mix samples until the buffer is full again.
In pseudocode:
Code: |
Arm7VBlankHandler:
if (initSystem)
{
Start sound channel, looping the buffer.
Start timer0 at the same rate as the sound channel.
Start timer1 cascading off timer0.
Set commandsystem->prevTimerValue to 0. This is used to see how many samples you need to mix each VBlank.
Set commandsystem->bufferPos to 0. This variable keeps track of where you should start mixing samples into each VBlank.
}
else
{
int timerValue = timer1's current value
int samplesNeeded = timerValue - commandsystem->prevTimerValue
if (samplesNeeded < 0)
samplesNeeded += 65536 // Happens if timer wrapped back to 0
Set commandsystem->prevTimerValue to timerValue.
Mix samplesNeeded samples into the buffer, possibly in 2 batches if you run into the end of the buffer.
Update commandsystem->bufferPos so you know where to start writing samples to next time.
} |
Not sure how much sense that makes, but hopefully it will help.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#97472 - josath - Thu Aug 10, 2006 1:24 am
DekuTree64 wrote: |
The only way I've gotten software mixing to be fully reliable is using a ring buffer. Instead of disabling the channel and telling it to play the other buffer, just set it up to loop a large single buffer. Then use a hardware timer to count how many samples have been played, and each VBlank, mix samples until the buffer is full again. |
That makes sense to me, one quick question: About what size buffers have you found to be optimal? Too big, and there will be some delay before the sound is heard, but too small might cause problems.
#97475 - DekuTree64 - Thu Aug 10, 2006 2:04 am
josath wrote: |
That makes sense to me, one quick question: About what size buffers have you found to be optimal? |
You should only need a few more samples than you would for double buffering, since it's essentially the same thing, but with a little variation in how many samples are mixed each frame. Usually I go with more like 3 frames' worth just to be safe.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#97943 - cold_as_ice - Sat Aug 12, 2006 1:32 pm
Deku can maybe post an example? Somehow i don't hear cracks anymore but my plack is little slow or to fast. Maybe it's because of my buffersize or my interupt at the wrong time or something else??????? This is a little bit with i did
Set timer0 at playrate frequency and let timer1 cascade from it. then in the vblank-handler of arm7 is system == init {
init channels. set channeltimer at 65536 - ((1 << 24) / system->frequency)
play channel with buffersize ((1 << 25) / frequency) / 2
channel source = soundbuffer
}
else
{
int curtimer = TIMER1_DATA;
int samples_needed = curtimer - prevtimer;
if(samples_needed < 0) samples_needed += 65536;
prevtimer = curtimer;
soundbuffer = cursor == 0 ? mixbuffer : mixbuffer + buffersize;
if(cursor == 0) MixSound(&mixbuffer[buffersize],samplestomix);
else MixSound(&mixbuffer[0],samplestomix);
cursor = 1 - cursor;
}
Should i not mix in my vblank? SHould i make a timer-interupt of this... if so at what timer??? Should i even make a timer-interupt. Now i only cascade from timer0 and check in vblank it's amount.
#98121 - cold_as_ice - Sun Aug 13, 2006 10:55 am
I started all over again. But still withouth succes:( I've set up a timer0 with playrate-frequency and timer1 set to cascade and irq enable. and inited the timer1 at 0x1000 - buffersize. It works a little bit. I can hear my music but it's so cracky. Maybe buffersize don't fits the soundchannel??? Anyway i included my sourcecode so maybe you can take a look at it and tell what i'm doing wrong??? I compiled it via Visual Studio and used devkitpro + libnds.
Package includes sounds:)
Get it here Please use [url=] syntax for long URLs -- moderator
#98177 - DekuTree64 - Sun Aug 13, 2006 8:46 pm
Sorry, I was gone most of the day yesterday so I didn't have time to reply here.
I still haven't made the switch to devkitpro r19, so I can't compile the newer one, but I think it has a few more bugs than the original anyway. ringbuffer_deku.zip compiles and runs, and does indeed click a lot.
I need to leave again now though, so I still might not get a chance to mess with the code until tomorrow.
EDIT: Also, I got this confused with this post... I was kind of curious why the code changed so drastically :)
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#98345 - cold_as_ice - Mon Aug 14, 2006 8:18 pm
It almost working, just a few clicks:( How big should i make buffersize (bigger or smaller). Let's say:
frequency = 22050 hz;
buffersize = 2048;
channel_cnt = 8bit playback;
SCHANNEL_LENGTH(0) = (buffersize / 4) & ~3 // for word-alignment
it this correct or am i missing something????
Here's my timer setup:
TIMER0_DATA = TIMER_FREQ_64(rate) & 0xFFFE;
TIMER0_CR = TIMER_ENABLE | TIMER_DIV_64;
TIMER1_DATA = 0;
TIMER1_CR = TIMER_ENABLE | TIMER_CASCADE | TIMER_DIV_1;
I hope someone can help me? If you want i can also post my sourcecode as it is right now
#98358 - DekuTree64 - Mon Aug 14, 2006 9:44 pm
Timer0 should be using TIMER_DIV_1. The purpose of clearing the bottom bit of the period is to make it run at the exact same frequency as the sound channel, and using div64, you'd have to clear bits on the sound channel's period to get it to match.
Which brings me to another problem I just noticed... clearing the bottom bit of the result from the TIMER_FREQ macros won't work. It looks like the macro does something like 0x10000 - SYSTEM_CLOCK / freq, but you need to clear the bottom bit of the SYSTEM_CLOCK / freq part BEFORE the subtraction happens.
Try this instead, because it's guaranteed to match the period perfectly:
Code: |
// 1 << 24 is ~16MHz, which is the sound clock speed
int period = (1 << 24) / 22050;
SCHANNEL_TIMER(0) = 0x10000 - period;
// CPU timers run at twice the frequency of sound timers, so
// wait twice as many cycles before wrapping around
TIMER0_DATA = 0x10000 - (period * 2);
TIMER0_CR = TIMER_ENABLE | TIMER_DIV_1;
...set up timer1 like before |
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#98440 - cold_as_ice - Tue Aug 15, 2006 9:27 am
Yeah finally succes:) It runs pretty good. Btw.. it runs better on the real hardware,the emulator i test on still sounds little shitty(Ideas). I've only got it working with 8bit but i think 16bit shouldn't be that problem now. Thank you very much Deku!!!!
#98441 - GPFerror - Tue Aug 15, 2006 9:36 am
cold_as_ice wrote: |
Yeah finally succes:) It runs pretty good. Btw.. it runs better on the real hardware,the emulator i test on still sounds little shitty(Ideas). I've only got it working with 8bit but i think 16bit shouldn't be that problem now. Thank you very much Deku!!!! |
Could you post the working version of your source please?
thanks,
Troy(GPF)
#98447 - cold_as_ice - Tue Aug 15, 2006 9:52 am
Sure! I also includes the sounds and the binaries so it might be a little big (+- 7 mb). So far it's only working with 8bit. The soundmix routine in arm9main.c could also be anything you want as long as you fill the buffer with the given size. I've only tested it with ideas-emulator and on the real nds so i don't know how other emulators responds to it?
here is the link http://www.yousendit.com/transfer.php?action=check_download&ufid=2B866B7A78592735&key=14e1ac70f256631645b034b4a65bd1fb7abe467e
#99516 - GPFerror - Tue Aug 22, 2006 4:10 am
thanks, I have been able to implement partial sound streaming in my SDL lib now, did you figure out 16bit also yet ?
thanks,
Troy(GPF)
http://gpf.dcemu.co.uk
#100659 - cold_as_ice - Tue Aug 29, 2006 10:33 am
Sorry for the late reaction. I was busy on something else. Maybe you've already found an solution but here's my source with 16bit and 8bit sound. Maybe i'm trying to get this work with module player:) It was actually pretty easy. 8bit to 16bit is just double the buffer sizes and mix the samples as 16bit.
[Extra wide yousendit.com URL no longer widens page -- MOD]
#101805 - josath - Fri Sep 08, 2006 4:28 am
I wish people wouldn't use yousendit/rapidshare/megaupload/etc, the files disappear, and when I want to see them later, I can't :( (since i missed it the first time around)
I guess it's handy for people who don't have any webspace...but still
#101815 - HyperHacker - Fri Sep 08, 2006 6:36 am
Also the downloads are slow, the sites are crammed with ads, getting to the file is often a huge pain involving a completely pointless timer, at least one is completely inaccessible by people with bad sight, etc. Those types of sites have to be one of the most annoying things on the web.
_________________
I'm a PSP hacker now, but I still <3 DS.
#101836 - cold_as_ice - Fri Sep 08, 2006 9:19 am
Lol sorry:) If you wish i can also send it by email or msn. I know rapidshares aren't that great and full off garbage.
#101847 - bsder - Fri Sep 08, 2006 11:04 am
I'd appreciate it if you could email it.
I sent you a PM with my email.
#103127 - toa - Tue Sep 19, 2006 1:37 pm
Can anyone re-seed the yousendit-links with the source code?
None of the latest links works right now.
Thanks in advance
#103129 - Omegas - Tue Sep 19, 2006 1:54 pm
Or put it up on dev-scene.com for everyone to see?
#103250 - toa - Wed Sep 20, 2006 8:27 am
Pretty nifty idea, upload away I say :-D
#103423 - toa - Thu Sep 21, 2006 8:57 pm
http://download.yousendit.com/EAE5B38555115712
Go grab the file, will re-upload in a few weeks time.
thanks to the cold_as_ice for sending me the file via pm!
#104451 - cold_as_ice - Fri Sep 29, 2006 7:50 am
Alright. I managed to restore my old website so i could store this file to stay there. Here is the link to it.http://www.geocities.com/johan_amtsop/soundsync16bit.zip(use copy past for using the link). This might be a little slow(geocities isn't the best host:P). If there's still any error try mailing to johan_amtsop@hotmail.com or send me a pm via msn
#129875 - TheChuckster - Mon May 28, 2007 3:57 pm
Can somebody please rehost the 8bit code? I tried GPF's DSBoy sound streaming code, but it pops and crackles even with a simple square wave. I noticed it popping in DSBoy as well.
EDIT: Nevermind I got the square wave working smoothly.
Thanks GPF.
#129995 - Noda - Tue May 29, 2007 11:08 pm
Where did you find that code? I can't find any trace of it on GPF's site :/
#130016 - GPFerror - Wed May 30, 2007 6:09 am
Noda wrote: |
Where did you find that code? I can't find any trace of it on GPF's site :/ |
http://forum.gbadev.org/viewtopic.php?t=12375&postdays=0&postorder=asc&start=30
has the link to the sourcecode on my site, which is based off of cold_as_ice's posted example from this thread.
Troy(GPF)
http://gpf.dcemu.co.uk
#130031 - Noda - Wed May 30, 2007 10:05 am
Thanks a lot; I'll check that!
I think I'll release a template as this problem is very common, and I need to add some functions that may be useful to others (multiple streams, ADPCM, streaming from fat)
#130353 - Noda - Sat Jun 02, 2007 2:31 pm
Grrr... I still have problems with sound streaming, I can't get it working, and I don't know what is wrong...
I've taken the cold_as_ice example, made it compile with latest DKP: no succes (no sound). I've tried getting the DSBoy streaming system (based on the previous one): still no sound...
I've tried quite a lot exprimentation, modifications, also I've taken a look at M-.-n streaming source, with the same results... I still don't get what is wrong :(
EDIT: FINALLY! I got it (somewhat working) :)
But I have a VERY strange problem, here is my main arm9 loop:
Code: |
while(1)
{
iprintf("\x1b[5;0Hcurrent frame: %d\n",framecounter);
iprintf("current soundbuffer: %X\n",soundsystem->mixbuffer);
iprintf("buffersize: %d\n",soundsystem->buffersize);
iprintf("samples needed %d\n",soundsystem->numsamples);
iprintf("soundformat: %d\n",soundsystem->format);
swiWaitForVBlank();
}
|
If I remove one of those printf, the sound becomes all garbage (sort of alien version of the sound), if they are here, the sound is perfect...
quite strange, isn't it?
#130458 - Noda - Sun Jun 03, 2007 8:04 pm
X-( this bug only occurs on a no$gba, on a real DS everything works fine...
#130463 - tepples - Sun Jun 03, 2007 9:16 pm
Noda wrote: |
X-( this bug only occurs on a no$gba, on a real DS everything works fine... |
If you find something that works on a DS but fails in NO$, then ask Martin Korth if he wants to see the source and binary.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#130464 - Noda - Sun Jun 03, 2007 10:03 pm
Actually I found various things which aren't working great in no$:
- arm9 sync/clock is bad
- fifo seems to work quite randomly
- it seems there's some arm9/7 lock protection problems
When I'll have some time I'll write a mail to him concerning that...
#130478 - tepples - Sun Jun 03, 2007 11:24 pm
When I worked with Forgotten on VisualBoyAdvance, test cases showing behavior differences prompted the quickest response.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#131250 - bsder - Wed Jun 13, 2007 12:56 am
While no$gba gets the pretty interface award, I find that being able to actually dig into the emulator source code is invaluable.
That's why I tend to prefer desmume over no$gba.