[Image]  APEX AUDIO SYSTEM
Instruction Manual

intro | getting started | conv2aas | example | faq
api : index | general | sfx | mod | misc | mixer


:: Introduction

Three simple examples of how to use AAS are included in the "AASExample", "AASExample2" and "AASExample_c++" folders that come with the SDK. "AASExample" and "AASExample_c++" work using the standard interrupt system, although this does mean that sound quality may suffer if it used in conjunction with other CPU-intensive interrupts. "AASExample2" uses a modified interrupt system that will work in all cases, although it does require more care to set up correctly. Feel free to modify the example code for use in your own projects.

The suggested structure for your project folder is as follows (the examples take the aas folder and conv2aas from the ‹root›/build folder present when you execute the Makefile in the root of the project to avoid duplication):


:: Makefile And Includes

In order for your programs to compile successfully they must be linked to the AAS library. To do this, the following options should be passed to the linker:

-L‹path-to›/aas/lib : Adds the "aas/lib" subfolder to the list of folders that will be searched for library files.

-lAAS : Links the AAS library ("libAAS.a") to your project.

In order for the compiler to be able to find AAS's include files, the follow option needs to be specified at the compilation stage:

-I‹path-to›/aas/include : Adds the specified subfolder ("aas/include") to the list of folders that will be searched for include files.

Both of these options are specified in the Makefile included in the project. It may also be necessary to change the "CROSS =" line in the Makefile depending on the location and file names of the GBA tools on your system.

NOTE: the Makefiles in the individual example directories aren't selfcontaining for maintainability reasons. They include example.make which includes common.make. Both are found in ‹root›/make. To make a single makefile out of these, just recursively replace the include directive with the actual content of the included file.

Once the Makefile has been configured appropriately, it is safe to include the AAS header files in your project, as shown in the example code:

#include "AAS.h"
#include "AAS_Data.h"

The "AAS_Data.h" header file contains information specific to your project and is generated by the Conv2AAS program. The makefile included with the example code automatically calls Conv2AAS each time the program is compiled so that your project will always have an up-to-date header file and will be linked to the most recent version of the files in the "AAS_Data" folder.


:: Interrupt Handling

AAS requires for one or some AAS-specific interrupts are set up correctly. This will require some general interrupt system to be set up.

You can use a specialized crt0.s file, which is how AAS used to be configured. But the easiest way to set them up is to use either libgba, or libtonc.

The AAS examples use libtonc as it seems to be the most popular general GBA library these days and because it's got much better documentation (see the reference and the interrupt tutorial). With libtonc, you can easily set the required interrupts from within your C code, provided that you include libtonc in you project.


:: Interrupt Handling setup for the simple case

The "AASExample" and "AASExample_c++" AAS interrupts have been configured for projects with no other CPU intensive interrupts. The only thing you need to do is to include the AAS and libtonc headers, initialize the interrupt handlers and assign AAS_Timer1InterruptHandler to the timer1 interrupt handler.

#include "AAS.h"
#include "AAS_Data.h"
#include "tonc.h"

...

int main() {

...

  // Set up the interrupt handlers
  irq_init(NULL);
  // set timer 1 to AAS_Timer1InterruptHandler()
  irq_add(II_TIMER1, AAS_Timer1InterruptHandler);

...

To understand how the general interrupt mechanism works exactly, read the Tonc interrupt tutorial.


:: Using AAS With Other CPU-Intensive Interrupts

A complication not mentioned in the explanation above is that AAS requires that its interrupt be processed very quickly to avoid audible gaps in the sound. This may cause problems if your code uses other CPU-intensive interrupts. In this situation, you should set up your interrupts a little bit differently.

First you should set up a timer 1 interrupt which automatically calls AAS_FastTimer1InterruptHandler. This is a simple routine that is designed to return quickly so as not to interfere with your own code. However, unlike AAS_Timer1InterruptHandler, AAS_FastTimer1InterruptHandler does not mix the next batch of audio so a seperate call to AAS_DoWork is also required. This must be done at least 50 times per second, although it is safe to do it more often than that. Doing it at the beginning of each VBlank is ideal. This method is demonstrated in "AASExample2". The code used in this case is shown below:

#include "AAS.h"
#include "AAS_Data.h"
#include "tonc.h"

...

int main() {

...

  // Set up the interrupt handlers
  irq_init(NULL);
  // set timer 1 to AAS_FastTimer1InterruptHandler()
  irq_add(II_TIMER1, AAS_FastTimer1InterruptHandler);
  // call AAS_DoWork() during vblank
  irq_add(II_VBLANK, AAS_DoWork);

...

Notice that it is necessary to set the vblank interrupt so that AAS_DoWork() will be called at least 50 times per second.


:: Using AAS

Once all the above is working, using AAS is remarkably simple. The code from "AASExample" is shown below. The code for "AASExample2" is identical apart from the fact that it plays a different MOD and includes the VBlank initialisation code mentioned above. The code for "AASExample_c++" is also very similar except main() is declared with "extern "C"" and again a different MOD is used.

#include "AAS.h"
#include "AAS_Data.h"
#include "tonc.h"

// Registers for GBA keys
#define REG_KEY (*(volatile AAS_u16 *)0x04000130)
#define REG_KEY_A 0x0001
#define REG_KEY_B 0x0002

int main() {
  int keys, keys_changed;
  int prev_keys = 0;

  // Initialise AAS
  AAS_SetConfig(AAS_CONFIG_MIX_32KHZ, AAS_CONFIG_CHANS_8,
                AAS_CONFIG_SPATIAL_STEREO, AAS_CONFIG_DYNAMIC_OFF);

  // Set up the interrupt handlers
  irq_init(NULL);
  // set timer 1 to AAS_Timer1InterruptHandler()
  irq_add(II_TIMER1, AAS_Timer1InterruptHandler);
  
  // Start playing MOD
  AAS_MOD_Play(AAS_DATA_MOD_FlatOutLies);

  // Show AAS Logo (not required)
  AAS_ShowLogo();

  // Main loop
  do {
    // Work out which keys have just been pressed
    keys = ~REG_KEY;
    keys_changed = keys ^ prev_keys;
    prev_keys = keys;

    // Play looping ambulance sound effect out of left speaker if A button is
    // pressed, stop when released
    if (keys_changed & REG_KEY_A) {
      if (keys & REG_KEY_A)
        AAS_SFX_Play(0, 64, 16000, AAS_DATA_SFX_START_Ambulance,
                     AAS_DATA_SFX_END_Ambulance, AAS_DATA_SFX_START_Ambulance);
      else
        AAS_SFX_Stop(0);
    }

    // Play explosion sound effect out of right speaker if B button is pressed
    if (keys_changed & keys & REG_KEY_B)
      AAS_SFX_Play(1, 64, 8000, AAS_DATA_SFX_START_Boom, AAS_DATA_SFX_END_Boom,
                   AAS_NULL);
  } while (1);

  return 0;
}

This code initialises AAS, starts playing FlatOutLies.mod, shows the AAS logo and then goes into an infinite loop whilst the MOD continues to play. Pressing A or B starts the Ambulance.wav or Boom.raw samples. It is important that AAS_SetConfig is called before AAS_MOD_Play, although AAS_ShowLogo can be safely called at any time. For more information about how these functions work, please read the API section of this documentation.