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 > About to flip out and kill someone... (Krawall)

#29476 - Wriggler - Sat Nov 20, 2004 10:37 pm

Hi guys,

I'm working on a project with another guy, and he's set up all the audio using the Krawall library and compiling it in HAM. I thought I'd try and be clever, and try to compile the thing in DevkitAdv. I don't think I realised what I was getting myself into!

I've changed the batch file which we use to make the project, and (after a while) it compiled in devkitadv. I'm not sure if I did it right though, so that could be messing things up.

Then I replaced the interrupt code with the assembler functions from dovotos tutorial (Day 4 part 2). Well, in fact I've only replaced the VBL one as I have no idea how to set up a timer 0 interrupt!

Anyways, the end result is a rom that compiles, but when I try to add the interrupts nothing happens at runtime. I'm left with a black screen.

Here's the first part of sound.c. I hope you can see what I'm trying to do. To be honest, I'm not entirely sure myself so any help would be greatly appreciated.

Thanks in advance.

Code:

// Global var the intrHandler function.
int gl_intr = 0;

#define INT_TIMER1      0x0010
#define INT_TYPE_TIM1   4
#define INT_TYPE_VBL    0


/******************************************************************************
* Check on the krawall interrupt.
******************************************************************************/
void IrqVBlank(void)
{
   gl_intr++;
   if (gl_intr == 2)
   {
      kramWorker();
      gl_intr = 0;
   }
}

/******************************************************************************
* Initalise krawall.
******************************************************************************/
void initSound(void)
{
   kragInit(KRAG_INIT_STEREO);

   //TODO: Replace these HAM interrupts
   //ham_StartIntHandler(INT_TYPE_TIM1,&kradInterrupt);
   //ham_StartIntHandler(INT_TYPE_VBL,&intrHandler);

   //Custom Krawall interrupt setup
   REG_DISPSTAT = (1<<3);
   IRQ_Set(1, IrqVBlank);
}


Cheers,

Ben

#29477 - Wriggler - Sat Nov 20, 2004 10:39 pm

Oh, and here's an extract from Dovoto's headers, as I think it's important for understanding what's going on in the above code.

Code:

//Interrupt table
u32* IntrTable[14];

extern void IrqHandler(void);

//Function to set an interrupt
void IRQ_Set(int irq, u32 irq_handle)
{
   int i;
   for(i=0; i<14; i++)   {
      if(irq & (1<<(i))) { IntrTable[i] = irq_handle; }
   }

   REG_INTERUPT = IrqHandler;      //This is an assembler function
   REG_IME = 0;
   REG_IE |= irq;
   REG_IME = 1;
}


Ben

#29682 - phantom-inker - Tue Nov 23, 2004 9:32 pm

In addition to regularly calling kramWorker(), you need to bind the timer interrupt to Krawall or you'll get nothing.

Sound on the GBA is quirky; there are several actors playing simultaneously, so it can be confusing to determine who does what. Here's a rundown for you:

  • The audio buffer --- RAM --- The audio buffer is an internal part of Krawall that stores the current chunk of digital audio that is being sent out through the speaker.
  • The DMA system --- hardware chip --- The DMA hardware is responsible for actually transferring the data from the audio buffer to the speaker.
  • The timer system --- hardware chip --- At regular intervals, when the DMA runs out of data to transfer, a timer must activate and throw an interrupt that resets the DMA transfer to the start of the audio buffer.
  • kramWorker --- software --- Mixes chunks of sound together in the audio buffer to ensure that the audio buffer is always full.

Krawall manages the audio buffer and DMA, and of course kramWorker() is part of it too.

In your code, you've called kragInit() to initialize Krawall, which is good; you're regularly calling kramWorker() to ensure that the buffer is full, which is good (although doing it on an interrupt is bad if you're not careful; see the Krawall documentation to find out why); however, you never set up the timer interrupt, so when the DMA runs out of data to feed to the speaker (after about a second), the audio just stops.

The sequence you should use is something like this:

  • Assign timer1 to kradInterrupt, and enable IRQs for timer1.
  • Call kragInit().
  • Once per frame in your main loop, call kramWorker(). I recommend against doing this in the vertical interrupt handler (but you can do it in a VCOUNT handler if you know what you're doing).

If those are correct, then functions like krapPlay() will work fine.

Heh, and it seems I have foam-at-the-mouth disease in yet another posting... ^^;
_________________
Do you suppose if I put a signature here, anyone would read it? No? I didn't think so either.

#29685 - Wriggler - Tue Nov 23, 2004 10:33 pm

Ahhhh, that makes things MUCH clearer now, thank you very much! Right, so I need a bit of restructuring and a new interrupt. Nice one. Cheers mate!

Ben