diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 2b9a090..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a7e2c67..0000000 --- a/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -build -data -*.gba -*.sav -*.elf - -*.pnproj -.DS_Store \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index f49bd29..0000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "configurations": [ - { - "name": "Mac", - "includePath": [ - "/usr/local/include", - "${workspaceFolder}/**", - "/opt/devkitPro/libtonc/include", - "${workspaceFolder}/source/", - "/opt/devkitPro/devkitARM/arm-none-eabi/include" - ], - "defines": [], - // "intelliSenseMode": "", - "browse": { - "path": [ - // "/usr/local/include", - "${workspaceFolder}/**", - "/opt/devkitPro/devkitARM/arm-none-eabi/include" - ], - "limitSymbolsToIncludedHeaders": true, - "databaseFilename": "" - }, - "macFrameworkPath": [ - "/System/Library/Frameworks", - "/Library/Frameworks" - ] - } - ], - "version": 4 -} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 83c2633..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,43 +0,0 @@ - -{ - // cf. https://github.com/JamieDStewart/GBA_VSCode_Basic/blob/master/.vscode/launch.json - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "2.0.0", - "configurations": [ - { - "name": "(gdb) Launch", - "type": "cppdbg", - "request": "launch", - "preLaunchTask": "gdb-debug", - "postDebugTask": "stop emulation", - "serverLaunchTimeout": 10000, - "stopAtEntry": true, - "program": "${workspaceFolder}/${workspaceFolderBasename}.elf", - "MIMode": "gdb", - "externalConsole": true, - "cwd": "${workspaceFolder}", - "targetArchitecture": "arm", - "miDebuggerServerAddress": "localhost:2345", - "windows": { - "miDebuggerPath": "C:/devkitPro/devkitARM/bin/arm-none-eabi-gdb.exe", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "ignoreFailures": true, - "text": "file ${workspaceFolder}/${workspaceFolderBasename}.elf -enable-pretty-printing" - }] - }, - "osx":{ - "miDebuggerPath": "/opt/devkitPro/devkitARM/bin/arm-none-eabi-gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "ignoreFailures": true, - "text": "file ${workspaceFolder}/${workspaceFolderBasename}.elf -enable-pretty-printing" - }] - }, - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 54827bb..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "files.associations": { - "tonc_types.h": "c", - "tonc_tte.h": "c", - "tonc_video.h": "c", - "tonc_memdef.h": "c", - "camera.h": "c", - "memory.h": "c", - "algorithm": "c", - "stdlib.h": "c", - "math.h": "c", - "draw.h": "c", - "tonc_math.h": "c", - "logutils.h": "c", - "typeinfo": "c", - "__locale": "c", - "tonc_memmap.h": "c", - "tonc_input.h": "c", - "scene.h": "c", - "chrono": "c", - "random": "c", - "iterator": "c", - "timer.h": "c", - "thread": "c" - } -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 87948ef..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "stop emulation", - "type":"shell", - "windows": { - "command":"taskkill /im mGBA.exe /F" - }, - "osx": { - "command": "killall mGBA" - } - }, - { - "label": "make debug", - "type": "process", - "command": "make", - "args": ["DEBUG=1"], - "problemMatcher": [] - }, - { - "label": "make release", - "type": "process", - "command": "make", - "args": ["DEBUG=0"], - "problemMatcher": [] - }, - { - //"dependsOn":"stop emulation", - "label": "clean", - "type": "shell", - "command": "make clean" - }, - { - "label": "gdb-debug", - "type": "shell", - "dependsOn": ["make debug"], - "isBackground": false, - "windows": { - "command": "C:/mGBA/mGBA.exe -g ${workspaceFolder}/${workspaceFolderBasename}.gba;sleep 5;echo debuggerReady" - }, - "osx":{ - "command": "/Users/joni/Documents/Creative/programming/gba/mGBA-0.8.4-osx/Applications/mGBA.app/Contents/MacOS/mGBA", - "args": ["-g", "${workspaceFolder}/${workspaceFolderBasename}.gba", "-l", "15"] - }, - "presentation": { - "clear": true, - "reveal": "always", - "panel": "new" - }, - "command": "debuggerReady", - "problemMatcher": { - "background": { - "activeOnStart": true, - "beginsPattern": "^.*debuggerReady.*$", - "endsPattern": "^.*debuggerReady.*$" - }, - } - }, - { - "label": "run", - "type": "shell", - "isBackground": true, - "command": "C:/NO$GBADebugger/NO$GBA.exe ${workspaceFolder}/${workspaceFolderBasename}.elf", - "problemMatcher": [] - } - ] -} \ No newline at end of file diff --git a/Makefile b/Makefile index cf24df5..26878c1 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,8 @@ endif include $(DEVKITARM)/gba_rules -MGBA := /Applications/mGBA.app/Contents/MacOS/mGBA # for "make run" +# The mGBA binary "make run": +MGBA := /Applications/mGBA.app/Contents/MacOS/mGBA #--------------------------------------------------------------------------------- # TARGET is the name of the output @@ -24,8 +25,8 @@ MGBA := /Applications/mGBA.app/Contents/MacOS/mGBA # for "make run" #--------------------------------------------------------------------------------- TARGET := $(notdir $(CURDIR)) BUILD := build -SOURCES := source source/scenes source/render asm data -INCLUDES := include $(DEVKITPRO)/libtonc/include/ +SOURCES := source source/scenes source/render asm data-models data-audio +INCLUDES := include $(DEVKITPRO)/libtonc/include/ $(CURDIR)/lib/apex-audio-system/build/aas/include/ DATA := MUSIC := @@ -61,14 +62,14 @@ LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $*.map) #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project #--------------------------------------------------------------------------------- -LIBS := -ltonc -lm - +LIBS := -ltonc -lm -lAAS #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- -LIBDIRS := $(DEVKITPRO)/libtonc/ $(LIBGBA) #$(CURDIR)/lib/libtonc/ +LIBDIRS := $(DEVKITPRO)/libtonc/ $(CURDIR)/lib/apex-audio-system/build/aas/ +#$(CURDIR)/lib/libtonc/ $(LIBGBA) #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional @@ -125,26 +126,31 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-iquote$(CURDIR)/$(dir)) \ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) -.PHONY: $(BUILD) clean run +.PHONY: $(BUILD) clean run all + +# Oh my... We have to $(MAKE) $(BUILD), i.e. make the build target with a new invocation of "make", to "recompute" the SOURCE variable (and everything that depends on it) because +# sourcefiles are generated in data-audio and data-models by the invocations of "Makefile-Music" and "Makefile-Models" if applicable. +# If we don't do this, we get linker errors when we "make" after "make clean" (as the newly generated source files in data-audio and data-models won't be considered then until the next "make" invocation). +all: + @$(MAKE) -f $(CURDIR)/assets/Makefile-Music + @$(MAKE) -f $(CURDIR)/assets/Makefile-Models + + @$(MAKE) $(BUILD) #--------------------------------------------------------------------------------- -$(BUILD): + +$(BUILD): @[ -d $@ ] || mkdir -p $@ - # $(MAKE) -C $(CURDIR)/lutcalc -f Makefile @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - -models: $(CURDIR)/assets/models/*.obj - python3 $(CURDIR)/tools/obj2model.py - #--------------------------------------------------------------------------------- clean: @echo clean ... @rm -fr $(BUILD) $(TARGET).elf $(TARGET).gba - @rm -f $(CURDIR)/lutcalc/lutcalc - @rm -f $(CURDIR)/data/* + @rm -f $(CURDIR)/data-models/* + @rm -f $(CURDIR)/data-audio/* -run: $(BUILD) Makefile +run: all Makefile $(MGBA) -2 -l 15 $(OUTPUT).gba #--------------------------------------------------------------------------------- else diff --git a/TODO.md b/TODO.md index 91c3378..6de7fb9 100644 --- a/TODO.md +++ b/TODO.md @@ -1,11 +1,11 @@ # TODO ## Important Features -- [ ] Integration of 'apex audio' for .mod support - [ ] Camera paths (splines?) - [ ] Animations (and "native" wireframe model support (only edges, not faces; maybe even 2d)) - [ ] Particle systems - [ ] Affine texture mapping (cf. fatmap.txt) +- [ ] Subpixel-accuracy (cf. fatmap2.txt) ## Implementation details and Bugfixes - [ ] Proper near-plane clipping @@ -17,6 +17,9 @@ - [ ] Option to calculate the actual centroid of a face for sorting - [ ] Better handling of lookAt singularity (looking completely down/up) +## Misc +- [ ] Create a Readme/How to use + ## Done - [x] Change model-instance draw options to be properties of the model-instances themselves (so we can have different draw styles for different model-instances and don't have to draw all instances the same) - [x] Fix broken performance measurement (calculate proper averages etc.) @@ -25,10 +28,9 @@ - [x] Basic .obj support - [x] Simplify perspective calculations - [x] Don't recalculate vertex projections for each face! -- [x] Better polygon sorting (ordering table) +- [x] Alternative to naive polygon sorting (ordering table) - [x] Mode switching - [x] Backface culling winding order/normal problem -- [x] Key chording for scene switching - -- [x] Handle .obj colours on import (so far, we just set all colours to a default one). -- [x] Use libtonc qran instead of rand +- [x] Key chording/sequences for scene switching +- [x] Handle .obj colours (.mtl) on import +- [x] Integration of 'apex audio system' for .mod support \ No newline at end of file diff --git a/assets/Makefile-Models b/assets/Makefile-Models new file mode 100644 index 0000000..815f9ee --- /dev/null +++ b/assets/Makefile-Models @@ -0,0 +1,4 @@ +# Assumes to be invoked from the project's top-level directory (namely where the top-level devkitarm-based Makefile is located). + +data-models/*.c data-models/*.h &: assets/models/*.obj + python3 tools/obj2model.py \ No newline at end of file diff --git a/assets/Makefile-Music b/assets/Makefile-Music new file mode 100644 index 0000000..c2f60ba --- /dev/null +++ b/assets/Makefile-Music @@ -0,0 +1,7 @@ +# Assumes to be invoked from the project's top-level directory (namely where the top-level devkitarm-based Makefile is located). + +CONV2AAS := lib/apex-audio-system/build/conv2aas/conv2aas + +data-audio/*.s data-audio/*.h &: assets/music + @ $(CONV2AAS) assets/music + @ mv AAS_Data.s AAS_Data.h data-audio \ No newline at end of file diff --git a/assets/music/BuxWV250.mod b/assets/music/BuxWV250.mod new file mode 100644 index 0000000..fde782b Binary files /dev/null and b/assets/music/BuxWV250.mod differ diff --git a/assets/music/aaa.mod b/assets/music/aaa.mod new file mode 100644 index 0000000..e3a5b4d Binary files /dev/null and b/assets/music/aaa.mod differ diff --git a/lib/.DS_Store b/lib/.DS_Store deleted file mode 100644 index 04d7171..0000000 Binary files a/lib/.DS_Store and /dev/null differ diff --git a/lib/apex-audio-system b/lib/apex-audio-system deleted file mode 160000 index 103b1db..0000000 --- a/lib/apex-audio-system +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 103b1db97fb71a320cb4bac8bd40ef106754c697 diff --git a/lib/apex-audio-system/.gitignore b/lib/apex-audio-system/.gitignore new file mode 100644 index 0000000..26f9464 --- /dev/null +++ b/lib/apex-audio-system/.gitignore @@ -0,0 +1,10 @@ +build +*.o +*.sav +*.tmp +*.gba +*.out +*.a +conv2aas +AAS_Data.h +AAS_Data.s diff --git a/lib/apex-audio-system/LICENSE b/lib/apex-audio-system/LICENSE new file mode 100644 index 0000000..10fac9a --- /dev/null +++ b/lib/apex-audio-system/LICENSE @@ -0,0 +1,18 @@ +Copyright (c) 2003-2021 James Daniels + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/apex-audio-system/Makefile b/lib/apex-audio-system/Makefile new file mode 100644 index 0000000..8bfb769 --- /dev/null +++ b/lib/apex-audio-system/Makefile @@ -0,0 +1,93 @@ +# compiler tools prefix used by makefiles for gba executables +# for example, to set to absolute devkitpro path, set to: +# /opt/devkitpro/devkitARM/bin/arm-none-eabi- +export CROSS = /opt/devkitpro/devkitARM/bin/arm-none-eabi- + +# compiler tools prefix used by makefiles for conv2aas executable +# for example, the empty prefix below will use the system gcc tools +export PREFIX = + +# example names +export EXAMPLE_PREFIX=AASExample +export EXAMPLE2_PREFIX=AASExample2 +export EXAMPLE_CPP_PREFIX=AASExamplePlusPlus + +BUILD = build + +AAS_DIR = src/aas +CONV2AAS_DIR = src/conv2aas +EXAMPLE_DIR = examples/AASExample +EXAMPLE2_DIR = examples/AASExample2 +EXAMPLE_CPP_DIR = examples/AASExample_c++ + +CONV2AAS_FILE = conv2aas +ifeq ($(OS),Windows_NT) + CONV2AAS_FILE = conv2aas.exe +endif + +LIB = $(BUILD)/aas/lib +INCLUDE = $(BUILD)/aas/include +BUILD_AAS = $(LIB)/libAAS.a +BUILD_CONV2AAS_DIR = $(BUILD)/conv2aas +BUILD_CONV2AAS = $(BUILD_CONV2AAS_DIR)/$(CONV2AAS_FILE) +BUILD_EXAMPLES = $(BUILD)/examples + +AAS = $(AAS_DIR)/libAAS.a +CONV2AAS = $(CONV2AAS_DIR)/$(CONV2AAS_FILE) +EXAMPLE = $(EXAMPLE_DIR)/$(EXAMPLE_PREFIX).gba +EXAMPLE2 = $(EXAMPLE2_DIR)/$(EXAMPLE2_PREFIX).gba +EXAMPLE_CPP = $(EXAMPLE_CPP_DIR)/$(EXAMPLE_CPP_PREFIX).gba + +.PHONY: all aas conv2aas example example2 example_cpp + +all: aas conv2aas example example2 example_cpp + +$(AAS): + $(MAKE) -e -C $(AAS_DIR) + +$(BUILD_AAS): $(AAS) + mkdir -p $(LIB) + mkdir -p $(INCLUDE) + cp $(AAS) $(LIB) + cp $(AAS_DIR)/AAS.h $(INCLUDE) + cp $(AAS_DIR)/AAS_Mixer.h $(INCLUDE) + +aas: $(BUILD_AAS) + +$(CONV2AAS): + $(MAKE) -e -C $(CONV2AAS_DIR) + +$(BUILD_CONV2AAS): $(CONV2AAS) + mkdir -p $(BUILD_CONV2AAS_DIR) + cp $(CONV2AAS) $(BUILD_CONV2AAS_DIR) + +conv2aas: $(BUILD_CONV2AAS) + +$(EXAMPLE): $(BUILD_AAS) $(BUILD_CONV2AAS) + $(MAKE) -e -C $(EXAMPLE_DIR) + +example: $(EXAMPLE) + mkdir -p $(BUILD_EXAMPLES) + cp $(EXAMPLE) $(BUILD_EXAMPLES) + +$(EXAMPLE2): $(BUILD_AAS) $(BUILD_CONV2AAS) + $(MAKE) -e -C $(EXAMPLE2_DIR) + +example2: $(EXAMPLE2) + mkdir -p $(BUILD_EXAMPLES) + cp $(EXAMPLE2) $(BUILD_EXAMPLES) + +$(EXAMPLE_CPP): $(BUILD_AAS) $(BUILD_CONV2AAS) + $(MAKE) -e -C $(EXAMPLE_CPP_DIR) + +example_cpp: $(EXAMPLE_CPP) + mkdir -p $(BUILD_EXAMPLES) + cp $(EXAMPLE_CPP) $(BUILD_EXAMPLES) + +clean: + $(MAKE) -C $(AAS_DIR) clean + $(MAKE) -C $(CONV2AAS_DIR) clean + $(MAKE) -C $(EXAMPLE_DIR) clean + $(MAKE) -C $(EXAMPLE2_DIR) clean + $(MAKE) -C $(EXAMPLE_CPP_DIR) clean + rm -r build diff --git a/lib/apex-audio-system/README.md b/lib/apex-audio-system/README.md new file mode 100644 index 0000000..b811ef9 --- /dev/null +++ b/lib/apex-audio-system/README.md @@ -0,0 +1,48 @@ +### Apex Audio System + +The Apex Audio System (AAS) is a sound library for the GBA. It includes a highly +efficient mixer, MOD playing routines and support for up to 16 channels. It is +designed for developers using a GCC-based development environment. AAS uses RAW, +WAV or *tracker 1-16 channel MOD files as input. + + +## Documentation + +AAS is fairly well documented. From building the library to a starter guide to +an extensive description of the api. See /docs/index.html + + +## History + +Apex Audio System was made by James Daniels of Apex Systems back in 2003 for the +GBA version of Payback. The library underwent several revisions, the latest of +which was v1.11. At the beginning of 2021, James was so kind to donate the +sources to the community, hence this Git repo. + + +## Latest release + +The current release is v1.12. See the documentation for a list of changes. + + +## Contact + +Github project page: https://github.com/stuij/apex-audio-system + +Pull requests are welcome, as are forks of course. If you want to report issues, +open an issue on the Github project issue tracker. + +For a more realtime interactive experience, join gbadev on Discord. There's a +good chance there's one or two people there that have used AAS before. + + +## License + +AAS is now distributed under the MIT license. For licensing terms, see the +LICENSE file in the root of this repo or go to +http://opensource.org/licenses/MIT + +James only had one request when handing over the sources: that users of the +library include a credit to Apex Designs. In essence this is now covered by the +MIT license. It's up to you how you want to fill this in, but please be +respectful of this requirement. diff --git a/lib/apex-audio-system/docs/api_general.html b/lib/apex-audio-system/docs/api_general.html new file mode 100644 index 0000000..ee26868 --- /dev/null +++ b/lib/apex-audio-system/docs/api_general.html @@ -0,0 +1,323 @@ + + + +AAS Instructions + + + + + + + + +
+ + + + + +
+[Image]  + +APEX AUDIO SYSTEM
+Instruction Manual +
+
+
+
+intro | getting started | conv2aas | example | faq
+api : index | general | sfx | mod | misc | mixer +
+ +
+ +
:: AAS_SetConfig +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_SetConfig( int config_mix, int config_chans, int config_spatial, int config_dynamic );
FUNCTIONSets the effective mixing rate, number of channels, volume boost, mono/stereo output and switches dynamic mixing on or off. Must be called before using any other AAS functions.
PARAMETERS + + + + + + + + + + + + + + + + + + + + + + + + + +
NameValid valuesMeaning
config_mix +AAS_CONFIG_MIX_32KHZ
+AAS_CONFIG_MIX_28KHZ
+AAS_CONFIG_MIX_24KHZ
+AAS_CONFIG_MIX_20KHZ
+AAS_CONFIG_MIX_16KHZ
+AAS_CONFIG_MIX_12KHZ
+AAS_CONFIG_MIX_8KHZ +
Specifies the effective mixing rate
config_chans +AAS_CONFIG_CHANS_16
+AAS_CONFIG_CHANS_8
+AAS_CONFIG_CHANS_4
+AAS_CONFIG_CHANS_16_LOUD
+AAS_CONFIG_CHANS_8_LOUD
+AAS_CONFIG_CHANS_4_LOUD +
Specifies the maximum number of channels and whether the output should be volume boosted and clipped
config_spatial +AAS_CONFIG_SPATIAL_STEREO
+AAS_CONFIG_SPATIAL_MONO +
Specifies mono/stereo output
config_dynamic +AAS_CONFIG_DYNAMIC_OFF
+AAS_CONFIG_DYNAMIC_ON
Specifies dynamic mixing on/off (see NOTES)
RETURNS + + + + + + + + + + +
AAS_OK:Function executed correctly.
AAS_ERROR_INVALID_CONFIG:Invalid configuration requested.
NOTES +

This function should be called at least once before calling any other AAS functions. It can also be used to change the audio settings, although doing so will stop any sounds that are currently playing. The recommended configuration is 24KHz AAS_CONFIG_CHANS_8 mono with dynamic mixing disabled.

+

The AAS_CONFIG_CHANS_x_LOUD modes increase the volume of the output but take ~10% more CPU time and can cause the sound to distort in some cases. They are not recommended for use with the 4 channel modes but are strongly encouraged when using 16 channels.

+

Dynamic mixing automatically adjusts the mixing rate depending on the frequency of the sounds being played, up to a maximum of the mixing rate you specified. Disabling it will cause AAS to always use the mixing rate you chose. Dynamic mixing is still somewhat experimental, but it often yields a significant performance boost for only a very small drop in quality.

+

If stereo mode is used the SFX channels are arranged as follows:

+
    +
  • SFX Channel 0 : Left
  • +
  • SFX Channel 1 : Right
  • +
  • SFX Channel 2 : Right
  • +
  • SFX Channel 3 : Left
  • +
  • SFX Channel 4 : Left
  • +
  • SFX Channel 5 : Right
  • +
  • SFX Channel 6 : Right
  • +
  • SFX Channel 7 : Left
  • +
  • SFX Channel 8 : Left
  • +
  • SFX Channel 9 : Right
  • +
  • SFX Channel 10 : Right
  • +
  • SFX Channel 11 : Left
  • +
  • SFX Channel 12 : Left
  • +
  • SFX Channel 13 : Right
  • +
  • SFX Channel 14 : Right
  • +
  • SFX Channel 15 : Left
  • +
+

In mono mode, all sounds come out both speakers.

+

The number of channels you can access is limited by the number that are already being used to play a MOD. So, if you're playing a 3 channel MOD in AAS_CONFIG_CHANS_4 mode then only the first channel (channel 0) will be available for playing sound effects. If AAS_CONFIG_CHANS_8 were used in the same situation then the first 5 channels (channels 0-4) would be available.

+
+
+ +
:: AAS_Timer1InterruptHandler +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_Timer1InterruptHandler();
FUNCTIONEither this or AAS_FastTimer1InterruptHandler must be quickly called when a Timer 1 interrupt occurs.
PARAMETERSNone
RETURNSNothing
NOTES +

The Timer 1 interrupt occurs roughly 50 times per second and this routine must be called by the user's interrupt handler each time the appropriate interrupt occurs. For more information about this please read the getting started section and, for example interrupt handling code, please read the example section.

+

This routine also mixes the next batch of audio so it can take a long time to return. This may cause problems if you have other CPU-intensive interrupts in your code. In these cases, AAS_FastTimer1InterruptHandler, AAS_DoWork and the special "__AAS_MultipleInterrupts" mode in the crt0.s file used in AASExample2 should be used instead of the normal interrupt handling modes.

+
+
+ +
:: AAS_FastTimer1InterruptHandler +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_FastTimer1InterruptHandler();
FUNCTIONEither this or AAS_Timer1InterruptHandler must be quickly called when a Timer 1 interrupt occurs. AAS_DoWork must also be called 50 times per second if AAS_FastTimer1InterruptHandler is used.
PARAMETERSNone
RETURNSNothing
NOTES +

This function also requires a seperate (less time-sensitive) call to AAS_DoWork at least 50 times a second. This function is called automatically if the special "AAS_MultipleInterrupts" mode in the custom crt0.s file included with the SDK is used.

+

The Timer 1 interrupt occurs roughly 50 times per second and this routine must be called by the user's interrupt handler each time the appropriate interrupt occurs. For more information about this please read the getting started section and, for example interrupt handling code, please read the example section.

+

This routine starts the next piece of audio playing, but does not mix the batch of audio that will be played after that. This means that this routine returns very quickly but a seperate call to AAS_DoWork is also required within the next 50th of a second. The ideal place to call AAS_DoWork is during VBlank. To prevent AAS_FastTimer1InterruptHandler() being halted by another interrupt, the special "__AAS_MultipleInterrupts" mode in the crt0.s file used in AASExample2 should also be used.

+

Alternatively, if your code does not use other CPU-intensive interrupts then you can use a normal interrupt handler and AAS_Timer1InterruptHandler. In this case there is no need for a seperate call to AAS_DoWork. An example of this method of handling interrupts is shown in AASExample.

+
+
+ +
:: AAS_DoWork +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_DoWork();
FUNCTIONMixes the next batch of audio. Should only be used in conjunction with AAS_FastTimer1InterruptHandler.
PARAMETERSNone
RETURNSNothing
NOTES +

This function should be called at least 50 times a second (during VBlank, for example) if you're using AAS_FastTimer1InterruptHandler. If you're using AAS_Timer1InterruptHandler instead then AAS_DoWork should not be called at all.

+

Should only be used in conjunction with AAS_FastTimer1InterruptHandler and the special "__AAS_MultipleInterrupts" mode in the crt0.s file used in AASExample2. Alternatively, AAS_Timer1InterruptHandler can be used with the standard interrupt handlers but this will not work correctly if there are other CPU-intensive interrupts in your code.

+
+
+ +
:: AAS_DoDMA3 +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_DoDMA3( void* source, void* dest, AAS_u32 flags_and_length );
FUNCTIONAllows DMA3 to be used safely.
PARAMETERS + + + + + + + + + + + + + + + + + + + + +
NameValid valuesMeaning
source +Depends on flags_and_length +Specifies source address
dest +Depends on flags_and_length +Specifies dest address
flags_and_length +See GBA docs +See GBA docs
RETURNSNothing
NOTES +

The mixer uses DMA3 internally, which means it is no longer safe to use DMA3 in your code in the usual way since the mixer might interrupt it halfway through and corrupt the parameters. To fix this you should either use AAS_DoDMA3 or the stmia assembler instruction to write all parameters with a single instruction.

+
+
+ +
:: AAS_ShowLogo +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_ShowLogo();
FUNCTIONDisplays the AAS splash screen.
PARAMETERSNone
RETURNSNothing
NOTES +

It is entirely optional for projects to use this splash-screen on startup from v1.12 onwards, now that this is an open-source project. This is a change from the v1.11 release back in 2008 and earlier. Although the creator does still appreciate attribution. Please read about licensing here.

+
+
+ + + diff --git a/lib/apex-audio-system/docs/api_index.html b/lib/apex-audio-system/docs/api_index.html new file mode 100644 index 0000000..d6faebf --- /dev/null +++ b/lib/apex-audio-system/docs/api_index.html @@ -0,0 +1,274 @@ + + + +AAS Instructions + + + + + + + + +
+ + + + + +
+[Image]  + +APEX AUDIO SYSTEM
+Instruction Manual +
+
+
+
+intro | getting started | conv2aas | example | faq
+api : index | general | sfx | mod | misc | mixer +
+ +
+ +
:: General Functions +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AAS_SetConfig:Sets the effective mixing rate, number of channels, volume boost, mono/stereo output and switches dynamic mixing on or off. Must be called before using any other AAS functions.
AAS_Timer1InterruptHandler:Either this or AAS_FastTimer1InterruptHandler must be quickly called when a Timer 1 interrupt occurs.
AAS_FastTimer1InterruptHandler:Either this or AAS_Timer1InterruptHandler must be quickly called when a Timer 1 interrupt occurs. AAS_DoWork must also be called 50 times per second if AAS_FastTimer1InterruptHandler is used.
AAS_DoWork:Mixes the next batch of audio. Should only be used in conjunction with AAS_FastTimer1InterruptHandler.
AAS_DoDMA3:Allows DMA3 to be used safely.
AAS_ShowLogo:Displays the AAS splash screen.
+ +
+
:: SFX Functions +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AAS_SFX_Play:Starts playing the specified sample.
AAS_SFX_ChannelExists:Returns AAS_TRUE only if AAS_SFX_Play will succeed for this channel, otherwise returns AAS_FALSE.
AAS_SFX_IsActive:Returns AAS_TRUE if channel is valid and active, AAS_FALSE otherwise.
AAS_SFX_EndLoop:If a looping sample was playing in this channel, it will not loop again at end of the current iteration.
AAS_SFX_SetFrequency:Changes the frequency of the sample playing in the specified channel.
AAS_SFX_SetVolume:Changes the volume of the sample playing in the specified channel.
AAS_SFX_Stop:Stops the sample currently playing in the specified channel.
AAS_SFX_Resume:Resumes a channel that has been previously stopped.
AAS_SFX_GetNumChannels:Returns the number of SFX channels that are currently available.
+ +
+
:: MOD Functions +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AAS_MOD_Play:Starts playing the specified MOD file.
AAS_MOD_SetLoop:Specifies whether the current MOD will loop. All MODs loop by default.
AAS_MOD_Stop:Stops playing current MOD.
AAS_MOD_Pause:Pauses the current MOD. It can be continued later using AAS_MOD_Resume.
AAS_MOD_Resume:Resumes a MOD that was previously paused using AAS_MOD_Pause.
AAS_MOD_IsPlaying:Checks whether a MOD is currently playing.
AAS_MOD_HasLooped:Checks whether or not the current MOD has looped.
AAS_MOD_GetVolume:Returns the current volume for MOD tunes. 0 = silent, 256 = max.
AAS_MOD_SetVolume:Sets the current volume for MOD tunes. 0 = silent, 256 = max.
AAS_MOD_GetSongPos:Returns the current song position of the playing MOD.
AAS_MOD_SetSongPos:Immediately jumps to the specified song position.
AAS_MOD_QueueSongPos:Jumps to the specified song position when the current pattern finishes.
AAS_MOD_GetLineNum:Returns the current line number of the playing MOD.
AAS_MOD_GetLastFilterValue:Returns the value specified by the most recent "E0: Set Filter" effect. Can be used to sychronise code with the music.
AAS_MOD_GetNumChannels:Returns the number of channels that are currently being reserved by the MOD.
+ +
+
:: Misc Functions +
+ + + + + + + + + + + + + + + + + +
AAS_GetOutputBufferAddress:Gets the address of the specified mixing buffer. Can be used to make oscilliscope displays of the current output.
AAS_GetOutputBufferLength:Gets the current length of the mixing buffer in bytes.
AAS_GetActualMixRate:Returns the current mixing rate in hertz.
+ +
+
:: Mixer Functions +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AAS_MixAudio:Mixes multiple sounds into a single mixing buffer. This function is in IWRAM and so it must be called using AAS_INIT_BRANCH and AAS_BRANCH() as described in "AAS_Mixer.h". This function should not normally be directly called.
AAS_MixAudio_NoChange:Mixes multiple sounds into a single mixing buffer. This function should only be called if there are no changes to chans[] since a previous call to AAS_MixAudio. Do not call twice in a row. This function is in IWRAM and so it must be called using AAS_INIT_BRANCH and AAS_BRANCH() as described in "AAS_Mixer.h". This function should not normally be directly called - see AAS_MixAudio.
AAS_MixAudio_SetMode:Enable/disable volume boost and (optional) clipping. This function should only be called if you can be 100% sure that AAS_MixAudio and AAS_MixAudio_NoChange won't interrupt it. This function should not normally be directly called - see AAS_MixAudio.
AAS_MixAudio_SetMaxChans_2:Sets the maximum number of channels in the set to 2. This function should only be called if you can be 100% sure that AAS_MixAudio and AAS_MixAudio_NoChange won't interrupt it. This function should not normally be directly called - see AAS_MixAudio.
AAS_MixAudio_SetMaxChans_4:Sets the maximum number of channels in the set to 4 (the default). This function should only be called if you can be 100% sure that AAS_MixAudio and AAS_MixAudio_NoChange won't interrupt it. This function should not normally be directly called - see AAS_MixAudio.
AAS_MixAudio_SetMaxChans_8:Sets the maximum number of channels in the set to 8. This function should only be called if you can be 100% sure that AAS_MixAudio and AAS_MixAudio_NoChange won't interrupt it. This function should not normally be directly called - see AAS_MixAudio.
+ +
+ + + diff --git a/lib/apex-audio-system/docs/api_misc.html b/lib/apex-audio-system/docs/api_misc.html new file mode 100644 index 0000000..b65b864 --- /dev/null +++ b/lib/apex-audio-system/docs/api_misc.html @@ -0,0 +1,163 @@ + + + +AAS Instructions + + + + + + + + +
+ + + + + +
+[Image]  + +APEX AUDIO SYSTEM
+Instruction Manual +
+
+
+
+intro | getting started | conv2aas | example | faq
+api : index | general | sfx | mod | misc | mixer +
+ +
+ +
:: AAS_GetOutputBufferAddress +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEconst AAS_s8* AAS_GetOutputBufferAddress( int buffer );
FUNCTIONGets the address of the specified mixing buffer. Can be used to make oscilliscope displays of the current output.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
buffer +0 or 1 +Specifies direct sound channel you want to get the mixing buffer for. 0 = Direct Sound A, 1 = Direct Sound B.
RETURNS + + + + + + + + + + +
AAS_NULL:The buffer you requested does not exist or is currently not being used (during a period of silence, for example).
Any valid address:The address of the start of the mixing buffer currently being used for the specified buffer.
NOTES +

Altering the values found in the mixing buffer may corrupt the sound output.

+
+
+ +
:: AAS_GetOutputBufferLength +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_GetOutputBufferLength();
FUNCTIONGets the current length of the mixing buffer in bytes.
PARAMETERSNone
RETURNS + + + + + +
Any integer:The current length of the mixing buffer in bytes.
NOTES +

Altering the values found in the mixing buffer may corrupt the sound output.

+
+
+ +
:: AAS_GetActualMixRate +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_GetActualMixRate();
FUNCTIONReturns the current mixing rate in hertz.
PARAMETERSNone
RETURNS + + + + + +
800-32000:The current mixing rate in hertz.
NOTES +

This function will always return the mixing rate you specified when you called AAS_SetConfig if you disabled dynamic mixing. With dynamic mixing enabled this value may be less than the rate you specified.

+
+
+ + + diff --git a/lib/apex-audio-system/docs/api_mixer.html b/lib/apex-audio-system/docs/api_mixer.html new file mode 100644 index 0000000..c6b8690 --- /dev/null +++ b/lib/apex-audio-system/docs/api_mixer.html @@ -0,0 +1,366 @@ + + + +AAS Instructions + + + + + + + + +
+ + + + + +
+[Image]  + +APEX AUDIO SYSTEM
+Instruction Manual +
+
+
+
+intro | getting started | conv2aas | example | faq
+api : index | general | sfx | mod | misc | mixer +
+ +
+ +
:: AAS_MixAudio +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_MixAudio( AAS_s8* mix_buffer, struct AAS_Channel chans[], int iterations );
FUNCTIONMixes multiple sounds into a single mixing buffer. This function is in IWRAM and so it must be called using AAS_INIT_BRANCH and AAS_BRANCH() as described in "AAS_Mixer.h". This function should not normally be directly called.
PARAMETERS + + + + + + + + + + + + + + + + + + + + +
NameValid valuesMeaning
mix_buffer +Any writeable word-aligned address at least iterations*16 bytes in size +Specifies the address of the mixing buffer you wish to use
chans +Any writeable word-aligned address pointing to valid channel data +The start address of an array of 8 AAS_Channel structures
iterations +1-127 +The number of 16 byte chunks you wish the function to write to mix_buffer
RETURNSNothing
NOTES +

This function (and the others in this section of the documentation) should only be used if you've got a strong reason for needing to access the mixing routine directly. Because of this, it isn't included in the usual "AAS.h" header file - you'll need to include "AAS_Mixer.h" instead, which is in the "aas/" folder of either the release or the ‹root›/build file when building from source. A good understanding of the GBA's sound hardware is required to use this routine directly.

+ +

The AAS_Channel structure is defined in the header file as follows:

+ +
+struct AAS_Channel
+{
+	AAS_u8 effective_volume;
+	AAS_BOOL active;
+	AAS_u8 volume;
+	AAS_u8 pos_fraction;
+	AAS_u16 frequency;
+	AAS_u16 delta;
+	const AAS_s8* pos;
+	const AAS_s8* end;
+	AAS_u32 loop_length;
+};
+ +

The meaning of these elements is shown below:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameValid valuesMeaning
effective_volume +0-255 (see below) +Specifies the volume of this channel. Channels with an effective_volume of zero will not be processed. This should usually be set to (active?volume:0) before calling AAS_MixAudio. Zero will be written here by the mixer when a non-looping sample finishes.
active +AAS_TRUE or AAS_FALSE +AAS_MixAudio does not read this value but it does write AAS_FALSE here when a non-looping sample finishes. (See effective_volume.)
volume +0-255 +Not directly used by AAS_MixAudio. (See effective_volume.)
pos_fraction +Any +The fractional component of the sample position. This value should be reset to zero when a sample is started, but other than that it should only be changed by AAS_MixAudio.
frequency +1-65535 +Not directly used by AAS_MixAudio. (See delta.)
delta +1-4095 +Specifies how much to add on to the sample position per byte in 2.10 fixed point format. Usually set to ((frequency<<10)/mixing_frequency) before calling AAS_MixAudio.
pos +Any valid address +The address of the current sample position. The fractional component is stored in pos_fraction.
end +Any valid address +The address of the end of the sample.
loop_length +Any +The number of bytes from the end of the sample back to the loop restart point. Zero indicates that the sample should not loop.
+ +

AAS_MixAudio expects to be passed a pointer to an array of 8 AAS_Channels - this is referred to as a channel set. An array containing 16 AAS_Channels is provided and is called AAS_channels[]. This can effectively be used as two seperate arrays of 8 AAS_Channels by calling using either &AAS_channels[0] or &AAS_channels[8] as a parameter. This allows a total of 16 channels - 8 per Direct Sound output. (The maximum number of channels per set is specified using the AAS_MixAudio_SetMaxChans_x functions - the default is 4.)

+ +

Also note that the total volume (i.e. the sum of the effective_volumes for all the channels in the set) must not exceed 256 (except if AAS_MIXAUDIO_MODE_BOOST is used (see AAS_MixAudio_SetMode), in which case the total must not exceed 128). If it does, the sound output will be distorted. This means that, despite 255 (127 with AAS_MIXAUDIO_MODE_BOOST) being a valid volume for a channel as indicated above, it is only safe to set a volume this high if the total effective_volume of the remaining channels in the channel set is 0 or 1. This means that if you intend to use all 8 channels in the set then you should generally use volumes in the range 0-32 (0-16 with AAS_MIXAUDIO_MODE_BOOST).

+ +

A few other things worth noting about this routine:

+
    +
  • It doesn't increment pos if a channel's effective_volume is 0. You'll need to increment it yourself if you want this to happen.
  • +
  • Do not call AAS_MixAudio if there are no active channels in the set. Use a seperate routine to write out zeroes to the buffer or use a pre-calculated buffer full of zeroes instead.
  • +
  • The dynamic mixing rate feature is also handled by a different routine so you cannot use this feature if you are accessing AAS_MixAudio directly without implimenting your own code to change the mixing rate.
  • +
  • All sample data should be 8-bit signed and clipped to the range -127 to 127. (Rather than the usual range of -128 to 127.) If this extra bit of clipping is not done then the sound may occasionally distort. Conv2AAS does this automatically, but if you're using a different program to import your sample data (not recommended) then you will need to preprocess the data to avoid this problem.
  • +
  • The mixer does not sanity check the input parameters. The result of passing illegal parameters is undefined.
  • +
  • AAS_MixAudio uses DMA 3, which may cause problems if it is called via an interrupt whilst another bit of code is halfway through initialising a DMA 3 transfer. AAS_DoDMA3 should be used to prevent this problem. This routine works by writing all the values required to start a DMA transfer with a single stmia instruction. You can do this in your own code as an alternative to calling AAS_DoDMA3.
  • +
  • You will need to set up your own sound handling routines and interrupts around the mixer to get it work usefully. This is normally handled by AAS but this is not possible when AAS_MixAudio is directly accessed. It should not be used in conjunction with any of the standard AAS commands with the exception of AAS_ShowLogo and AAS_DoDMA3.
  • +
  • Also bare in mind that the API for this routine is more likely to change in future versions of AAS than those for the other routines. [Last changed in v1.11]
  • +
+ +
+
+ +
:: AAS_MixAudio_NoChange +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_MixAudio_NoChange( AAS_s8* mix_buffer, struct AAS_Channel chans[], int iterations );
FUNCTIONMixes multiple sounds into a single mixing buffer. This function should only be called if there are no changes to chans[] since a previous call to AAS_MixAudio. Do not call twice in a row. This function is in IWRAM and so it must be called using AAS_INIT_BRANCH and AAS_BRANCH() as described in "AAS_Mixer.h". This function should not normally be directly called - see AAS_MixAudio.
PARAMETERSSee AAS_MixAudio.
RETURNSNothing
NOTES +

This function works in the same way as AAS_MixAudio, except that it is slightly faster but should only be called if there are no changes to chans[] since a previous call to AAS_MixAudio. It should also not be called twice in a row.

+
+
+ +
:: AAS_MixAudio_SetMode +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_MixAudio_SetMode( int mode );
FUNCTIONEnable/disable volume boost and (optional) clipping. This function should only be called if you can be 100% sure that AAS_MixAudio and AAS_MixAudio_NoChange won't interrupt it. This function should not normally be directly called - see AAS_MixAudio.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
mode +AAS_MIXAUDIO_MODE_NORMAL
+AAS_MIXAUDIO_MODE_BOOST
+AAS_MIXAUDIO_MODE_BOOSTANDCLIP +
Specifies whether the volume should be boosted and (optionally) clipped
RETURNSNothing
NOTES +

The three mixing modes work as follows:

+ +
    +
  • AAS_MIXAUDIO_MODE_NORMAL. No volume boosting. The total volume of the channel set must be <= 256. This is the default setting.
  • +
  • AAS_MIXAUDIO_MODE_BOOST. All volumes are doubled. The output is not clipped so the total volume of the channel set must be <= 128 otherwise severe distortion will occur.
  • +
  • AAS_MIXAUDIO_MODE_BOOSTANDCLIP. All volumes are doubled. The output is clipped so the total volume of the channel set must be <= 256.
  • +
+
+
+ +
:: AAS_MixAudio_SetMaxChans_2 +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_MixAudio_SetMaxChans_2();
FUNCTIONSets the maximum number of channels in the set to 2. This function should only be called if you can be 100% sure that AAS_MixAudio and AAS_MixAudio_NoChange won't interrupt it. This function should not normally be directly called - see AAS_MixAudio.
PARAMETERSNone
RETURNSNothing
NOTES +

For best performance, the maximum number of channels in the set should be set to the lowest number that is >= the actual number of channels in the set.

+
+
+ +
:: AAS_MixAudio_SetMaxChans_4 +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_MixAudio_SetMaxChans_4();
FUNCTIONSets the maximum number of channels in the set to 4 (the default). This function should only be called if you can be 100% sure that AAS_MixAudio and AAS_MixAudio_NoChange won't interrupt it. This function should not normally be directly called - see AAS_MixAudio.
PARAMETERSNone
RETURNSNothing
NOTES +

For best performance, the maximum number of channels in the set should be set to the lowest number that is >= the actual number of channels in the set.

+
+
+ +
:: AAS_MixAudio_SetMaxChans_8 +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_MixAudio_SetMaxChans_8();
FUNCTIONSets the maximum number of channels in the set to 8. This function should only be called if you can be 100% sure that AAS_MixAudio and AAS_MixAudio_NoChange won't interrupt it. This function should not normally be directly called - see AAS_MixAudio.
PARAMETERSNone
RETURNSNothing
NOTES +

For best performance, the maximum number of channels in the set should be set to the lowest number that is >= the actual number of channels in the set.

+
+
+ + + diff --git a/lib/apex-audio-system/docs/api_mod.html b/lib/apex-audio-system/docs/api_mod.html new file mode 100644 index 0000000..03fa1bf --- /dev/null +++ b/lib/apex-audio-system/docs/api_mod.html @@ -0,0 +1,649 @@ + + + +AAS Instructions + + + + + + + + +
+ + + + + +
+[Image]  + +APEX AUDIO SYSTEM
+Instruction Manual +
+
+
+
+intro | getting started | conv2aas | example | faq
+api : index | general | sfx | mod | misc | mixer +
+ +
+ +
:: AAS_MOD_Play +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_MOD_Play( int song_num );
FUNCTIONStarts playing the specified MOD file.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
song_num +AAS_DATA_MOD_???, where ??? is the name of the MOD you wish to play (see your project's AAS_Data.h file for a complete list of all available MODs) +Specifies the MOD you want to start playing
RETURNS + + + + + + + + + + + + + + + + + + + + +
AAS_OK:The function executed correctly.
AAS_ERROR_MOD_DOES_NOT_EXIST:The MOD you requested does not exist.
AAS_ERROR_CALL_SET_CONFIG_FIRST:AAS_SetConfig has not been successfully called yet. It must be successfully called at least once before calling this function.
AAS_ERROR_NOT_ENOUGH_CHANNELS:The MOD you requested needs more channels than you have available.
NOTES +

If an existing MOD file is already playing it will be replaced by the new selection. AAS_SetConfig must be called at least once before calling this function. Any sound effects that are playing in the MOD channels will be stopped.

+
+
+ +
:: AAS_MOD_SetLoop +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_MOD_SetLoop( AAS_BOOL loop );
FUNCTIONSpecifies whether the current MOD will loop. All MODs loop by default.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
loop +AAS_TRUE or AAS_FALSE +Specifies whether the current MOD will loop
RETURNS + + + + + + + + + + + + + + + +
AAS_OK:The MOD has been set to loop as requested.
AAS_ERROR_NO_MOD_PLAYING:The command failed because no MOD is currently playing.
AAS_ERROR_CALL_SET_CONFIG_FIRST:AAS_SetConfig has not been successfully called yet. It must be successfully called at least once before calling this function.
NOTESAll MODs loop by default. This means that if you want your MODs not to loop, you must call "AAS_MOD_SetLoop( AAS_FALSE );" immediately after the AAS_MOD_Play command.
+
+ +
:: AAS_MOD_Stop +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_MOD_Stop();
FUNCTIONStops playing current MOD.
PARAMETERSNone
RETURNSNothing
NOTES +

If a MOD is currently playing it will be stopped. Any sound effects that are playing in the MOD channels will be stopped - see AAS_SetConfig.

+
+
+ +
:: AAS_MOD_Pause +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_MOD_Pause();
FUNCTIONPauses the current MOD. It can be continued later using AAS_MOD_Resume.
PARAMETERSNone
RETURNSNothing
NOTES +

Unlike AAS_MOD_Stop, the channels used by the MOD player are not returned for use as SFX channels when AAS_MOD_Pause is called.

+
+
+ +
:: AAS_MOD_Resume +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEvoid AAS_MOD_Resume();
FUNCTIONResumes a MOD that was previously paused using AAS_MOD_Pause.
PARAMETERSNone
RETURNSNothing
NOTES +

Calling AAS_MOD_Resume without pausing a MOD beforehand using AAS_MOD_Pause will have no effect. Resuming a MOD that is already playing also has no effect.

+
+
+ +
:: AAS_MOD_IsPlaying +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEAAS_BOOL AAS_MOD_IsPlaying();
FUNCTIONChecks whether a MOD is currently playing.
PARAMETERSNone
RETURNS + + + + + + + + + + +
AAS_FALSE:No MOD is currently playing.
AAS_TRUE:A MOD is currently playing.
NOTESNone
+
+ +
:: AAS_MOD_HasLooped +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEAAS_BOOL AAS_MOD_HasLooped();
FUNCTIONChecks whether or not the current MOD has looped.
PARAMETERSNone
RETURNS + + + + + + + + + + +
AAS_FALSE:The MOD has not yet looped.
AAS_TRUE:The MOD has looped.
NOTESAlways returns AAS_FALSE if no MOD is playing or if AAS has not yet been initialised.
+
+ +
:: AAS_MOD_GetVolume +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_MOD_GetVolume();
FUNCTIONReturns the current volume for MOD tunes. 0 = silent, 256 = max.
PARAMETERSNone
RETURNS + + + + + +
0-256:The current MOD volume. 0 = silent, 256 = max.
NOTESNone
+
+ +
:: AAS_MOD_SetVolume +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_MOD_SetVolume( int vol );
FUNCTIONSets the current volume for MOD tunes. 0 = silent, 256 = max.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
vol +0-256 +Specifies the new volume you want MODs to be played at
RETURNS + + + + + + + + + + +
AAS_OK:The volume was successfully changed as requested.
AAS_ERROR_VOLUME_OUT_OF_RANGE:The volume was not in the range 0-256. The MOD volume has not been adjusted.
NOTESNone
+
+ +
:: AAS_MOD_GetSongPos +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_MOD_GetSongPos();
FUNCTIONReturns the current song position of the playing MOD.
PARAMETERSNone
RETURNS + + + + + + + + + + +
0-127:The current song position.
AAS_ERROR_NO_MOD_PLAYING:There is no MOD currently playing.
NOTESNone
+
+ +
:: AAS_MOD_SetSongPos +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_MOD_SetSongPos( int song_pos );
FUNCTIONImmediately jumps to the specified song position.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
song_pos +0-127 +Specifies the new song position
RETURNS + + + + + + + + + + + + + + + +
AAS_OK:The function executed correctly.
AAS_ERROR_INVALID_SONG_POS:The specified song position does not exist.
AAS_ERROR_NO_MOD_PLAYING:There is no MOD currently playing.
NOTESNone
+
+ +
:: AAS_MOD_QueueSongPos +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_MOD_QueueSongPos( int song_pos );
FUNCTIONJumps to the specified song position when the current pattern finishes.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
song_pos +0-127 +Specifies the new song position
RETURNS + + + + + + + + + + + + + + + +
AAS_OK:The function executed correctly.
AAS_ERROR_INVALID_SONG_POS:The specified song position does not exist.
AAS_ERROR_NO_MOD_PLAYING:There is no MOD currently playing.
NOTESNone
+
+ +
:: AAS_MOD_GetLineNum +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_MOD_GetLineNum();
FUNCTIONReturns the current line number of the playing MOD.
PARAMETERSNone
RETURNS + + + + + + + + + + +
0-63:The current line number.
AAS_ERROR_NO_MOD_PLAYING:There is no MOD currently playing.
NOTESNone
+
+ +
:: AAS_MOD_GetLastFilterValue +
+ + + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_MOD_GetLastFilterValue();
FUNCTIONReturns the value specified by the most recent "E0: Set Filter" effect. Can be used to sychronise code with the music.
PARAMETERSNone
RETURNS + + + + + +
0-15:The most recent value specified by an "E0: Set Filter" effect.
NOTESWill return 0 if no "E0: Set Filter" effect has yet been found, if no MOD is playing or if AAS has not been initialised. The "E0: Set Filter" effect makes no difference to the sound output of AAS as the GBA has no hardware filter so it is safe to change whilst a piece of music is playing.
+
+ +
:: AAS_MOD_GetNumChannels +
+ + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_MOD_GetNumChannels();
FUNCTIONReturns the number of channels that are currently being reserved by the MOD.
PARAMETERSNone
RETURNS + + + + + +
0-16:The number of channels that are currently being reserved by the MOD.
NOTES +

None

+
+
+ + + diff --git a/lib/apex-audio-system/docs/api_sfx.html b/lib/apex-audio-system/docs/api_sfx.html new file mode 100644 index 0000000..7af6e27 --- /dev/null +++ b/lib/apex-audio-system/docs/api_sfx.html @@ -0,0 +1,598 @@ + + + +AAS Instructions + + + + + + + + +
+ + + + + +
+[Image]  + +APEX AUDIO SYSTEM
+Instruction Manual +
+
+
+
+intro | getting started | conv2aas | example | faq
+api : index | general | sfx | mod | misc | mixer +
+ +
+ +
:: AAS_SFX_Play +
+ + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_SFX_Play( int channel, int sample_volume, int sample_frequency, const AAS_s8* sample_start, const AAS_s8* sample_end, const AAS_s8* sample_restart );
FUNCTIONStarts playing the specified sample.
PARAMETERS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameValid valuesMeaning
channel +Depends on how AAS has been configured - see AAS_SetConfig +Specifies the channel you wish to use
sample_volume +0-64 +Specifies the volume you wish to play the sample at
sample_frequency +1-65535 +Specifies the frequency you wish to play the sample at
sample_start +AAS_DATA_SFX_START_???, where ??? is the name of the sample you wish to play (see your project's AAS_Data.h file for a complete list of all available samples) +Specifies the start address of the sample you wish to play
sample_end +AAS_DATA_SFX_END_???, where ??? is the name of the sample you wish to play (see your project's AAS_Data.h file for a complete list of all available samples) +Specifies the end address if the sample you wish to play
sample_restart +AAS_NULL or any address between AAS_DATA_SFX_START_??? (inclusive) and AAS_DATA_SFX_END_??? (exclusive), where ??? is the name of the sample you wish to play (see your project's AAS_Data.h file for a complete list of all available samples) +Specifies the address the sample will loop to when it gets to the end. NULL indicates that the sample should not loop.
RETURNS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AAS_OK:Function executed correctly.
AAS_ERROR_INVALID_SAMPLE_ADDRESS:The sample_start, sample_end or sample_restart addresses specified are not valid.
AAS_ERROR_VOLUME_OUT_OF_RANGE:The volume specified is not in the range 0-64.
AAS_ERROR_FREQUENCY_OUT_OF_RANGE:The frequency specified is not in the range 1-65535.
AAS_ERROR_CHANNEL_NOT_AVAILABLE:The channel you specified is not available to play a sample - see AAS_SetConfig.
AAS_ERROR_CALL_SET_CONFIG_FIRST:AAS_SetConfig has not been successfully called yet. It must be successfully called at least once before calling this function.
NOTES +

Sample frequency is capped at 4 times the mixing rate specified when calling AAS_SetConfig.

+
+
+ +
:: AAS_SFX_ChannelExists +
+ + + + + + + + + + + + + + + + + + + + +
PROTOTYPEAAS_BOOL AAS_SFX_ChannelExists( int channel );
FUNCTIONReturns AAS_TRUE only if AAS_SFX_Play will succeed for this channel, otherwise returns AAS_FALSE.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
channel +Depends on how AAS has been configured - see AAS_SetConfig +Specifies the channel you wish to test
RETURNS + + + + + + + + + + +
AAS_FALSE:This channel is not currently a valid sound effect channel.
AAS_TRUE:This channel is currently a valid sound effect channel.
NOTES +

Whether a channel is available or not depends on how many channels were specified when calling AAS_SetConfig and also on whether or not a MOD is currently playing. See AAS_SetConfig for more information.

+
+
+ +
:: AAS_SFX_IsActive +
+ + + + + + + + + + + + + + + + + + + + +
PROTOTYPEAAS_BOOL AAS_SFX_IsActive( int channel );
FUNCTIONReturns AAS_TRUE if channel is valid and active, AAS_FALSE otherwise.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
channel +Depends on how AAS has been configured - see AAS_SetConfig +Specifies the channel you wish to test
RETURNS + + + + + + + + + + +
AAS_FALSE:This is an invalid channel for sound effects, or it is valid but currently in use.
AAS_TRUE:This is a valid sound effect channel and it currently has a sound effect playing.
NOTES +

Whether or not a channel is valid depends on how many channels were specified when calling AAS_SetConfig and also on whether or not a MOD is currently playing. See AAS_SetConfig for more information. Provided the channel specified is valid, this function will return AAS_TRUE if there is another sound effect playing on this channel, and AAS_FALSE if there is not. It will always return AAS_FALSE if the channel is invalid.

+
+
+ +
:: AAS_SFX_EndLoop +
+ + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_SFX_EndLoop( int channel );
FUNCTIONIf a looping sample was playing in this channel, it will not loop again at end of the current iteration.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
channel +Depends on how AAS has been configured - see AAS_SetConfig +Specifies the channel you wish to change
RETURNS + + + + + + + + + + + + + + + +
AAS_OK:The function suceeded.
AAS_ERROR_CHANNEL_NOT_AVAILABLE:The channel specified is invalid.
AAS_ERROR_CALL_SET_CONFIG_FIRST:AAS_SetConfig should be successfully called at least once before calling this function.
NOTES +

None

+
+
+ +
:: AAS_SFX_SetFrequency +
+ + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_SFX_SetFrequency( int channel, int sample_frequency );
FUNCTIONChanges the frequency of the sample playing in the specified channel.
PARAMETERS + + + + + + + + + + + + + + + +
NameValid valuesMeaning
channel +Depends on how AAS has been configured - see AAS_SetConfig +Specifies the channel you wish to change
sample_frequency +1-65535 +Specifies the new frequency you wish to play the sample at
RETURNS + + + + + + + + + + + + + + + + + + + + +
AAS_OK:The function suceeded.
AAS_ERROR_FREQUENCY_OUT_OF_RANGE:The frequency specified in not in the range 1-65535.
AAS_ERROR_CHANNEL_NOT_AVAILABLE:The channel specified is invalid.
AAS_ERROR_CALL_SET_CONFIG_FIRST:AAS_SetConfig should be successfully called at least once before calling this function.
NOTES +

Sample frequency is capped at four times the mixing rate specified when calling AAS_SetConfig. If no sample is playing in the specified channel then this function has no effect.

+
+
+ +
:: AAS_SFX_SetVolume +
+ + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_SFX_SetVolume( int channel, int sample_volume );
FUNCTIONChanges the volume of the sample playing in the specified channel.
PARAMETERS + + + + + + + + + + + + + + + +
NameValid valuesMeaning
channel +Depends on how AAS has been configured - see AAS_SetConfig +Specifies the channel you wish to change
sample_volume +0-64 +Specifies the new volume you wish to play the sample at
RETURNS + + + + + + + + + + + + + + + + + + + + +
AAS_OK:The function suceeded.
AAS_ERROR_VOLUME_OUT_OF_RANGE:The frequency specified in not in the range 0-64.
AAS_ERROR_CHANNEL_NOT_AVAILABLE:The channel specified is invalid.
AAS_ERROR_CALL_SET_CONFIG_FIRST:AAS_SetConfig should be successfully called at least once before calling this function.
NOTES +

If no sample is playing in the specified channel then this function has no effect.

+
+
+ +
:: AAS_SFX_Stop +
+ + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_SFX_Stop( int channel );
FUNCTIONStops the sample currently playing in the specified channel.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
channel +Depends on how AAS has been configured - see AAS_SetConfig +Specifies the channel you wish to stop
RETURNS + + + + + + + + + + + + + + + +
AAS_OK:The function suceeded.
AAS_ERROR_CHANNEL_NOT_AVAILABLE:The channel specified is invalid.
AAS_ERROR_CALL_SET_CONFIG_FIRST:AAS_SetConfig should be successfully called at least once before calling this function.
NOTES +

If no sample is playing in the specified channel then this function has no effect.

+
+
+ +
:: AAS_SFX_Resume +
+ + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_SFX_Resume( int channel );
FUNCTIONResumes a channel that has been previously stopped.
PARAMETERS + + + + + + + + + + +
NameValid valuesMeaning
channel +Depends on how AAS has been configured - see AAS_SetConfig +Specifies the channel you wish to resume
RETURNS + + + + + + + + + + + + + + + + + + + + + + + + + +
AAS_OK:The function suceeded.
AAS_ERROR_CHANNEL_NOT_AVAILABLE:The channel specified is invalid.
AAS_ERROR_CALL_SET_CONFIG_FIRST:AAS_SetConfig should be successfully called at least once before calling this function.
AAS_ERROR_CHANNEL_ACTIVE:The channel is already active so it cannot be resumed.
AAS_ERROR_CHANNEL_UNRESUMEABLE:This channel has either never been used or is inactive because the sample finished.
NOTES +

None

+
+
+ +
:: AAS_SFX_GetNumChannels +
+ + + + + + + + + + + + + + + + + + + + +
PROTOTYPEint AAS_SFX_GetNumChannels();
FUNCTIONReturns the number of SFX channels that are currently available.
PARAMETERSNone
RETURNS + + + + + +
0-16:The number of SFX channels that are currently available.
NOTES +

None

+
+
+ + + diff --git a/lib/apex-audio-system/docs/conv2aas.html b/lib/apex-audio-system/docs/conv2aas.html new file mode 100644 index 0000000..dd2b617 --- /dev/null +++ b/lib/apex-audio-system/docs/conv2aas.html @@ -0,0 +1,139 @@ + + + +AAS Instructions + + + + + + + + +
+ + + + + +
+[Image]  + +APEX AUDIO SYSTEM
+Instruction Manual +
+
+
+
+intro | getting started | conv2aas | example | faq
+api : index | general | sfx | mod | misc | mixer +
+ +
+ +
:: What Is Conv2AAS? +
+ +

Conv2AAS is a simple tool that reads in all the files in a specified directory and converts them into a single data file (with an associated header file) which can then be used in your project. Any redundancy in the data will be removed. For example, if two MODs in your project use the same samples then those samples will only be included once to save space.

+ +
+
:: What File Formats Are Supported? +
+ +

Currently, Conv2AAS supports the following file formats:

+ + + + + + + + + + + + + + + + + + + + + + +
FormatExtensionRestrictions
MOD +.mod +Protracker/Noisetracker/FastTracker/Falcon/TakeTracker 1-16 channel MODs are supported. The following effects are implemented:
+
+0: Arpeggio
+1: Slide Up
+2: Slide Down
+3: Tone Portamento
+4: Vibrato
+5: Tone Portamento + Volume Slide
+6: Vibrato + Volume Slide
+7: Tremolo
+9: Set Sample Offset
+A: Volume Slide
+B: Position Jump
+C: Set Volume
+D: Pattern Break
+E0: Set Filter (*)
+E1: Fine Slide Up
+E2: Fine Slide Down
+E6: Set/Jump to Loop
+E9: Retrigger Note
+EA: Fine Volume Slide Up
+EB: Fine Volume Slide Down
+EC: Note Cut
+ED: Note Delay
+EE: Pattern Delay
+F: Set Speed
+
+(*) The GBA has no hardware filter so this effect does not change the audio output. However, the most recent value set by this effect can be read in your code via the AAS_MOD_GetLastFilterValue function. This can be used to sychronise your code with the music.
+
+Conv2AAS will produce warnings if a MOD uses unsupported effects, is in the wrong format or if it has too many channels. However, even if a MOD does use unsupported effects, it will often still play almost perfectly.
RAW +.raw +Data must be 8-bit signed mono PCM with no header.
WAV +.wav +Must be in 8-bit unsigned mono PCM format. (Automatically converted to signed format by Conv2AAS.)
+ +
+
:: Creating Sound Files +
+ +

Probably the best MOD editor out there is ModPlug. It can convert from other formats and has the added advantage of being free. For converting samples into the appropriate RAW and WAV formats, I recommend SoX, which is also free.

+ +

To convert to the appropriate formats using sox, use the following command:

+ +
+sox [source_filename] -s -b -c 1 [destination_filename]
+ +

[source_filename] is the name of the sound you wish to convert (e.g. "source.wav"). [destination_filename] is the name of the file you wish to create (e.g. "dest.raw") - it should end with ".wav" or ".raw" to be compatible with Conv2AAS. Note that sox will give a warning when converting to .wav format that it has converted the data to unsigned - this is normal. Also make sure that [source_filename] and [destination_filename] are different. It is even possible to use sox to automatically convert all your sound files as part of your project's makefile.

+ +
+
:: Calling Conv2AAS +
+ +

Conv2AAS includes versions compiled for DOS/Windows and Linux. Both are named conv2aas. It should be called from the command line and only needs one parameter, which is the name of the folder that contains the data files. All the files in that folder will be processed so it is recommended that you create a subfolder for your project that contains all the sound files. Conv2AAS always creates two files in the current directory:

+ +

AAS_Data.h : This is the header file that you should include in your main code whenever you want access the AAS sound data.

+ +

AAS_Data.s : This is the raw data itself, stored as an assembly file suitable for the GBA. It should be assembled to produce an object file that can then be linked with your project.

+ +

The example code included with AAS comes with a makefile that will automatically run Conv2AAS each time your program is compiled. It is highly recommended that you use a similar system in your project.

+ +
+ + + diff --git a/lib/apex-audio-system/docs/example.html b/lib/apex-audio-system/docs/example.html new file mode 100644 index 0000000..82a35a0 --- /dev/null +++ b/lib/apex-audio-system/docs/example.html @@ -0,0 +1,232 @@ + + + +AAS Instructions + + + + + + + + +
+ + + + + +
+[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:

+ + + +
+
:: 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:

+ +

-Laas/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:

+ +

-Iaas/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 And crt0.s +
+ +

A crt0.s or similar file is required for any GBA project and, amongst other things, it specifies how hardware interrupts will be handled. AAS can be made to work with all these different methods, provided that a Timer 1 interrupt results in a call to AAS_Timer1InterruptHandler.

+ +

In "AASExample" and "AASExample_c++", the crt0.s file has been configured to use "Fast Interrupts", which means that any interrupt will automatically call a function named InterruptProcess() and it is then up to the user to implement this routine. In order for this work with AAS, your InterruptProcess() code must automatically call "AAS_Timer1InterruptHandler()" when a Timer 1 interrupt occurs. The C code to do this is shown below. The C++ code used in "AASExample_c++" is much the same except InterruptProcess() has to be declared "extern "C"" to prevent name mangling.

+ +
+#define REG_IE (*(volatile AAS_u16 *)0x4000200)
+#define REG_IF (*(volatile AAS_u16 *)0x4000202) 
+
+void InterruptProcess()
+{
+  AAS_u16 intr_bits = REG_IE & REG_IF;
+
+  // It's best to test for AAS's Timer 1 interrupt first
+  if ( intr_bits & 0x10 ) // Timer 1
+    AAS_Timer1InterruptHandler();
+	
+  // Process other interrupts here by testing appropriate bits of "intr_bits"
+
+  // Clear the interrupt flags
+  REG_IF |= REG_IF;
+}
+ +

This routine simply creates a bit mask (intr_bits) that indicates which interrupts have occurred (there may be more than one) and then tests for the Timer 1 interrupt that is used by AAS. If it occured then it calls AAS_Timer1InterruptHandler. You can add additional code to service any other interrupts you may be using in your project. Once all interrupts have been serviced, it is necessary to clear the interrupt flags as the last action before returning from the function.

+ +
+
:: 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 use the special "AAS_MultipleInterrupts" mode that has been added to the custom crt0.s included with the SDK. In this mode, a Timer 1 interrupt automatically calls AAS_FastTimer1InterruptHandler, which 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:

+ +
+void VBlankInterruptHandler()
+{
+  AAS_DoWork();
+  
+  // Insert your own VBlank code here
+}
+
+void UnusedInterruptHandler()
+{
+};
+
+void (*AAS_IntrTable[13])(void) =
+{
+  VBlankInterruptHandler,      // VBlank Interrupt
+  UnusedInterruptHandler,      // HBlank Interrupt
+  UnusedInterruptHandler,      // V Counter Interrupt
+  UnusedInterruptHandler,      // Timer 0 Interrupt
+  UnusedInterruptHandler,      // Timer 2 Interrupt
+  UnusedInterruptHandler,      // Timer 3 Interrupt
+  UnusedInterruptHandler,      // Serial Communication Interrupt
+  UnusedInterruptHandler,      // DMA0 Interrupt
+  UnusedInterruptHandler,      // DMA1 Interrupt
+  UnusedInterruptHandler,      // DMA2 Interrupt
+  UnusedInterruptHandler,      // DMA3 Interrupt
+  UnusedInterruptHandler,      // Key Interrupt
+  UnusedInterruptHandler       // Cart Interrupt
+};
+ +

Notice that there is not a "Timer 1 Interrupt" entry in the definition of AAS_IntrTable[] as this interrupt always results in a call to AAS_FastTimer1InterruptHandler. Also note that it is necessary to initialise the VBlank interrupt so that AAS_DoWork() will be called at least 50 times per second. To achieve this, the code below needs to be included somewhere in your setup routines:

+ +
+// Define registers
+#define REG_IE (*(volatile AAS_u16 *)0x4000200)
+#define	REG_DISPSTAT (*(volatile AAS_u16*)0x04000004)
+
+// Enable VBlank interrupt
+REG_DISPSTAT |= 0x8;
+REG_IE |= 0x1;
+ +
+
:: Using AAS +
+ +

Once all the tricky stuff described above is working, actually 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 AgbMain() is declared with "extern "C"" and again a different MOD is used.

+ +
+// Registers for GBA keys
+#define	REG_KEY (*(volatile AAS_u16 *)0x04000130)
+#define REG_KEY_A 0x0001
+#define REG_KEY_B 0x0002
+
+void AgbMain() 
+{
+  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 );
+	
+  // Start playing MOD
+  AAS_MOD_Play( AAS_DATA_MOD_FlatOutLies );
+	
+  // Show AAS Logo (required for non-commercial projects)
+  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 );
+}
+ +

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.

+ +
+ + + diff --git a/lib/apex-audio-system/docs/faq.html b/lib/apex-audio-system/docs/faq.html new file mode 100644 index 0000000..5fc2e36 --- /dev/null +++ b/lib/apex-audio-system/docs/faq.html @@ -0,0 +1,70 @@ + + + +AAS Instructions + + + + + + + + +
+ + + + + +
+[Image]  + +APEX AUDIO SYSTEM
+Instruction Manual +
+
+
+
+intro | getting started | conv2aas | example | faq
+api : index | general | sfx | mod | misc | mixer +
+ +
+ +
:: How do I reference AAS sounds with numbers? +
+ +

All the sounds in your project are given a unique variable name based on their filename in the header file (AAS_Data.h) generated by Conv2AAS. In some cases you may want to use a number to refer to the data instead. To do this, create a const array that is pre-defined to list all the sounds in your project and use the array in your code instead. For example, with samples called "mysample1.wav" and "mysample2.wav":

+ +
+struct AAS_Samp
+{
+  const AAS_s8* const start;
+  const AAS_s8* const end;
+};
+
+const struct AAS_Samp AAS_samples[] =
+{
+  { AAS_DATA_SFX_START_mysample1, AAS_DATA_SFX_END_mysample1 },
+  { AAS_DATA_SFX_START_mysample2, AAS_DATA_SFX_END_mysample2 }
+};
+ +

These samples can then be referred to using numbers as follows:

+ +
+AAS_SFX_Play( 0, 64, 16000, AAS_samples[0].start, AAS_samples[0].end, AAS_NULL );
+ +

This code could easily be extended to also store loop, volume and frequency data as well.

+ +
+ + + diff --git a/lib/apex-audio-system/docs/getting_started.html b/lib/apex-audio-system/docs/getting_started.html new file mode 100644 index 0000000..92f3ba8 --- /dev/null +++ b/lib/apex-audio-system/docs/getting_started.html @@ -0,0 +1,132 @@ + + + +AAS Instructions + + + + + + + + +
+ + + + + +
+[Image]  + +APEX AUDIO SYSTEM
+Instruction Manual +
+
+
+
+intro | getting started | conv2aas | example | faq
+api : index | general | sfx | mod | misc | mixer +
+ +
+ +
:: Building AAS components +
+ +

We use a makefile in the root of the repo to build the library, conversion tool and examples. It is expected that you have a cross-compiler and a host compiler installed on your system. The paths to these need to be configured at the top of the makefile:

+ + +

Run make without arguments in the root of the repo to build aas, conv2aas and the examples

. The files can be found in ‹root›/build:

+ + +

To build one or more individual components, add their name as argument to the makefile:

+ + +
+
:: First Steps +
+ +

Once the library and conv2aas are built, the user must include the AAS header files ("AAS.h" and, optionally, "AAS_Mixer.h") and link "libAAS.a" with their project. Next, the interrupt handling routines must be set up so that a Timer 1 interrupt results in a call to AAS_Timer1InterruptHandler (or AAS_FastTimer1InterruptHandler with a seperate call to AAS_DoWork later if "AAS_MultipleInterrupts" are being used). The example code included with AAS demonstrates how to do this, and users are encouraged to reuse the code shown in their own projects.

+ +

It is also recommended that the project's makefile be modified so that Conv2AAS is automatically called when the project is compiled, and its output is assembled and linked with the main code. The makefile included with the example code shows how to do this.

+ +

It is also important that none of the following resources are used in your code as they are required by AAS: +

+

+ +

Also note that DMA3 can be used, but only via the AAS_DoDMA3 function call or with a single stmia instruction. Once these steps have been successfully completed AAS should be ready for use. A detailed description of AAS's API can be found here and some example code can be found here.

+ +
+
:: Things To Look Out For +
+ +

Whilst every effort has been made to make AAS as easy to use as possible, there are a few things to look out for:

+ + + +
+ + + diff --git a/lib/apex-audio-system/docs/images/aas_logo.gif b/lib/apex-audio-system/docs/images/aas_logo.gif new file mode 100644 index 0000000..02c4a8c Binary files /dev/null and b/lib/apex-audio-system/docs/images/aas_logo.gif differ diff --git a/lib/apex-audio-system/docs/index.html b/lib/apex-audio-system/docs/index.html new file mode 100644 index 0000000..ba6956c --- /dev/null +++ b/lib/apex-audio-system/docs/index.html @@ -0,0 +1,149 @@ + + + +AAS Instructions + + + + + + + + +
+ + + + + +
+[Image]  + +APEX AUDIO SYSTEM
+Instruction Manual +
+
+
+
+intro | getting started | conv2aas | example | faq
+api : index | general | sfx | mod | misc | mixer +
+ +
+ +
:: What Is It? +
+ +

The Apex Audio System (AAS) is a sound library for the GBA. It includes a highly efficient mixer, MOD playing routines and support for up to 16 channels. It is designed for developers using a GCC-based development environment.

+ + + + + + + + + + + + + + + + + + +
MIXING RATE8-32 KHz, optionally dynamic.
NUMBER OF CHANNELSUp to 16.
FEATURES (PER CHANNEL)Looping, pitch and volume control.
MEMORY USAGE~3.2K IWRAM, ~3.3K EWRAM (includes code and all buffers).
+ +
+
:: History +
+ +

Apex Audio System was made by James Daniels of Apex Systems back in 2003 for his GBA game Payback. The library underwent several revisions, the latest of which was v1.11. At the beginning of 2021, James was so kind to donate the sources to the community.

+ +

The current release is v1.12.

+

Changes since v1.11:

+ + +
+
:: How Fast Is It? +
+ +

AAS includes easily the fastest audio system yet made for the GBA, using an average of only ~1% CPU per active channel at 32 KHz. (Most GBA mixers use at least twice as much CPU power mixing at just 16 KHz!) AAS also supports up 16 channels and a dynamic mixing rate that adjusts automatically depending on the pitch of the sounds being played.

+ +

The exact CPU usage varies depending on the configuration, but the average CPU usage for CreamOfTheEarth.mod in different situations is shown below:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mixing modeMonoStereo
32 KHz3.6%4.1%
32 KHz, dynamic3.0%3.2%
24 KHz3.2%3.5%
24 KHz, dynamic3.0%3.2%
16 KHz2.7%3.0%
16 KHz, dynamic2.7%3.0%
+ +
+
:: Licensing +
+ +

AAS is now distributed under the MIT license. For licensing terms, see the LICENSE file in the root of this repo or go to http://opensource.org/licenses/MIT

+ +

James only had one request when handing over the sources: that users of the library include a credit to Apex Designs. In essence this is now covered by the MIT license. It's up to you how you want to fill this in, but please be respectful of this requirement.

+ +
+
:: Contact +
+ +

The sources are hosted on Github: https://github.com/stuij/apex-audio-system

+ +

Pull requests are welcome, as are forks of course. If you want to report issues, open an issue on the Github project issue tracker.

+ +

For a more realtime interactive experience, join gbadev on Discord. There's a good chance there's one or two people there that have used AAS before.

+ +
+ + + diff --git a/lib/apex-audio-system/examples/AASExample/AASExample.c b/lib/apex-audio-system/examples/AASExample/AASExample.c new file mode 100644 index 0000000..5279063 --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample/AASExample.c @@ -0,0 +1,69 @@ +// AAS Example for projects with no other CPU intensive interrupts +// Notes: +// + crt0.s file included with the example should be set to use __FastInterrupts. +// + Can also be made to work with __SingleInterrupts and __MultipleInterrupts. +// + Use __AAS_MultipleInterrupts when there are other CPU intensive interrupts - see AASExample2. + +#include "AAS.h" +#include "AAS_Data.h" + +// Registers for interrupt handler +#define REG_IE (*(volatile AAS_u16 *)0x4000200) +#define REG_IF (*(volatile AAS_u16 *)0x4000202) + +void InterruptProcess() +{ + AAS_u16 intr_bits = REG_IE & REG_IF; + + // It's best to test for AAS's Timer 1 interrupt first + if ( intr_bits & 0x10 ) // Timer 1 + AAS_Timer1InterruptHandler(); + + // Process other interrupts here by testing appropriate bits of "intr_bits" + + // Clear the interrupt flags + REG_IF |= REG_IF; +} + +// Registers for GBA keys +#define REG_KEY (*(volatile AAS_u16 *)0x04000130) +#define REG_KEY_A 0x0001 +#define REG_KEY_B 0x0002 + +void AgbMain() +{ + 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 ); + + // 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 ); +} diff --git a/lib/apex-audio-system/examples/AASExample/AAS_Data/Ambulance.wav b/lib/apex-audio-system/examples/AASExample/AAS_Data/Ambulance.wav new file mode 100644 index 0000000..94d9d62 Binary files /dev/null and b/lib/apex-audio-system/examples/AASExample/AAS_Data/Ambulance.wav differ diff --git a/lib/apex-audio-system/examples/AASExample/AAS_Data/Boom.raw b/lib/apex-audio-system/examples/AASExample/AAS_Data/Boom.raw new file mode 100644 index 0000000..7537624 Binary files /dev/null and b/lib/apex-audio-system/examples/AASExample/AAS_Data/Boom.raw differ diff --git a/lib/apex-audio-system/examples/AASExample/AAS_Data/FlatOutLies.mod b/lib/apex-audio-system/examples/AASExample/AAS_Data/FlatOutLies.mod new file mode 100644 index 0000000..7b06f97 Binary files /dev/null and b/lib/apex-audio-system/examples/AASExample/AAS_Data/FlatOutLies.mod differ diff --git a/lib/apex-audio-system/examples/AASExample/Makefile b/lib/apex-audio-system/examples/AASExample/Makefile new file mode 100644 index 0000000..01e03b4 --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample/Makefile @@ -0,0 +1,8 @@ +# AAS Example Makefile +EXAMPLE_PREFIX ?= AASExample +SHORTNAME = $(EXAMPLE_PREFIX) + +CROSS = arm-none-eabi- +LD = $(CROSS)gcc + +include ../../make/example.make diff --git a/lib/apex-audio-system/examples/AASExample/crt0.s b/lib/apex-audio-system/examples/AASExample/crt0.s new file mode 100644 index 0000000..a4a092b --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample/crt0.s @@ -0,0 +1,781 @@ +@******************************************************************** +@* crt0.S v1.26 by Jeff Frohwein * +@******************************************************************** + +@ - Modified by James Daniels/Apex Designs to give AAS interrupts higher priority in special +@ "AAS_MultipleInterrupts" mode + +@ v1.0 - Original release +@ v1.1 - Added proper .data section support +@ v1.2 - Added support for c++, overlays, interrupts, and +@ far calls (__FarFunction & __FarProcedure). +@ - Some ideas from Jason Wilkins & Mike Heckenbach. +@ v1.21- Killed the dumb test bug left in the code. +@ v1.22- Killed dumb bug "numero dos" in multiple interrupts routine. Thanks Mike H. :) +@ v1.23- Now correctly handles zero length .bss section. +@ v1.24- Loop back to start_vector now works if main {} exits. +@ v1.25- __FarProcedure now works. It was missing a .thumb_func directive. +@ v1.26- Added missing Serial Interrupt processing to __MultipleInterrupts section. +@ Added __FastInterrupt option for minimal interrupt processing. +@ Optimized __MultipleInterrupts section to save 4 bytes of stack space. +@ Added __ISRinIWRAM option that puts interrupt processing in IWRAM by default. +@ Options passed to main() or AgbMain() are now set to 0. (Thanks to DarkFader) +@ +@ This file is released into the public domain for commercial +@ or non-commercial usage with no restrictions placed upon it. + + .TEXT + +@ Comment out the next line ONLY if you plan to never support +@ multiboot mode and want to save a few bytes by removing +@ multiboot support code. Otherwise, leave it alone. It wont +@ disturb code designed to run only on flash carts. +@ +@ The normal way to enable generating code that works with +@ both multiboot and flash carts is to add the following to +@ your C code in your main project file AS A GLOBAL VARIABLE: +@ +@ #define MULTIBOOT int __gba_multiboot; +@ Then use it like this : MULTIBOOT +@ +@ IT MUST BE A GLOBAL VARIABLE OR IT WILL NOT WORK! +@ If this variable is not defined somewhere in your project +@ then code will be generated to run out of ROM instead of +@ EXRAM. The value of this variable is not important. + + .equ __MultiBootInclude, 1 + +@ If you are compiling for multiboot dedicated (will not +@ run in a cart) code then uncomment the following. Normally +@ you should leave this commented out so that a multiboot +@ image will run in a cart as well (by copying from ROM to RAM). +@ +@ This sets the maker code to "MB " which is a key that +@ some emulators look for to know to load the rom image +@ at 0x2000000 instead of the standard 0x8000000. + +@ .equ __MultibootDedicated, 1 + +@ There are two methods for clearing memory and +@ copying appropriate setup data. The fast & bulky +@ method is GBA DMA copy/clear but some emulators +@ do not accurately do DMA. If you have an inaccurate +@ emulator or want to conserve ROM space then comment +@ out the following line. There is not much advantage +@ gained by doing DMA copy/clear. + +@ .equ __DMACopyClear, 1 + +@ Uncomment the following line to support C++ development. +@ You also need to name your main C function the following: +@ int main (void) ...instead of... int AgbMain (void) +@ Doing so will cause ~5500 bytes of c++ support code to be +@ linked in with your project so do not enable c++ support +@ unless you plan to use it. + +@ .equ __CPPSupport, 1 + +@ Comment out the following line to disable interrupt support +@ in your code and to save some space in this file. + + .equ __InterruptSupport, 1 + + +@ Comment out the following line to put interrupt support in +@ ROM instead of IWRAM. Interrupt support in ROM will slow +@ down interrupt execution and has no advantage other than +@ saving a little bit of IWRAM. + + .equ __ISRinIWRAM, 1 + +@ NOTE: Only ONE of the following 3 interrupt options may be +@ uncommented. Also, __InterruptSupport above must be uncommented +@ for any of the following to have an effect. +@ +@ __FastInterrupts +@ Uncomment this line for minimal interrupt processing. +@ +@ __SingleInterrupts +@ Uncomment this line if you wish to use a table of function +@ pointers to process specific interrupts. +@ +@ __MultipleInterrupts +@ Uncomment this line to allow multiple-interrupts-at-once +@ support. If you have several interrupts where one can +@ occur while another is being serviced then you need to +@ enable this option. +@ +@ __AAS_MultipleInterrupts +@ Uncomment this line to allow multiple-interrupts-at-once +@ support, giving the AAS interrupt higher priority. If +@ you have several interrupts where one can occur while +@ another is being serviced then you need to enable this +@ option. Only for use with AAS! Added by James Daniels. + +.equ __FastInterrupts, 1 +@ .equ __SingleInterrupts, 1 +@ .equ __MultipleInterrupts, 1 +@ .equ __AAS_MultipleInterrupts, 1 + + +@ Uncomment the following line to disable sound and enter an +@ infinite loop if cart is removed during game play. You +@ must have the cart interrupt enabled for this to work and +@ __ISRinIWRAM, above, must be enabled (not commented out.) + +@ .equ __HandleCartInterrupt, 1 + +@ The following prevents IRQ stack overflow by switching to +@ System mode (User stack) when handling multiple interrupts. +@ To force use of IRQ stack only, comment out the following line. + + .equ __SwitchToUserStack, 1 + +@ !!!! NOTE: THE COPY ROUTINES IN THIS FILE WORK ON 4 BYTE +@ BOUNDARIES. YOUR LINKER SCRIPT MUST ALIGN SECTION STARTS +@ AND SECTION ENDS FOR SECTIONS THAT GET COPIED TO RAM WITH +@ ALIGN(4) !!!! + + .GLOBAL _start +_start: + .ALIGN + .CODE 32 + @ Start Vector + + b rom_header_end + + @ Nintendo Logo Character Data (8000004h) + .fill 156,1,0 + + @ Game Title (80000A0h) + .ascii "AAS Example" + .byte 0x00 + + .ifdef __MultibootDedicated + @ Game Code (80000ACh) + .ascii "MB " + .else + @ Game Code (80000ACh) + .byte 0x00,0x00,0x00,0x00 + .endif + + @ Maker Code (80000B0h) + .byte 0x30,0x31 + + @ Fixed Value (80000B2h) + .byte 0x96 + + @ Main Unit Code (80000B3h) + .byte 0x00 + + @ Device Type (80000B4h) + .byte 0x00 + + @ Unused Data (7Byte) (80000B5h) + .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00 + + @ Software Version No (80000BCh) + .byte 0x00 + + @ Complement Check (80000BDh) + .byte 0xf0 + + @ Checksum (80000BEh) + .byte 0x00,0x00 + + .ALIGN + .ARM @ ..or you can use CODE 32 here + +rom_header_end: + b start_vector @ This branch must be here for proper + @ positioning of the following header. + @ DO NOT REMOVE IT. + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ The following reserved bytes are used if the code is compiled for @ +@ multiboot mode. It does not hurt anything to leave this header in +@ even if the code is not compiled for multiboot. The GBA BIOS will +@ auto-patch the first two bytes with 0x03 and 0x01, respectively, +@ before running any code if it is executed as multiboot. +@ + +@ The following two bytes are included even for non-multiboot supporting +@ builds to guarantee that any generic library code that depends on them +@ will still be functional. + + .GLOBAL __boot_method, __slave_number + +__boot_method: + .byte 0 @ boot method (0=ROM boot, 3=Multiplay boot) +__slave_number: + .byte 0 @ slave # (1=slave#1, 2=slave#2, 3=slave#3) + + .ifdef __MultiBootInclude + + .byte 0 @ reserved + .byte 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .endif +@ @ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +@@@@@@@@@@@@@@@@@@@@@@ +@ Reset @ +@@@@@@@@@@@@@@@@@@@@@@ + + .GLOBAL start_vector + .ALIGN + .ARM @ ..or you can use CODE 32 here +start_vector: + mov r0, #0x12 @ Switch to IRQ Mode + msr cpsr, r0 + ldr sp,=__sp_irq @ Set SP_irq + mov r0, #0x1f @ Switch to System Mode + msr cpsr, r0 + ldr sp,=__sp_usr @ Set SP_usr + +@ Enter Thumb mode + adr r0,1f + 1 @ add r0,pc,#1 also works here + @ for those that want to conserve labels. + bx r0 + + .THUMB @ ..or you can use .CODE 16 here +1: + + .ifdef __InterruptSupport + ldr r1, =__intr_vector_buf @ Set Interrupt Address + ldr r0, =intr_main + str r0, [r1] + .endif + + .ifdef __MultiBootInclude + +@ *** Multiboot Copy Routine *** +@ Check the Program Counter to see if code is running +@ at 0x2000000 or 0x8000000. If it is running at 0x8000000 +@ then copy 256K bytes of it to 0x2000000 and then branch +@ to 0x2000000. +@ The reason for all this is to allow a program to be used +@ "as is" with an flash cart/emulator or with an MBV2-style +@ multiboot cable. +@ NOTE: You can also detect if this ROM is running from +@ 0x2000000 by checking the multiboot header above. + + ldr r0,=__text_start + lsl r0,#5 @ Was code compiled at 0x08000000 or higher? + bcs DoEWRAMClear @ yes, you can not run it in external WRAM + +@ Make sure we're in ExWRAM + + mov r0,pc + lsl r0,#5 @ Are we running from ROM (0x8000000 or higher) ? + bcc SkipEWRAMClear @ No, so no need to do a copy. + +@ We were started in ROM, silly emulators. :P +@ So we need to copy to ExWRAM. + + mov r3,#0x40 + lsl r3,#12 @ r3 = 0x40000 + lsl r2,r3,#7 @ r2 = 0x2000000 + mov r6,r2 @ r6 = 0x2000000 + lsl r1,r2,#2 @ r1 = 0x8000000 + + bl CopyMem + +@ Jump to the code to execute + + bx r6 + .endif + +DoEWRAMClear: +@ Clear External WRAM to 0x00 + + mov r1,#0x40 + lsl r1,#12 @ r1 = 0x40000 + lsl r0,r1,#7 @ r0 = 0x2000000 + bl ClearMem + +SkipEWRAMClear: +@ ldr r0,=AgbMain +@ bx r0 + +@ Clear Internal WRAM to 0x00 + mov r0,#3 + lsl r0,#24 @ r0 = 0x3000000 + ldr r1,=__sp_usr_offset - 16 + bl ClearMem + + .ifdef __MultiBootInclude +@ Clear BSS section to 0x00 +@ (Sometimes BSS may be in External WRAM) + ldr r0,=__bss_start + ldr r1,=__bss_end + sub r1,r0 + bl ClearMem + .endif + +@ Copy initialized data (data section) from LMA to VMA (ROM to RAM) + ldr r1,=__data_lma + ldr r2,=__data_start + ldr r4,=__data_end + bl CopyMemChk + +@ Copy internal work ram (iwram section) from LMA to VMA (ROM to RAM) + ldr r1,=__iwram_lma + ldr r2,=__iwram_start + ldr r4,=__iwram_end + bl CopyMemChk + +@ Copy internal work ram overlay 0 (iwram0 section) from LMA to VMA (ROM to RAM) + ldr r2,=__load_stop_iwram0 + ldr r1,=__load_start_iwram0 + sub r3,r2,r1 @ Is there any data to copy? + beq CIW0Skip @ no + + ldr r2,=__iwram_overlay_start + bl CopyMem +CIW0Skip: + +@ Copy external work ram (ewram section) from LMA to VMA (ROM to RAM) + ldr r1,=__ewram_lma + ldr r2,=__ewram_start + ldr r4,=__ewram_end + bl CopyMemChk + +@ Copy external work ram overlay 0 (ewram0 section) from LMA to VMA (ROM to RAM) + ldr r2,=__load_stop_ewram0 + ldr r1,=__load_start_ewram0 + sub r3,r2,r1 @ Is there any data to copy? + beq CEW0Skip @ no + + ldr r2,=__ewram_overlay_start + bl CopyMem +CEW0Skip: + +@ Jump to user code + + mov r0,#0 @ int argc + mov r1,#0 @ char *argv[] + + ldr r3,=start_vector + mov lr,r3 @ Set start_vector as return address + +.ifdef __CPPSupport + ldr r3,=main +.else + ldr r3,=AgbMain +.endif + bx r3 + + + .GLOBAL __FarFunction,__FarProcedure + .THUMB_FUNC +__FarFunction: + .THUMB_FUNC +__FarProcedure: + bx r0 + nop + nop @ This nop is here to allow unmapped memory to be used as + @ as a delay of almost 1 sec with a 1 cycle resolution. + @ Read this for technical info: + @ http://www.devrs.com/gba/files/gbadevfaqs.php#RepeatUses + +@ Clear memory to 0x00 if length != 0 +@ r0 = Start Address +@ r1 = Length + +ClearMem: + cmp r1,#0 @ Is length zero? + beq ClearMX @ yes, exit + +.ifdef __DMACopyClear + ldr r2,reg_base + lsr r1,#2 @ r1 = (length/4) & 0xffff + + adr r3,fill_val + str r3,[r2,#0x4] @ Set source address (fill value) + str r0,[r2,#0x8] @ Set destination address (fill dest address) + strh r1,[r2,#0xc] @ Set DMA length + ldr r1,=0x8500 @ dma_clrb + strh r1,[r2,#0xe] @ Start DMA +.else + mov r2,#0 +ClrLoop: + stmia r0!,{r2} + sub r1,#4 + bne ClrLoop +.endif +ClearMX: + bx lr + +@ Copy memory if length != 0 +@ r1 = Source Address +@ r2 = Dest Address +@ r4 = Dest Address + Length + +CopyMemChk: + sub r3,r4,r2 @ Is there any data to copy? + beq CIDExit @ no + +@ Copy memory +@ r1 = Source Address +@ r2 = Dest Address +@ r3 = Length + +CopyMem: +.ifdef __DMACopyClear + ldr r0,reg_base + lsr r3,#2 @ r3 = (length/4) & 0xffff + + str r1,[r0,#0x4] @ Set source address + str r2,[r0,#0x8] @ Set destination address + strh r3,[r0,#0xc] @ Set DMA length + ldr r3,=0x8400 @ dma_copy + strh r3,[r0,#0xe] @ Start DMA +.else +CIDLoop: + ldmia r1!,{r0} + stmia r2!,{r0} + sub r3,#4 + bne CIDLoop +.endif +CIDExit: +If_Undefined_Reference__rename_main_or_AgbMain_to_each_other_in_your_C_file: + bx lr + + .ALIGN + +.ifdef __DMACopyClear +fill_val: .word 0 +reg_base: .word 0x040000d0 +.endif + + .ALIGN + .POOL + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ Interrupt Processing @ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + .ifdef __ISRinIWRAM + .SECTION .iwram + .endif + + .EXTERN IntrTable + .EXTERN InterruptProcess + .GLOBAL intr_main + .ALIGN + .ARM + +@ NOTE: Ifyou copy the following code (start: intr_main - +@ end: intr_main_end) to internal WRAM then do not forget +@ to copy everything between these two labels. The .POOL +@ data must be copied since it is used by intr_main. + +@ NOTE2: If __ISRinIWRAM is defined then the copy to +@ IWRAM is done automatically for you. + + .ifdef __InterruptSupport + + .ifdef __FastInterrupts +intr_main: + ldr r0,=InterruptProcess + bx r0 + .endif + + .ifdef __SingleInterrupts +intr_main: + @ Single interrupts support + mov r3, #0x4000000 @ REG_BASE + ldr r2, [r3,#0x200]! @ Read REG_IE + and r1, r2, r2, lsr #16 @ r1 = IE & IF + ldr r2, =IntrTable + + ands r0, r1, #1 @ V-Blank Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #2 @ H-Blank Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #4 @ V Counter Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #8 @ Timer 0 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x10 @ Timer 1 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x20 @ Timer 2 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x40 @ Timer 3 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x80 @ Serial Communication Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x100 @ DMA0 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x200 @ DMA1 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x400 @ DMA2 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x800 @ DMA3 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x1000 @ Key Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x2000 @ Cart Interrupt + + .ifdef __HandleCartInterrupt + strneb r0, [r3, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X) +loop: bne loop @ Infinite loop if cart removed + .endif + +jump_intr: + strh r0, [r3, #2] @ IF Clear + ldr r0, [r2] @ Jump to user IRQ process + bx r0 + .endif + + .ifdef __MultipleInterrupts +intr_main: + @ Multiple interrupts support + mov r2, #0x4000000 @ REG_BASE + ldr r3, [r2,#0x200]! @ r2 = IE : r3 = IF|IE + ldrh r1, [r2, #0x8] @ r1 = IME + mrs r0, spsr + stmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} // IF|IE + + mov r0, #1 @ IME = 1 (To permit multiple interrupts if + @ an interrupt occurs) + strh r0, [r2, #0x8] + and r1, r3, r3, lsr #16 @ r1 = IE & IF + ldr r12, =IntrTable + + ands r0, r1, #1 @ V-blank interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #2 @ H-blank interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #4 @ V-counter interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #8 @ Timer 0 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x10 @ Timer 1 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x20 @ Timer 2 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x40 @ Timer 3 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x80 @ Serial Communication Interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x100 @ DMA 0 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x200 @ DMA 1 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x400 @ DMA 2 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x800 @ DMA 3 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x1000 @ Key interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x2000 @ Cart interrupt + + .ifdef __HandleCartInterrupt + strneb r0, [r2, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X) +loop: bne loop @ Infinite loop if cart removed + .endif + +jump_intr: + strh r0, [r2, #2] @ Clear IF + +@ Enable multiple interrupts & switch to system +@ mode if __SwitchToUserStack is defined. + + mrs r3, cpsr + .ifdef __SwitchToUserStack + bic r3, r3, #0xdf @ \__ + orr r3, r3, #0x1f @ / --> Enable IRQ & FIQ. Set CPU mode to System. + .else + bic r3, r3, #0xc0 @ Enable IRQ & FIQ + .endif + msr cpsr, r3 + + ldr r0, [r12] + + stmfd sp!, {lr} + adr lr, IntrRet + bx r0 +IntrRet: + ldmfd sp!, {lr} + +@ Disable multiple interrupts & switch to IRQ Mode +@ if __SwitchToUserStack is defined. + + mrs r3, cpsr + .ifdef __SwitchToUserStack + bic r3, r3, #0xdf @ \__ + orr r3, r3, #0x92 @ / --> Disable IRQ. Enable FIQ. Set CPU mode to IRQ. + .else + orr r3, r3, #0x80 @ Disable IRQ. + .endif + msr cpsr, r3 + + ldmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} //IF|IE +@ strh r3, [r2] @ set IE + strh r1, [r2, #0x8] @ restore REG_IME + msr spsr, r0 @ restore spsr + bx lr + + .endif + + .ifdef __AAS_MultipleInterrupts +intr_main: + @ Multiple interrupts support + mov r2, #0x4000000 @ REG_BASE + ldr r3, [r2,#0x200]! @ r2 = IE : r3 = IF|IE + ldrh r1, [r2, #0x8] @ r1 = IME + mrs r0, spsr + stmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} // IF|IE + + and r1, r3, r3, lsr #16 @ r1 = IE & IF + + ands r0, r1, #0x10 @ Timer 1 interrupt + bne jump_intr_AAS + + mov r0, #1 @ IME = 1 (To permit multiple interrupts if + @ an interrupt occurs) + strh r0, [r2, #0x8] + +AAS_intr_start: + ands r0, r1, #1 @ V-blank interrupt + blne jump_intr + ands r0, r1, #2 @ H-blank interrupt + blne jump_intr + ands r0, r1, #4 @ V-counter interrupt + blne jump_intr + ands r0, r1, #8 @ Timer 0 interrupt + blne jump_intr + ands r0, r1, #0x20 @ Timer 2 interrupt + blne jump_intr + ands r0, r1, #0x40 @ Timer 3 interrupt + blne jump_intr + ands r0, r1, #0x80 @ Serial Communication Interrupt + blne jump_intr + ands r0, r1, #0x100 @ DMA 0 interrupt + blne jump_intr + ands r0, r1, #0x200 @ DMA 1 interrupt + blne jump_intr + ands r0, r1, #0x400 @ DMA 2 interrupt + blne jump_intr + ands r0, r1, #0x800 @ DMA 3 interrupt + blne jump_intr + ands r0, r1, #0x1000 @ Key interrupt + blne jump_intr + ands r0, r1, #0x2000 @ Cart interrupt + + .ifdef __HandleCartInterrupt + strneb r0, [r2, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X) +loop: bne loop @ Infinite loop if cart removed + .endif + +jump_intr: + strh r0, [r2, #2] @ Clear IF + +@ Enable multiple interrupts & switch to system +@ mode if __SwitchToUserStack is defined. + + ldr r12, =AAS_IntrTable + adr r0, AAS_intr_start+8 + sub r14, r14, r0 + mov r14, r14, lsr #3 + ldr r0, [r12, r14, lsl #2] + + mrs r3, cpsr + bic r3, r3, #0xc0 @ Enable IRQ & FIQ + .ifdef __SwitchToUserStack + orr r3, r3, #0x1f @ Set CPU mode to System. + .endif + msr cpsr, r3 + + stmfd sp!, {lr} + adr lr, IntrRet + bx r0 + +IntrRet: + ldmfd sp!, {lr} + +@ Disable multiple interrupts & switch to IRQ Mode +@ if __SwitchToUserStack is defined. + + mrs r3, cpsr + .ifdef __SwitchToUserStack + bic r3, r3, #0xdf @ \__ + orr r3, r3, #0x92 @ / --> Disable IRQ. Enable FIQ. Set CPU mode to IRQ. + .else + orr r3, r3, #0x80 @ Disable IRQ. + .endif + msr cpsr, r3 + + ldmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} //IF|IE + strh r1, [r2, #0x8] @ restore REG_IME + msr spsr, r0 @ restore spsr + bx lr + +jump_intr_AAS: + strh r0, [r2, #2] @ Clear IF + +@ Switch to system mode if __SwitchToUserStack is defined. + + .ifdef __SwitchToUserStack + mrs r3, cpsr + orr r3, r3, #0x1f @ Set CPU mode to System. + msr cpsr, r3 + .endif + + ldr r0, =AAS_FastTimer1InterruptHandler + + stmfd sp!, {lr} + adr lr, IntrRet + bx r0 + + .endif + + .ALIGN + .POOL @ If you copy the intr_main routine, above, to internal + @ RAM then copy the pool data as well because IntrTable + @ address is stored here. Use intr_main_end as last address+1. +intr_main_end: + .endif + + .ALIGN + .POOL + + + .END + + diff --git a/lib/apex-audio-system/examples/AASExample/lnkscript b/lib/apex-audio-system/examples/AASExample/lnkscript new file mode 100644 index 0000000..30cb9c0 --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample/lnkscript @@ -0,0 +1,297 @@ +/* Linker Script v1.3 by Jeff Frohwein */ +/* v1.0 - Original release */ +/* v1.1 - Added proper .data section support */ +/* v1.2 - Added support for c++ & iwram overlays */ +/* - Major contributions by Jason Wilkins. */ +/* v1.3 - .ewram section now can be used when */ +/* compiling for MULTIBOOT mode. This fixes */ +/* malloc() in DevKitAdvance which depends */ +/* on __eheap_start instead of end to define*/ +/* the starting location of heap space. */ +/* External global variable __gba_iwram_heap*/ +/* support added to allow labels end, _end, */ +/* & __end__ to point to end of iwram or */ +/* the end of ewram. */ + +/* This file is released into the public domain */ +/* for commercial or non-commercial use with no */ +/* restrictions placed upon it. */ + +/* NOTE!!!: This linker script defines the RAM & */ +/* ROM start addresses. In order for it to work */ +/* properly, remove -Ttext and -Tbss linker */ +/* options from your makefile if they are */ +/* present. */ + +/* You can use the following to view section */ +/* addresses in your .elf file: */ +/* objdump -h file.elf */ +/* Please note that empty sections may incorrectly*/ +/* list the lma address as the vma address for */ +/* some versions of objdump. */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +/* SEARCH_DIR(/bin/arm); */ + +/* By default this linker script will generate code */ +/* for flash carts located at 0x8000000. In order to */ +/* generate code that is compiled at 0x2000000 that */ +/* will run on flash carts or in multiboot mode then */ +/* you need to add the following variable to your main */ +/* project file. It's value is NOT important but */ +/* IT MUST BE A GLOBAL VARIABLE OR IT WILL NOT WORK: */ + +/* #define MULTIBOOT int __gba_multiboot; */ +/* Then use it like this: MULTIBOOT */ + +/* By default this linker script will set the labels */ +/* end, _end, & __end__ at the end of ewram. To force */ +/* them to be set to the end of iwram then you need to */ +/* add the following variable to your main */ +/* project file. It's value is NOT important but */ +/* IT MUST BE A GLOBAL VARIABLE OR IT WILL NOT WORK: */ + +/* #define IWRAMHEAP int __gba_iwram_heap; */ +/* Then use it like this: IWRAMHEAP */ + +/* The linker script function "var1 += var2;" sometimes */ +/* reports incorrect values in the *.map file but the */ +/* actual value it calculates is usually, if not always, */ +/* correct. If you leave out the ". = ALIGN(4);" at the */ +/* end of each section then the return value of SIZEOF() */ +/* is sometimes incorrect and "var1 += var2;" appears to */ +/* not work as well. "var1 += var2" style functions are */ +/* avoided below as a result. */ + +/* The linker script MEMORY directive is not used here due */ +/* to the fact that __text_start is not always a fixed value. */ + +__text_start = DEFINED (__gba_multiboot) ? 0x2000000 : 0x8000000; +/* __ewram_start = 0x2000000; */ /* Removed in v1.3 */ +__eheap_end = 0x2040000; +__iwram_start = 0x3000000; +__iheap_end = 0x3008000 - 0x400; +__sp_usr = 0x3008000 - 0x100; +__sp_irq = 0x3008000 - 0x60; +__intr_vector_buf = 0x3008000 - 4; +__sp_usr_offset = __sp_usr - __iwram_start; +__intr_vect_offset = __intr_vector_buf - __sp_usr; + +SECTIONS +{ + .text __text_start : /* ALIGN (4): */ + { + *(EXCLUDE_FILE (*text.iwram*) .text) + *(.text.*) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + *(.glue_7) + *(.glue_7t) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0xff +/* laddr = ADDR(.text) + SIZEOF(.text); */ + __text_end = .; + + .rodata : + { + *(.rodata) + *all.rodata*(*) + *(.roda) + *(.rodata.*) + *(.gnu.linkonce.r*) + SORT(CONSTRUCTORS) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0xff +/* laddr += SIZEOF(.rodata); */ + + .ctors : + { + /* gcc uses crtbegin.o to find the start of the constructors, so + we make sure it is first. Because this is a wildcard, it + doesn't matter if the user does not actually link against + crtbegin.o; the linker won't look for a file to match a + wildcard. The wildcard also means that it doesn't matter which + directory crtbegin.o is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0 +/* laddr += SIZEOF(.ctors); */ + laddr = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors); + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0 +/* laddr += SIZEOF(.dtors); */ + laddr = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors); + + .eh_frame : + { + KEEP (*(.eh_frame)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0 +/* laddr += SIZEOF(.eh_frame); */ + + .gcc_except_table : + { + *(.gcc_except_table) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0 +/* laddr += (SIZEOF(.gcc_except_table) + 3) & ~ 3; */ +/* __iwram_lma = laddr; */ + __iwram_lma = (ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors) + SIZEOF(.eh_frame) + SIZEOF(.gcc_except_table) + 3) & ~ 3; + + .iwram __iwram_start : AT (__iwram_lma) + { + __iwram_start = ABSOLUTE(.) ; + *(.iwram) + *iwram.*(.text) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0xff +/* laddr += SIZEOF(.iwram); */ +/* __data_lma = laddr; */ + __data_lma = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors) + SIZEOF(.eh_frame) + SIZEOF(.gcc_except_table) + SIZEOF(.iwram); + + __iwram_end = . ; + + .bss ALIGN(4) : + { + __bss_start = ABSOLUTE(.); + __bss_start__ = ABSOLUTE(.); + *(.dynbss) + *(.gnu.linkonce.b*) + *(COMMON) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } + + __bss_end = . ; + __bss_end__ = . ; + + .data ALIGN(4) : AT (__data_lma) + { + __data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + CONSTRUCTORS + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0xff +/* laddr += SIZEOF(.data); */ +/* __iwram_overlay_lma = laddr; */ + __iwram_overlay_lma = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors) + SIZEOF(.eh_frame) + SIZEOF(.gcc_except_table) + SIZEOF(.iwram) + SIZEOF(.data); + + __data_end = .; + PROVIDE (edata = .); +/* __data_lma = LOADADDR(.data); */ + __iwram_overlay_start = . ; + + OVERLAY : NOCROSSREFS AT (__iwram_overlay_lma) + { + .iwram0 { *(.iwram0) . = ALIGN(4);} + .iwram1 { *(.iwram1) . = ALIGN(4);} + .iwram2 { *(.iwram2) . = ALIGN(4);} + .iwram3 { *(.iwram3) . = ALIGN(4);} + .iwram4 { *(.iwram4) . = ALIGN(4);} + .iwram5 { *(.iwram5) . = ALIGN(4);} + .iwram6 { *(.iwram6) . = ALIGN(4);} + .iwram7 { *(.iwram7) . = ALIGN(4);} + .iwram8 { *(.iwram8) . = ALIGN(4);} + .iwram9 { *(.iwram9) . = ALIGN(4);} + } = 0xff +/* laddr += (SIZEOF(.iwram0)+SIZEOF(.iwram1)+SIZEOF(.iwram2)+SIZEOF(.iwram3)+SIZEOF(.iwram4)+SIZEOF(.iwram5)+SIZEOF(.iwram6)+SIZEOF(.iwram7)+SIZEOF(.iwram8)+SIZEOF(.iwram9)); */ +/* __ewram_lma = laddr; */ + __ewram_lma = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors) + SIZEOF(.eh_frame) + SIZEOF(.gcc_except_table) + SIZEOF(.iwram) + SIZEOF(.data) + SIZEOF(.iwram0)+SIZEOF(.iwram1)+SIZEOF(.iwram2)+SIZEOF(.iwram3)+SIZEOF(.iwram4)+SIZEOF(.iwram5)+SIZEOF(.iwram6)+SIZEOF(.iwram7)+SIZEOF(.iwram8)+SIZEOF(.iwram9); + +/* __iwram_overlay_lma = LOADADDR (.iwram0); */ + __iwram_overlay_end = . ; +/* _end = . ; */ +/* __end__ = . ; */ +/* PROVIDE (end = .); */ + __iheap_start = . ; + + /* v1.3 */ + __ewram_start = DEFINED (__gba_multiboot) ? __ewram_lma : 0x2000000; + + .ewram __ewram_start : AT (__ewram_lma) + { +/* __ewram_start = ABSOLUTE(.); */ + *(.ewram) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0xff +/* laddr += SIZEOF(.ewram); */ +/* __ewram_overlay_lma = laddr; */ + __ewram_overlay_lma = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors) + SIZEOF(.eh_frame) + SIZEOF(.gcc_except_table) + SIZEOF(.iwram) + SIZEOF(.data) + SIZEOF(.iwram0)+SIZEOF(.iwram1)+SIZEOF(.iwram2)+SIZEOF(.iwram3)+SIZEOF(.iwram4)+SIZEOF(.iwram5)+SIZEOF(.iwram6)+SIZEOF(.iwram7)+SIZEOF(.iwram8)+SIZEOF(.iwram9) + SIZEOF(.ewram); + +/* __ewram_lma = LOADADDR(.ewram); */ + __ewram_end = . ; + __ewram_overlay_start = . ; + + OVERLAY ALIGN(4): NOCROSSREFS AT (__ewram_overlay_lma) + { + .ewram0 { *(.ewram0) . = ALIGN(4);} + .ewram1 { *(.ewram1) . = ALIGN(4);} + .ewram2 { *(.ewram2) . = ALIGN(4);} + .ewram3 { *(.ewram3) . = ALIGN(4);} + .ewram4 { *(.ewram4) . = ALIGN(4);} + .ewram5 { *(.ewram5) . = ALIGN(4);} + .ewram6 { *(.ewram6) . = ALIGN(4);} + .ewram7 { *(.ewram7) . = ALIGN(4);} + .ewram8 { *(.ewram8) . = ALIGN(4);} + .ewram9 { *(.ewram9) . = ALIGN(4);} + } = 0xff + + __ewram_overlay_end = . ; + + __eheap_start = . ; + + _end = DEFINED (__gba_iwram_heap) ? __iheap_start : .; /* v1.3 */ + __end__ = _end ; /* v1.3 */ + PROVIDE (end = _end); /* v1.3 */ + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .stack 0x80000 : { _stack = .; *(.stack) } + /* These must appear regardless of . */ +} diff --git a/lib/apex-audio-system/examples/AASExample2/AASExample.c b/lib/apex-audio-system/examples/AASExample2/AASExample.c new file mode 100644 index 0000000..747ff99 --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample2/AASExample.c @@ -0,0 +1,87 @@ +// AAS Example for projects with other CPU intensive interrupts +// Notes: +// + Specially modified crt0.s file included with the example must be set to use __AAS_MultipleInterrupts +// + AAS_DoWork() must be called at least 50 times/sec. In this example, it's being called during VBlank. + +#include "AAS.h" +#include "AAS_Data.h" + +// Registers for interrupt handler +#define REG_IE (*(volatile AAS_u16 *)0x4000200) +#define REG_IME (*(volatile AAS_u16 *)0x4000208) +#define REG_DISPSTAT (*(volatile AAS_u16*)0x04000004) + +void VBlankInterruptHandler() +{ + AAS_DoWork(); + + // Insert your own VBlank code here +} + +void UnusedInterruptHandler() +{ +}; + +void (*AAS_IntrTable[13])(void) = +{ + VBlankInterruptHandler, // VBlank Interrupt + UnusedInterruptHandler, // HBlank Interrupt + UnusedInterruptHandler, // V Counter Interrupt + UnusedInterruptHandler, // Timer 0 Interrupt + UnusedInterruptHandler, // Timer 2 Interrupt + UnusedInterruptHandler, // Timer 3 Interrupt + UnusedInterruptHandler, // Serial Communication Interrupt + UnusedInterruptHandler, // DMA0 Interrupt + UnusedInterruptHandler, // DMA1 Interrupt + UnusedInterruptHandler, // DMA2 Interrupt + UnusedInterruptHandler, // DMA3 Interrupt + UnusedInterruptHandler, // Key Interrupt + UnusedInterruptHandler // Cart Interrupt +}; + +// Registers for GBA keys +#define REG_KEY (*(volatile AAS_u16 *)0x04000130) +#define REG_KEY_A 0x0001 +#define REG_KEY_B 0x0002 + +void AgbMain() +{ + int keys, keys_changed; + int prev_keys = 0; + + // Enable vblank interrupt + REG_DISPSTAT |= 0x8; + REG_IE |= 0x1; + + // Initialise AAS + AAS_SetConfig( AAS_CONFIG_MIX_32KHZ, AAS_CONFIG_CHANS_8, AAS_CONFIG_SPATIAL_STEREO, AAS_CONFIG_DYNAMIC_OFF ); + + // Start playing MOD + AAS_MOD_Play( AAS_DATA_MOD_CreamOfTheEarth ); + + // 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 ); +} diff --git a/lib/apex-audio-system/examples/AASExample2/AAS_Data/Ambulance.wav b/lib/apex-audio-system/examples/AASExample2/AAS_Data/Ambulance.wav new file mode 100644 index 0000000..94d9d62 Binary files /dev/null and b/lib/apex-audio-system/examples/AASExample2/AAS_Data/Ambulance.wav differ diff --git a/lib/apex-audio-system/examples/AASExample2/AAS_Data/Boom.raw b/lib/apex-audio-system/examples/AASExample2/AAS_Data/Boom.raw new file mode 100644 index 0000000..7537624 Binary files /dev/null and b/lib/apex-audio-system/examples/AASExample2/AAS_Data/Boom.raw differ diff --git a/lib/apex-audio-system/examples/AASExample2/AAS_Data/CreamOfTheEarth.mod b/lib/apex-audio-system/examples/AASExample2/AAS_Data/CreamOfTheEarth.mod new file mode 100644 index 0000000..13cbe1a Binary files /dev/null and b/lib/apex-audio-system/examples/AASExample2/AAS_Data/CreamOfTheEarth.mod differ diff --git a/lib/apex-audio-system/examples/AASExample2/Makefile b/lib/apex-audio-system/examples/AASExample2/Makefile new file mode 100644 index 0000000..4387a47 --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample2/Makefile @@ -0,0 +1,8 @@ +# AAS Example Makefile +EXAMPLE2_PREFIX ?= AASExample2 +SHORTNAME = $(EXAMPLE2_PREFIX) + +CROSS ?= arm-none-eabi- +LD = $(CROSS)gcc + +include ../../make/example.make diff --git a/lib/apex-audio-system/examples/AASExample2/crt0.s b/lib/apex-audio-system/examples/AASExample2/crt0.s new file mode 100644 index 0000000..ae4c056 --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample2/crt0.s @@ -0,0 +1,781 @@ +@******************************************************************** +@* crt0.S v1.26 by Jeff Frohwein * +@******************************************************************** + +@ - Modified by James Daniels/Apex Designs to give AAS interrupts higher priority in special +@ "AAS_MultipleInterrupts" mode + +@ v1.0 - Original release +@ v1.1 - Added proper .data section support +@ v1.2 - Added support for c++, overlays, interrupts, and +@ far calls (__FarFunction & __FarProcedure). +@ - Some ideas from Jason Wilkins & Mike Heckenbach. +@ v1.21- Killed the dumb test bug left in the code. +@ v1.22- Killed dumb bug "numero dos" in multiple interrupts routine. Thanks Mike H. :) +@ v1.23- Now correctly handles zero length .bss section. +@ v1.24- Loop back to start_vector now works if main {} exits. +@ v1.25- __FarProcedure now works. It was missing a .thumb_func directive. +@ v1.26- Added missing Serial Interrupt processing to __MultipleInterrupts section. +@ Added __FastInterrupt option for minimal interrupt processing. +@ Optimized __MultipleInterrupts section to save 4 bytes of stack space. +@ Added __ISRinIWRAM option that puts interrupt processing in IWRAM by default. +@ Options passed to main() or AgbMain() are now set to 0. (Thanks to DarkFader) +@ +@ This file is released into the public domain for commercial +@ or non-commercial usage with no restrictions placed upon it. + + .TEXT + +@ Comment out the next line ONLY if you plan to never support +@ multiboot mode and want to save a few bytes by removing +@ multiboot support code. Otherwise, leave it alone. It wont +@ disturb code designed to run only on flash carts. +@ +@ The normal way to enable generating code that works with +@ both multiboot and flash carts is to add the following to +@ your C code in your main project file AS A GLOBAL VARIABLE: +@ +@ #define MULTIBOOT int __gba_multiboot; +@ Then use it like this : MULTIBOOT +@ +@ IT MUST BE A GLOBAL VARIABLE OR IT WILL NOT WORK! +@ If this variable is not defined somewhere in your project +@ then code will be generated to run out of ROM instead of +@ EXRAM. The value of this variable is not important. + + .equ __MultiBootInclude, 1 + +@ If you are compiling for multiboot dedicated (will not +@ run in a cart) code then uncomment the following. Normally +@ you should leave this commented out so that a multiboot +@ image will run in a cart as well (by copying from ROM to RAM). +@ +@ This sets the maker code to "MB " which is a key that +@ some emulators look for to know to load the rom image +@ at 0x2000000 instead of the standard 0x8000000. + +@ .equ __MultibootDedicated, 1 + +@ There are two methods for clearing memory and +@ copying appropriate setup data. The fast & bulky +@ method is GBA DMA copy/clear but some emulators +@ do not accurately do DMA. If you have an inaccurate +@ emulator or want to conserve ROM space then comment +@ out the following line. There is not much advantage +@ gained by doing DMA copy/clear. + +@ .equ __DMACopyClear, 1 + +@ Uncomment the following line to support C++ development. +@ You also need to name your main C function the following: +@ int main (void) ...instead of... int AgbMain (void) +@ Doing so will cause ~5500 bytes of c++ support code to be +@ linked in with your project so do not enable c++ support +@ unless you plan to use it. + +@ .equ __CPPSupport, 1 + +@ Comment out the following line to disable interrupt support +@ in your code and to save some space in this file. + + .equ __InterruptSupport, 1 + + +@ Comment out the following line to put interrupt support in +@ ROM instead of IWRAM. Interrupt support in ROM will slow +@ down interrupt execution and has no advantage other than +@ saving a little bit of IWRAM. + + .equ __ISRinIWRAM, 1 + +@ NOTE: Only ONE of the following 3 interrupt options may be +@ uncommented. Also, __InterruptSupport above must be uncommented +@ for any of the following to have an effect. +@ +@ __FastInterrupts +@ Uncomment this line for minimal interrupt processing. +@ +@ __SingleInterrupts +@ Uncomment this line if you wish to use a table of function +@ pointers to process specific interrupts. +@ +@ __MultipleInterrupts +@ Uncomment this line to allow multiple-interrupts-at-once +@ support. If you have several interrupts where one can +@ occur while another is being serviced then you need to +@ enable this option. +@ +@ __AAS_MultipleInterrupts +@ Uncomment this line to allow multiple-interrupts-at-once +@ support, giving the AAS interrupt higher priority. If +@ you have several interrupts where one can occur while +@ another is being serviced then you need to enable this +@ option. Only for use with AAS! Added by James Daniels. + +@ .equ __FastInterrupts, 1 +@ .equ __SingleInterrupts, 1 +@ .equ __MultipleInterrupts, 1 +.equ __AAS_MultipleInterrupts, 1 + + +@ Uncomment the following line to disable sound and enter an +@ infinite loop if cart is removed during game play. You +@ must have the cart interrupt enabled for this to work and +@ __ISRinIWRAM, above, must be enabled (not commented out.) + +@ .equ __HandleCartInterrupt, 1 + +@ The following prevents IRQ stack overflow by switching to +@ System mode (User stack) when handling multiple interrupts. +@ To force use of IRQ stack only, comment out the following line. + + .equ __SwitchToUserStack, 1 + +@ !!!! NOTE: THE COPY ROUTINES IN THIS FILE WORK ON 4 BYTE +@ BOUNDARIES. YOUR LINKER SCRIPT MUST ALIGN SECTION STARTS +@ AND SECTION ENDS FOR SECTIONS THAT GET COPIED TO RAM WITH +@ ALIGN(4) !!!! + + .GLOBAL _start +_start: + .ALIGN + .CODE 32 + @ Start Vector + + b rom_header_end + + @ Nintendo Logo Character Data (8000004h) + .fill 156,1,0 + + @ Game Title (80000A0h) + .ascii "AAS Example" + .byte 0x00 + + .ifdef __MultibootDedicated + @ Game Code (80000ACh) + .ascii "MB " + .else + @ Game Code (80000ACh) + .byte 0x00,0x00,0x00,0x00 + .endif + + @ Maker Code (80000B0h) + .byte 0x30,0x31 + + @ Fixed Value (80000B2h) + .byte 0x96 + + @ Main Unit Code (80000B3h) + .byte 0x00 + + @ Device Type (80000B4h) + .byte 0x00 + + @ Unused Data (7Byte) (80000B5h) + .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00 + + @ Software Version No (80000BCh) + .byte 0x00 + + @ Complement Check (80000BDh) + .byte 0xf0 + + @ Checksum (80000BEh) + .byte 0x00,0x00 + + .ALIGN + .ARM @ ..or you can use CODE 32 here + +rom_header_end: + b start_vector @ This branch must be here for proper + @ positioning of the following header. + @ DO NOT REMOVE IT. + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ The following reserved bytes are used if the code is compiled for @ +@ multiboot mode. It does not hurt anything to leave this header in +@ even if the code is not compiled for multiboot. The GBA BIOS will +@ auto-patch the first two bytes with 0x03 and 0x01, respectively, +@ before running any code if it is executed as multiboot. +@ + +@ The following two bytes are included even for non-multiboot supporting +@ builds to guarantee that any generic library code that depends on them +@ will still be functional. + + .GLOBAL __boot_method, __slave_number + +__boot_method: + .byte 0 @ boot method (0=ROM boot, 3=Multiplay boot) +__slave_number: + .byte 0 @ slave # (1=slave#1, 2=slave#2, 3=slave#3) + + .ifdef __MultiBootInclude + + .byte 0 @ reserved + .byte 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .endif +@ @ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +@@@@@@@@@@@@@@@@@@@@@@ +@ Reset @ +@@@@@@@@@@@@@@@@@@@@@@ + + .GLOBAL start_vector + .ALIGN + .ARM @ ..or you can use CODE 32 here +start_vector: + mov r0, #0x12 @ Switch to IRQ Mode + msr cpsr, r0 + ldr sp,=__sp_irq @ Set SP_irq + mov r0, #0x1f @ Switch to System Mode + msr cpsr, r0 + ldr sp,=__sp_usr @ Set SP_usr + +@ Enter Thumb mode + adr r0,1f + 1 @ add r0,pc,#1 also works here + @ for those that want to conserve labels. + bx r0 + + .THUMB @ ..or you can use .CODE 16 here +1: + + .ifdef __InterruptSupport + ldr r1, =__intr_vector_buf @ Set Interrupt Address + ldr r0, =intr_main + str r0, [r1] + .endif + + .ifdef __MultiBootInclude + +@ *** Multiboot Copy Routine *** +@ Check the Program Counter to see if code is running +@ at 0x2000000 or 0x8000000. If it is running at 0x8000000 +@ then copy 256K bytes of it to 0x2000000 and then branch +@ to 0x2000000. +@ The reason for all this is to allow a program to be used +@ "as is" with an flash cart/emulator or with an MBV2-style +@ multiboot cable. +@ NOTE: You can also detect if this ROM is running from +@ 0x2000000 by checking the multiboot header above. + + ldr r0,=__text_start + lsl r0,#5 @ Was code compiled at 0x08000000 or higher? + bcs DoEWRAMClear @ yes, you can not run it in external WRAM + +@ Make sure we're in ExWRAM + + mov r0,pc + lsl r0,#5 @ Are we running from ROM (0x8000000 or higher) ? + bcc SkipEWRAMClear @ No, so no need to do a copy. + +@ We were started in ROM, silly emulators. :P +@ So we need to copy to ExWRAM. + + mov r3,#0x40 + lsl r3,#12 @ r3 = 0x40000 + lsl r2,r3,#7 @ r2 = 0x2000000 + mov r6,r2 @ r6 = 0x2000000 + lsl r1,r2,#2 @ r1 = 0x8000000 + + bl CopyMem + +@ Jump to the code to execute + + bx r6 + .endif + +DoEWRAMClear: +@ Clear External WRAM to 0x00 + + mov r1,#0x40 + lsl r1,#12 @ r1 = 0x40000 + lsl r0,r1,#7 @ r0 = 0x2000000 + bl ClearMem + +SkipEWRAMClear: +@ ldr r0,=AgbMain +@ bx r0 + +@ Clear Internal WRAM to 0x00 + mov r0,#3 + lsl r0,#24 @ r0 = 0x3000000 + ldr r1,=__sp_usr_offset - 16 + bl ClearMem + + .ifdef __MultiBootInclude +@ Clear BSS section to 0x00 +@ (Sometimes BSS may be in External WRAM) + ldr r0,=__bss_start + ldr r1,=__bss_end + sub r1,r0 + bl ClearMem + .endif + +@ Copy initialized data (data section) from LMA to VMA (ROM to RAM) + ldr r1,=__data_lma + ldr r2,=__data_start + ldr r4,=__data_end + bl CopyMemChk + +@ Copy internal work ram (iwram section) from LMA to VMA (ROM to RAM) + ldr r1,=__iwram_lma + ldr r2,=__iwram_start + ldr r4,=__iwram_end + bl CopyMemChk + +@ Copy internal work ram overlay 0 (iwram0 section) from LMA to VMA (ROM to RAM) + ldr r2,=__load_stop_iwram0 + ldr r1,=__load_start_iwram0 + sub r3,r2,r1 @ Is there any data to copy? + beq CIW0Skip @ no + + ldr r2,=__iwram_overlay_start + bl CopyMem +CIW0Skip: + +@ Copy external work ram (ewram section) from LMA to VMA (ROM to RAM) + ldr r1,=__ewram_lma + ldr r2,=__ewram_start + ldr r4,=__ewram_end + bl CopyMemChk + +@ Copy external work ram overlay 0 (ewram0 section) from LMA to VMA (ROM to RAM) + ldr r2,=__load_stop_ewram0 + ldr r1,=__load_start_ewram0 + sub r3,r2,r1 @ Is there any data to copy? + beq CEW0Skip @ no + + ldr r2,=__ewram_overlay_start + bl CopyMem +CEW0Skip: + +@ Jump to user code + + mov r0,#0 @ int argc + mov r1,#0 @ char *argv[] + + ldr r3,=start_vector + mov lr,r3 @ Set start_vector as return address + +.ifdef __CPPSupport + ldr r3,=main +.else + ldr r3,=AgbMain +.endif + bx r3 + + + .GLOBAL __FarFunction,__FarProcedure + .THUMB_FUNC +__FarFunction: + .THUMB_FUNC +__FarProcedure: + bx r0 + nop + nop @ This nop is here to allow unmapped memory to be used as + @ as a delay of almost 1 sec with a 1 cycle resolution. + @ Read this for technical info: + @ http://www.devrs.com/gba/files/gbadevfaqs.php#RepeatUses + +@ Clear memory to 0x00 if length != 0 +@ r0 = Start Address +@ r1 = Length + +ClearMem: + cmp r1,#0 @ Is length zero? + beq ClearMX @ yes, exit + +.ifdef __DMACopyClear + ldr r2,reg_base + lsr r1,#2 @ r1 = (length/4) & 0xffff + + adr r3,fill_val + str r3,[r2,#0x4] @ Set source address (fill value) + str r0,[r2,#0x8] @ Set destination address (fill dest address) + strh r1,[r2,#0xc] @ Set DMA length + ldr r1,=0x8500 @ dma_clrb + strh r1,[r2,#0xe] @ Start DMA +.else + mov r2,#0 +ClrLoop: + stmia r0!,{r2} + sub r1,#4 + bne ClrLoop +.endif +ClearMX: + bx lr + +@ Copy memory if length != 0 +@ r1 = Source Address +@ r2 = Dest Address +@ r4 = Dest Address + Length + +CopyMemChk: + sub r3,r4,r2 @ Is there any data to copy? + beq CIDExit @ no + +@ Copy memory +@ r1 = Source Address +@ r2 = Dest Address +@ r3 = Length + +CopyMem: +.ifdef __DMACopyClear + ldr r0,reg_base + lsr r3,#2 @ r3 = (length/4) & 0xffff + + str r1,[r0,#0x4] @ Set source address + str r2,[r0,#0x8] @ Set destination address + strh r3,[r0,#0xc] @ Set DMA length + ldr r3,=0x8400 @ dma_copy + strh r3,[r0,#0xe] @ Start DMA +.else +CIDLoop: + ldmia r1!,{r0} + stmia r2!,{r0} + sub r3,#4 + bne CIDLoop +.endif +CIDExit: +If_Undefined_Reference__rename_main_or_AgbMain_to_each_other_in_your_C_file: + bx lr + + .ALIGN + +.ifdef __DMACopyClear +fill_val: .word 0 +reg_base: .word 0x040000d0 +.endif + + .ALIGN + .POOL + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ Interrupt Processing @ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + .ifdef __ISRinIWRAM + .SECTION .iwram + .endif + + .EXTERN IntrTable + .EXTERN InterruptProcess + .GLOBAL intr_main + .ALIGN + .ARM + +@ NOTE: Ifyou copy the following code (start: intr_main - +@ end: intr_main_end) to internal WRAM then do not forget +@ to copy everything between these two labels. The .POOL +@ data must be copied since it is used by intr_main. + +@ NOTE2: If __ISRinIWRAM is defined then the copy to +@ IWRAM is done automatically for you. + + .ifdef __InterruptSupport + + .ifdef __FastInterrupts +intr_main: + ldr r0,=InterruptProcess + bx r0 + .endif + + .ifdef __SingleInterrupts +intr_main: + @ Single interrupts support + mov r3, #0x4000000 @ REG_BASE + ldr r2, [r3,#0x200]! @ Read REG_IE + and r1, r2, r2, lsr #16 @ r1 = IE & IF + ldr r2, =IntrTable + + ands r0, r1, #1 @ V-Blank Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #2 @ H-Blank Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #4 @ V Counter Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #8 @ Timer 0 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x10 @ Timer 1 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x20 @ Timer 2 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x40 @ Timer 3 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x80 @ Serial Communication Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x100 @ DMA0 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x200 @ DMA1 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x400 @ DMA2 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x800 @ DMA3 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x1000 @ Key Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x2000 @ Cart Interrupt + + .ifdef __HandleCartInterrupt + strneb r0, [r3, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X) +loop: bne loop @ Infinite loop if cart removed + .endif + +jump_intr: + strh r0, [r3, #2] @ IF Clear + ldr r0, [r2] @ Jump to user IRQ process + bx r0 + .endif + + .ifdef __MultipleInterrupts +intr_main: + @ Multiple interrupts support + mov r2, #0x4000000 @ REG_BASE + ldr r3, [r2,#0x200]! @ r2 = IE : r3 = IF|IE + ldrh r1, [r2, #0x8] @ r1 = IME + mrs r0, spsr + stmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} // IF|IE + + mov r0, #1 @ IME = 1 (To permit multiple interrupts if + @ an interrupt occurs) + strh r0, [r2, #0x8] + and r1, r3, r3, lsr #16 @ r1 = IE & IF + ldr r12, =IntrTable + + ands r0, r1, #1 @ V-blank interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #2 @ H-blank interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #4 @ V-counter interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #8 @ Timer 0 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x10 @ Timer 1 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x20 @ Timer 2 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x40 @ Timer 3 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x80 @ Serial Communication Interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x100 @ DMA 0 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x200 @ DMA 1 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x400 @ DMA 2 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x800 @ DMA 3 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x1000 @ Key interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x2000 @ Cart interrupt + + .ifdef __HandleCartInterrupt + strneb r0, [r2, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X) +loop: bne loop @ Infinite loop if cart removed + .endif + +jump_intr: + strh r0, [r2, #2] @ Clear IF + +@ Enable multiple interrupts & switch to system +@ mode if __SwitchToUserStack is defined. + + mrs r3, cpsr + .ifdef __SwitchToUserStack + bic r3, r3, #0xdf @ \__ + orr r3, r3, #0x1f @ / --> Enable IRQ & FIQ. Set CPU mode to System. + .else + bic r3, r3, #0xc0 @ Enable IRQ & FIQ + .endif + msr cpsr, r3 + + ldr r0, [r12] + + stmfd sp!, {lr} + adr lr, IntrRet + bx r0 +IntrRet: + ldmfd sp!, {lr} + +@ Disable multiple interrupts & switch to IRQ Mode +@ if __SwitchToUserStack is defined. + + mrs r3, cpsr + .ifdef __SwitchToUserStack + bic r3, r3, #0xdf @ \__ + orr r3, r3, #0x92 @ / --> Disable IRQ. Enable FIQ. Set CPU mode to IRQ. + .else + orr r3, r3, #0x80 @ Disable IRQ. + .endif + msr cpsr, r3 + + ldmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} //IF|IE +@ strh r3, [r2] @ set IE + strh r1, [r2, #0x8] @ restore REG_IME + msr spsr, r0 @ restore spsr + bx lr + + .endif + + .ifdef __AAS_MultipleInterrupts +intr_main: + @ Multiple interrupts support + mov r2, #0x4000000 @ REG_BASE + ldr r3, [r2,#0x200]! @ r2 = IE : r3 = IF|IE + ldrh r1, [r2, #0x8] @ r1 = IME + mrs r0, spsr + stmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} // IF|IE + + and r1, r3, r3, lsr #16 @ r1 = IE & IF + + ands r0, r1, #0x10 @ Timer 1 interrupt + bne jump_intr_AAS + + mov r0, #1 @ IME = 1 (To permit multiple interrupts if + @ an interrupt occurs) + strh r0, [r2, #0x8] + +AAS_intr_start: + ands r0, r1, #1 @ V-blank interrupt + blne jump_intr + ands r0, r1, #2 @ H-blank interrupt + blne jump_intr + ands r0, r1, #4 @ V-counter interrupt + blne jump_intr + ands r0, r1, #8 @ Timer 0 interrupt + blne jump_intr + ands r0, r1, #0x20 @ Timer 2 interrupt + blne jump_intr + ands r0, r1, #0x40 @ Timer 3 interrupt + blne jump_intr + ands r0, r1, #0x80 @ Serial Communication Interrupt + blne jump_intr + ands r0, r1, #0x100 @ DMA 0 interrupt + blne jump_intr + ands r0, r1, #0x200 @ DMA 1 interrupt + blne jump_intr + ands r0, r1, #0x400 @ DMA 2 interrupt + blne jump_intr + ands r0, r1, #0x800 @ DMA 3 interrupt + blne jump_intr + ands r0, r1, #0x1000 @ Key interrupt + blne jump_intr + ands r0, r1, #0x2000 @ Cart interrupt + + .ifdef __HandleCartInterrupt + strneb r0, [r2, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X) +loop: bne loop @ Infinite loop if cart removed + .endif + +jump_intr: + strh r0, [r2, #2] @ Clear IF + +@ Enable multiple interrupts & switch to system +@ mode if __SwitchToUserStack is defined. + + ldr r12, =AAS_IntrTable + adr r0, AAS_intr_start+8 + sub r14, r14, r0 + mov r14, r14, lsr #3 + ldr r0, [r12, r14, lsl #2] + + mrs r3, cpsr + bic r3, r3, #0xc0 @ Enable IRQ & FIQ + .ifdef __SwitchToUserStack + orr r3, r3, #0x1f @ Set CPU mode to System. + .endif + msr cpsr, r3 + + stmfd sp!, {lr} + adr lr, IntrRet + bx r0 + +IntrRet: + ldmfd sp!, {lr} + +@ Disable multiple interrupts & switch to IRQ Mode +@ if __SwitchToUserStack is defined. + + mrs r3, cpsr + .ifdef __SwitchToUserStack + bic r3, r3, #0xdf @ \__ + orr r3, r3, #0x92 @ / --> Disable IRQ. Enable FIQ. Set CPU mode to IRQ. + .else + orr r3, r3, #0x80 @ Disable IRQ. + .endif + msr cpsr, r3 + + ldmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} //IF|IE + strh r1, [r2, #0x8] @ restore REG_IME + msr spsr, r0 @ restore spsr + bx lr + +jump_intr_AAS: + strh r0, [r2, #2] @ Clear IF + +@ Switch to system mode if __SwitchToUserStack is defined. + + .ifdef __SwitchToUserStack + mrs r3, cpsr + orr r3, r3, #0x1f @ Set CPU mode to System. + msr cpsr, r3 + .endif + + ldr r0, =AAS_FastTimer1InterruptHandler + + stmfd sp!, {lr} + adr lr, IntrRet + bx r0 + + .endif + + .ALIGN + .POOL @ If you copy the intr_main routine, above, to internal + @ RAM then copy the pool data as well because IntrTable + @ address is stored here. Use intr_main_end as last address+1. +intr_main_end: + .endif + + .ALIGN + .POOL + + + .END + + diff --git a/lib/apex-audio-system/examples/AASExample2/lnkscript b/lib/apex-audio-system/examples/AASExample2/lnkscript new file mode 100644 index 0000000..30cb9c0 --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample2/lnkscript @@ -0,0 +1,297 @@ +/* Linker Script v1.3 by Jeff Frohwein */ +/* v1.0 - Original release */ +/* v1.1 - Added proper .data section support */ +/* v1.2 - Added support for c++ & iwram overlays */ +/* - Major contributions by Jason Wilkins. */ +/* v1.3 - .ewram section now can be used when */ +/* compiling for MULTIBOOT mode. This fixes */ +/* malloc() in DevKitAdvance which depends */ +/* on __eheap_start instead of end to define*/ +/* the starting location of heap space. */ +/* External global variable __gba_iwram_heap*/ +/* support added to allow labels end, _end, */ +/* & __end__ to point to end of iwram or */ +/* the end of ewram. */ + +/* This file is released into the public domain */ +/* for commercial or non-commercial use with no */ +/* restrictions placed upon it. */ + +/* NOTE!!!: This linker script defines the RAM & */ +/* ROM start addresses. In order for it to work */ +/* properly, remove -Ttext and -Tbss linker */ +/* options from your makefile if they are */ +/* present. */ + +/* You can use the following to view section */ +/* addresses in your .elf file: */ +/* objdump -h file.elf */ +/* Please note that empty sections may incorrectly*/ +/* list the lma address as the vma address for */ +/* some versions of objdump. */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +/* SEARCH_DIR(/bin/arm); */ + +/* By default this linker script will generate code */ +/* for flash carts located at 0x8000000. In order to */ +/* generate code that is compiled at 0x2000000 that */ +/* will run on flash carts or in multiboot mode then */ +/* you need to add the following variable to your main */ +/* project file. It's value is NOT important but */ +/* IT MUST BE A GLOBAL VARIABLE OR IT WILL NOT WORK: */ + +/* #define MULTIBOOT int __gba_multiboot; */ +/* Then use it like this: MULTIBOOT */ + +/* By default this linker script will set the labels */ +/* end, _end, & __end__ at the end of ewram. To force */ +/* them to be set to the end of iwram then you need to */ +/* add the following variable to your main */ +/* project file. It's value is NOT important but */ +/* IT MUST BE A GLOBAL VARIABLE OR IT WILL NOT WORK: */ + +/* #define IWRAMHEAP int __gba_iwram_heap; */ +/* Then use it like this: IWRAMHEAP */ + +/* The linker script function "var1 += var2;" sometimes */ +/* reports incorrect values in the *.map file but the */ +/* actual value it calculates is usually, if not always, */ +/* correct. If you leave out the ". = ALIGN(4);" at the */ +/* end of each section then the return value of SIZEOF() */ +/* is sometimes incorrect and "var1 += var2;" appears to */ +/* not work as well. "var1 += var2" style functions are */ +/* avoided below as a result. */ + +/* The linker script MEMORY directive is not used here due */ +/* to the fact that __text_start is not always a fixed value. */ + +__text_start = DEFINED (__gba_multiboot) ? 0x2000000 : 0x8000000; +/* __ewram_start = 0x2000000; */ /* Removed in v1.3 */ +__eheap_end = 0x2040000; +__iwram_start = 0x3000000; +__iheap_end = 0x3008000 - 0x400; +__sp_usr = 0x3008000 - 0x100; +__sp_irq = 0x3008000 - 0x60; +__intr_vector_buf = 0x3008000 - 4; +__sp_usr_offset = __sp_usr - __iwram_start; +__intr_vect_offset = __intr_vector_buf - __sp_usr; + +SECTIONS +{ + .text __text_start : /* ALIGN (4): */ + { + *(EXCLUDE_FILE (*text.iwram*) .text) + *(.text.*) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + *(.glue_7) + *(.glue_7t) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0xff +/* laddr = ADDR(.text) + SIZEOF(.text); */ + __text_end = .; + + .rodata : + { + *(.rodata) + *all.rodata*(*) + *(.roda) + *(.rodata.*) + *(.gnu.linkonce.r*) + SORT(CONSTRUCTORS) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0xff +/* laddr += SIZEOF(.rodata); */ + + .ctors : + { + /* gcc uses crtbegin.o to find the start of the constructors, so + we make sure it is first. Because this is a wildcard, it + doesn't matter if the user does not actually link against + crtbegin.o; the linker won't look for a file to match a + wildcard. The wildcard also means that it doesn't matter which + directory crtbegin.o is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0 +/* laddr += SIZEOF(.ctors); */ + laddr = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors); + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0 +/* laddr += SIZEOF(.dtors); */ + laddr = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors); + + .eh_frame : + { + KEEP (*(.eh_frame)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0 +/* laddr += SIZEOF(.eh_frame); */ + + .gcc_except_table : + { + *(.gcc_except_table) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0 +/* laddr += (SIZEOF(.gcc_except_table) + 3) & ~ 3; */ +/* __iwram_lma = laddr; */ + __iwram_lma = (ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors) + SIZEOF(.eh_frame) + SIZEOF(.gcc_except_table) + 3) & ~ 3; + + .iwram __iwram_start : AT (__iwram_lma) + { + __iwram_start = ABSOLUTE(.) ; + *(.iwram) + *iwram.*(.text) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0xff +/* laddr += SIZEOF(.iwram); */ +/* __data_lma = laddr; */ + __data_lma = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors) + SIZEOF(.eh_frame) + SIZEOF(.gcc_except_table) + SIZEOF(.iwram); + + __iwram_end = . ; + + .bss ALIGN(4) : + { + __bss_start = ABSOLUTE(.); + __bss_start__ = ABSOLUTE(.); + *(.dynbss) + *(.gnu.linkonce.b*) + *(COMMON) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } + + __bss_end = . ; + __bss_end__ = . ; + + .data ALIGN(4) : AT (__data_lma) + { + __data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + CONSTRUCTORS + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0xff +/* laddr += SIZEOF(.data); */ +/* __iwram_overlay_lma = laddr; */ + __iwram_overlay_lma = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors) + SIZEOF(.eh_frame) + SIZEOF(.gcc_except_table) + SIZEOF(.iwram) + SIZEOF(.data); + + __data_end = .; + PROVIDE (edata = .); +/* __data_lma = LOADADDR(.data); */ + __iwram_overlay_start = . ; + + OVERLAY : NOCROSSREFS AT (__iwram_overlay_lma) + { + .iwram0 { *(.iwram0) . = ALIGN(4);} + .iwram1 { *(.iwram1) . = ALIGN(4);} + .iwram2 { *(.iwram2) . = ALIGN(4);} + .iwram3 { *(.iwram3) . = ALIGN(4);} + .iwram4 { *(.iwram4) . = ALIGN(4);} + .iwram5 { *(.iwram5) . = ALIGN(4);} + .iwram6 { *(.iwram6) . = ALIGN(4);} + .iwram7 { *(.iwram7) . = ALIGN(4);} + .iwram8 { *(.iwram8) . = ALIGN(4);} + .iwram9 { *(.iwram9) . = ALIGN(4);} + } = 0xff +/* laddr += (SIZEOF(.iwram0)+SIZEOF(.iwram1)+SIZEOF(.iwram2)+SIZEOF(.iwram3)+SIZEOF(.iwram4)+SIZEOF(.iwram5)+SIZEOF(.iwram6)+SIZEOF(.iwram7)+SIZEOF(.iwram8)+SIZEOF(.iwram9)); */ +/* __ewram_lma = laddr; */ + __ewram_lma = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors) + SIZEOF(.eh_frame) + SIZEOF(.gcc_except_table) + SIZEOF(.iwram) + SIZEOF(.data) + SIZEOF(.iwram0)+SIZEOF(.iwram1)+SIZEOF(.iwram2)+SIZEOF(.iwram3)+SIZEOF(.iwram4)+SIZEOF(.iwram5)+SIZEOF(.iwram6)+SIZEOF(.iwram7)+SIZEOF(.iwram8)+SIZEOF(.iwram9); + +/* __iwram_overlay_lma = LOADADDR (.iwram0); */ + __iwram_overlay_end = . ; +/* _end = . ; */ +/* __end__ = . ; */ +/* PROVIDE (end = .); */ + __iheap_start = . ; + + /* v1.3 */ + __ewram_start = DEFINED (__gba_multiboot) ? __ewram_lma : 0x2000000; + + .ewram __ewram_start : AT (__ewram_lma) + { +/* __ewram_start = ABSOLUTE(.); */ + *(.ewram) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } = 0xff +/* laddr += SIZEOF(.ewram); */ +/* __ewram_overlay_lma = laddr; */ + __ewram_overlay_lma = ADDR(.text) + SIZEOF(.text) + SIZEOF(.rodata) + SIZEOF(.ctors) + SIZEOF(.dtors) + SIZEOF(.eh_frame) + SIZEOF(.gcc_except_table) + SIZEOF(.iwram) + SIZEOF(.data) + SIZEOF(.iwram0)+SIZEOF(.iwram1)+SIZEOF(.iwram2)+SIZEOF(.iwram3)+SIZEOF(.iwram4)+SIZEOF(.iwram5)+SIZEOF(.iwram6)+SIZEOF(.iwram7)+SIZEOF(.iwram8)+SIZEOF(.iwram9) + SIZEOF(.ewram); + +/* __ewram_lma = LOADADDR(.ewram); */ + __ewram_end = . ; + __ewram_overlay_start = . ; + + OVERLAY ALIGN(4): NOCROSSREFS AT (__ewram_overlay_lma) + { + .ewram0 { *(.ewram0) . = ALIGN(4);} + .ewram1 { *(.ewram1) . = ALIGN(4);} + .ewram2 { *(.ewram2) . = ALIGN(4);} + .ewram3 { *(.ewram3) . = ALIGN(4);} + .ewram4 { *(.ewram4) . = ALIGN(4);} + .ewram5 { *(.ewram5) . = ALIGN(4);} + .ewram6 { *(.ewram6) . = ALIGN(4);} + .ewram7 { *(.ewram7) . = ALIGN(4);} + .ewram8 { *(.ewram8) . = ALIGN(4);} + .ewram9 { *(.ewram9) . = ALIGN(4);} + } = 0xff + + __ewram_overlay_end = . ; + + __eheap_start = . ; + + _end = DEFINED (__gba_iwram_heap) ? __iheap_start : .; /* v1.3 */ + __end__ = _end ; /* v1.3 */ + PROVIDE (end = _end); /* v1.3 */ + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .stack 0x80000 : { _stack = .; *(.stack) } + /* These must appear regardless of . */ +} diff --git a/lib/apex-audio-system/examples/AASExample_c++/AASExample.cpp b/lib/apex-audio-system/examples/AASExample_c++/AASExample.cpp new file mode 100644 index 0000000..6fb841c --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample_c++/AASExample.cpp @@ -0,0 +1,69 @@ +// AAS C++ Example for projects with no other CPU intensive interrupts +// Notes: +// + crt0.s file included with the example should be set to use __FastInterrupts. +// + Can also be made to work with __SingleInterrupts and __MultipleInterrupts. +// + Use __AAS_MultipleInterrupts when there are other CPU intensive interrupts - see AASExample2. + +#include "AAS.h" +#include "AAS_Data.h" + +// Registers for interrupt handler +#define REG_IE (*(volatile AAS_u16 *)0x4000200) +#define REG_IF (*(volatile AAS_u16 *)0x4000202) + +extern "C" void InterruptProcess() +{ + AAS_u16 intr_bits = REG_IE & REG_IF; + + // It's best to test for AAS's Timer 1 interrupt first + if ( intr_bits & 0x10 ) // Timer 1 + AAS_Timer1InterruptHandler(); + + // Process other interrupts here by testing appropriate bits of "intr_bits" + + // Clear the interrupt flags + REG_IF |= REG_IF; +} + +// Registers for GBA keys +#define REG_KEY (*(volatile AAS_u16 *)0x04000130) +#define REG_KEY_A 0x0001 +#define REG_KEY_B 0x0002 + +extern "C" void AgbMain() +{ + 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 ); + + // Start playing MOD + AAS_MOD_Play( AAS_DATA_MOD_its_just_sonorous ); + + // 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 ); +} diff --git a/lib/apex-audio-system/examples/AASExample_c++/AAS_Data/Ambulance.wav b/lib/apex-audio-system/examples/AASExample_c++/AAS_Data/Ambulance.wav new file mode 100644 index 0000000..94d9d62 Binary files /dev/null and b/lib/apex-audio-system/examples/AASExample_c++/AAS_Data/Ambulance.wav differ diff --git a/lib/apex-audio-system/examples/AASExample_c++/AAS_Data/Boom.raw b/lib/apex-audio-system/examples/AASExample_c++/AAS_Data/Boom.raw new file mode 100644 index 0000000..7537624 Binary files /dev/null and b/lib/apex-audio-system/examples/AASExample_c++/AAS_Data/Boom.raw differ diff --git a/lib/apex-audio-system/examples/AASExample_c++/AAS_Data/its_just_sonorous.mod b/lib/apex-audio-system/examples/AASExample_c++/AAS_Data/its_just_sonorous.mod new file mode 100644 index 0000000..9dab797 Binary files /dev/null and b/lib/apex-audio-system/examples/AASExample_c++/AAS_Data/its_just_sonorous.mod differ diff --git a/lib/apex-audio-system/examples/AASExample_c++/Makefile b/lib/apex-audio-system/examples/AASExample_c++/Makefile new file mode 100644 index 0000000..d908cb1 --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample_c++/Makefile @@ -0,0 +1,8 @@ +# AAS Example Makefile +EXAMPLE_CPP_PREFIX ?= AASExamplePlusPlus +SHORTNAME = $(EXAMPLE_CPP_PREFIX) + +CROSS ?= arm-none-eabi- +LD = $(CROSS)g++ + +include ../../make/example.make diff --git a/lib/apex-audio-system/examples/AASExample_c++/crt0.s b/lib/apex-audio-system/examples/AASExample_c++/crt0.s new file mode 100644 index 0000000..a4a092b --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample_c++/crt0.s @@ -0,0 +1,781 @@ +@******************************************************************** +@* crt0.S v1.26 by Jeff Frohwein * +@******************************************************************** + +@ - Modified by James Daniels/Apex Designs to give AAS interrupts higher priority in special +@ "AAS_MultipleInterrupts" mode + +@ v1.0 - Original release +@ v1.1 - Added proper .data section support +@ v1.2 - Added support for c++, overlays, interrupts, and +@ far calls (__FarFunction & __FarProcedure). +@ - Some ideas from Jason Wilkins & Mike Heckenbach. +@ v1.21- Killed the dumb test bug left in the code. +@ v1.22- Killed dumb bug "numero dos" in multiple interrupts routine. Thanks Mike H. :) +@ v1.23- Now correctly handles zero length .bss section. +@ v1.24- Loop back to start_vector now works if main {} exits. +@ v1.25- __FarProcedure now works. It was missing a .thumb_func directive. +@ v1.26- Added missing Serial Interrupt processing to __MultipleInterrupts section. +@ Added __FastInterrupt option for minimal interrupt processing. +@ Optimized __MultipleInterrupts section to save 4 bytes of stack space. +@ Added __ISRinIWRAM option that puts interrupt processing in IWRAM by default. +@ Options passed to main() or AgbMain() are now set to 0. (Thanks to DarkFader) +@ +@ This file is released into the public domain for commercial +@ or non-commercial usage with no restrictions placed upon it. + + .TEXT + +@ Comment out the next line ONLY if you plan to never support +@ multiboot mode and want to save a few bytes by removing +@ multiboot support code. Otherwise, leave it alone. It wont +@ disturb code designed to run only on flash carts. +@ +@ The normal way to enable generating code that works with +@ both multiboot and flash carts is to add the following to +@ your C code in your main project file AS A GLOBAL VARIABLE: +@ +@ #define MULTIBOOT int __gba_multiboot; +@ Then use it like this : MULTIBOOT +@ +@ IT MUST BE A GLOBAL VARIABLE OR IT WILL NOT WORK! +@ If this variable is not defined somewhere in your project +@ then code will be generated to run out of ROM instead of +@ EXRAM. The value of this variable is not important. + + .equ __MultiBootInclude, 1 + +@ If you are compiling for multiboot dedicated (will not +@ run in a cart) code then uncomment the following. Normally +@ you should leave this commented out so that a multiboot +@ image will run in a cart as well (by copying from ROM to RAM). +@ +@ This sets the maker code to "MB " which is a key that +@ some emulators look for to know to load the rom image +@ at 0x2000000 instead of the standard 0x8000000. + +@ .equ __MultibootDedicated, 1 + +@ There are two methods for clearing memory and +@ copying appropriate setup data. The fast & bulky +@ method is GBA DMA copy/clear but some emulators +@ do not accurately do DMA. If you have an inaccurate +@ emulator or want to conserve ROM space then comment +@ out the following line. There is not much advantage +@ gained by doing DMA copy/clear. + +@ .equ __DMACopyClear, 1 + +@ Uncomment the following line to support C++ development. +@ You also need to name your main C function the following: +@ int main (void) ...instead of... int AgbMain (void) +@ Doing so will cause ~5500 bytes of c++ support code to be +@ linked in with your project so do not enable c++ support +@ unless you plan to use it. + +@ .equ __CPPSupport, 1 + +@ Comment out the following line to disable interrupt support +@ in your code and to save some space in this file. + + .equ __InterruptSupport, 1 + + +@ Comment out the following line to put interrupt support in +@ ROM instead of IWRAM. Interrupt support in ROM will slow +@ down interrupt execution and has no advantage other than +@ saving a little bit of IWRAM. + + .equ __ISRinIWRAM, 1 + +@ NOTE: Only ONE of the following 3 interrupt options may be +@ uncommented. Also, __InterruptSupport above must be uncommented +@ for any of the following to have an effect. +@ +@ __FastInterrupts +@ Uncomment this line for minimal interrupt processing. +@ +@ __SingleInterrupts +@ Uncomment this line if you wish to use a table of function +@ pointers to process specific interrupts. +@ +@ __MultipleInterrupts +@ Uncomment this line to allow multiple-interrupts-at-once +@ support. If you have several interrupts where one can +@ occur while another is being serviced then you need to +@ enable this option. +@ +@ __AAS_MultipleInterrupts +@ Uncomment this line to allow multiple-interrupts-at-once +@ support, giving the AAS interrupt higher priority. If +@ you have several interrupts where one can occur while +@ another is being serviced then you need to enable this +@ option. Only for use with AAS! Added by James Daniels. + +.equ __FastInterrupts, 1 +@ .equ __SingleInterrupts, 1 +@ .equ __MultipleInterrupts, 1 +@ .equ __AAS_MultipleInterrupts, 1 + + +@ Uncomment the following line to disable sound and enter an +@ infinite loop if cart is removed during game play. You +@ must have the cart interrupt enabled for this to work and +@ __ISRinIWRAM, above, must be enabled (not commented out.) + +@ .equ __HandleCartInterrupt, 1 + +@ The following prevents IRQ stack overflow by switching to +@ System mode (User stack) when handling multiple interrupts. +@ To force use of IRQ stack only, comment out the following line. + + .equ __SwitchToUserStack, 1 + +@ !!!! NOTE: THE COPY ROUTINES IN THIS FILE WORK ON 4 BYTE +@ BOUNDARIES. YOUR LINKER SCRIPT MUST ALIGN SECTION STARTS +@ AND SECTION ENDS FOR SECTIONS THAT GET COPIED TO RAM WITH +@ ALIGN(4) !!!! + + .GLOBAL _start +_start: + .ALIGN + .CODE 32 + @ Start Vector + + b rom_header_end + + @ Nintendo Logo Character Data (8000004h) + .fill 156,1,0 + + @ Game Title (80000A0h) + .ascii "AAS Example" + .byte 0x00 + + .ifdef __MultibootDedicated + @ Game Code (80000ACh) + .ascii "MB " + .else + @ Game Code (80000ACh) + .byte 0x00,0x00,0x00,0x00 + .endif + + @ Maker Code (80000B0h) + .byte 0x30,0x31 + + @ Fixed Value (80000B2h) + .byte 0x96 + + @ Main Unit Code (80000B3h) + .byte 0x00 + + @ Device Type (80000B4h) + .byte 0x00 + + @ Unused Data (7Byte) (80000B5h) + .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00 + + @ Software Version No (80000BCh) + .byte 0x00 + + @ Complement Check (80000BDh) + .byte 0xf0 + + @ Checksum (80000BEh) + .byte 0x00,0x00 + + .ALIGN + .ARM @ ..or you can use CODE 32 here + +rom_header_end: + b start_vector @ This branch must be here for proper + @ positioning of the following header. + @ DO NOT REMOVE IT. + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ The following reserved bytes are used if the code is compiled for @ +@ multiboot mode. It does not hurt anything to leave this header in +@ even if the code is not compiled for multiboot. The GBA BIOS will +@ auto-patch the first two bytes with 0x03 and 0x01, respectively, +@ before running any code if it is executed as multiboot. +@ + +@ The following two bytes are included even for non-multiboot supporting +@ builds to guarantee that any generic library code that depends on them +@ will still be functional. + + .GLOBAL __boot_method, __slave_number + +__boot_method: + .byte 0 @ boot method (0=ROM boot, 3=Multiplay boot) +__slave_number: + .byte 0 @ slave # (1=slave#1, 2=slave#2, 3=slave#3) + + .ifdef __MultiBootInclude + + .byte 0 @ reserved + .byte 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .word 0 @ reserved + .endif +@ @ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + +@@@@@@@@@@@@@@@@@@@@@@ +@ Reset @ +@@@@@@@@@@@@@@@@@@@@@@ + + .GLOBAL start_vector + .ALIGN + .ARM @ ..or you can use CODE 32 here +start_vector: + mov r0, #0x12 @ Switch to IRQ Mode + msr cpsr, r0 + ldr sp,=__sp_irq @ Set SP_irq + mov r0, #0x1f @ Switch to System Mode + msr cpsr, r0 + ldr sp,=__sp_usr @ Set SP_usr + +@ Enter Thumb mode + adr r0,1f + 1 @ add r0,pc,#1 also works here + @ for those that want to conserve labels. + bx r0 + + .THUMB @ ..or you can use .CODE 16 here +1: + + .ifdef __InterruptSupport + ldr r1, =__intr_vector_buf @ Set Interrupt Address + ldr r0, =intr_main + str r0, [r1] + .endif + + .ifdef __MultiBootInclude + +@ *** Multiboot Copy Routine *** +@ Check the Program Counter to see if code is running +@ at 0x2000000 or 0x8000000. If it is running at 0x8000000 +@ then copy 256K bytes of it to 0x2000000 and then branch +@ to 0x2000000. +@ The reason for all this is to allow a program to be used +@ "as is" with an flash cart/emulator or with an MBV2-style +@ multiboot cable. +@ NOTE: You can also detect if this ROM is running from +@ 0x2000000 by checking the multiboot header above. + + ldr r0,=__text_start + lsl r0,#5 @ Was code compiled at 0x08000000 or higher? + bcs DoEWRAMClear @ yes, you can not run it in external WRAM + +@ Make sure we're in ExWRAM + + mov r0,pc + lsl r0,#5 @ Are we running from ROM (0x8000000 or higher) ? + bcc SkipEWRAMClear @ No, so no need to do a copy. + +@ We were started in ROM, silly emulators. :P +@ So we need to copy to ExWRAM. + + mov r3,#0x40 + lsl r3,#12 @ r3 = 0x40000 + lsl r2,r3,#7 @ r2 = 0x2000000 + mov r6,r2 @ r6 = 0x2000000 + lsl r1,r2,#2 @ r1 = 0x8000000 + + bl CopyMem + +@ Jump to the code to execute + + bx r6 + .endif + +DoEWRAMClear: +@ Clear External WRAM to 0x00 + + mov r1,#0x40 + lsl r1,#12 @ r1 = 0x40000 + lsl r0,r1,#7 @ r0 = 0x2000000 + bl ClearMem + +SkipEWRAMClear: +@ ldr r0,=AgbMain +@ bx r0 + +@ Clear Internal WRAM to 0x00 + mov r0,#3 + lsl r0,#24 @ r0 = 0x3000000 + ldr r1,=__sp_usr_offset - 16 + bl ClearMem + + .ifdef __MultiBootInclude +@ Clear BSS section to 0x00 +@ (Sometimes BSS may be in External WRAM) + ldr r0,=__bss_start + ldr r1,=__bss_end + sub r1,r0 + bl ClearMem + .endif + +@ Copy initialized data (data section) from LMA to VMA (ROM to RAM) + ldr r1,=__data_lma + ldr r2,=__data_start + ldr r4,=__data_end + bl CopyMemChk + +@ Copy internal work ram (iwram section) from LMA to VMA (ROM to RAM) + ldr r1,=__iwram_lma + ldr r2,=__iwram_start + ldr r4,=__iwram_end + bl CopyMemChk + +@ Copy internal work ram overlay 0 (iwram0 section) from LMA to VMA (ROM to RAM) + ldr r2,=__load_stop_iwram0 + ldr r1,=__load_start_iwram0 + sub r3,r2,r1 @ Is there any data to copy? + beq CIW0Skip @ no + + ldr r2,=__iwram_overlay_start + bl CopyMem +CIW0Skip: + +@ Copy external work ram (ewram section) from LMA to VMA (ROM to RAM) + ldr r1,=__ewram_lma + ldr r2,=__ewram_start + ldr r4,=__ewram_end + bl CopyMemChk + +@ Copy external work ram overlay 0 (ewram0 section) from LMA to VMA (ROM to RAM) + ldr r2,=__load_stop_ewram0 + ldr r1,=__load_start_ewram0 + sub r3,r2,r1 @ Is there any data to copy? + beq CEW0Skip @ no + + ldr r2,=__ewram_overlay_start + bl CopyMem +CEW0Skip: + +@ Jump to user code + + mov r0,#0 @ int argc + mov r1,#0 @ char *argv[] + + ldr r3,=start_vector + mov lr,r3 @ Set start_vector as return address + +.ifdef __CPPSupport + ldr r3,=main +.else + ldr r3,=AgbMain +.endif + bx r3 + + + .GLOBAL __FarFunction,__FarProcedure + .THUMB_FUNC +__FarFunction: + .THUMB_FUNC +__FarProcedure: + bx r0 + nop + nop @ This nop is here to allow unmapped memory to be used as + @ as a delay of almost 1 sec with a 1 cycle resolution. + @ Read this for technical info: + @ http://www.devrs.com/gba/files/gbadevfaqs.php#RepeatUses + +@ Clear memory to 0x00 if length != 0 +@ r0 = Start Address +@ r1 = Length + +ClearMem: + cmp r1,#0 @ Is length zero? + beq ClearMX @ yes, exit + +.ifdef __DMACopyClear + ldr r2,reg_base + lsr r1,#2 @ r1 = (length/4) & 0xffff + + adr r3,fill_val + str r3,[r2,#0x4] @ Set source address (fill value) + str r0,[r2,#0x8] @ Set destination address (fill dest address) + strh r1,[r2,#0xc] @ Set DMA length + ldr r1,=0x8500 @ dma_clrb + strh r1,[r2,#0xe] @ Start DMA +.else + mov r2,#0 +ClrLoop: + stmia r0!,{r2} + sub r1,#4 + bne ClrLoop +.endif +ClearMX: + bx lr + +@ Copy memory if length != 0 +@ r1 = Source Address +@ r2 = Dest Address +@ r4 = Dest Address + Length + +CopyMemChk: + sub r3,r4,r2 @ Is there any data to copy? + beq CIDExit @ no + +@ Copy memory +@ r1 = Source Address +@ r2 = Dest Address +@ r3 = Length + +CopyMem: +.ifdef __DMACopyClear + ldr r0,reg_base + lsr r3,#2 @ r3 = (length/4) & 0xffff + + str r1,[r0,#0x4] @ Set source address + str r2,[r0,#0x8] @ Set destination address + strh r3,[r0,#0xc] @ Set DMA length + ldr r3,=0x8400 @ dma_copy + strh r3,[r0,#0xe] @ Start DMA +.else +CIDLoop: + ldmia r1!,{r0} + stmia r2!,{r0} + sub r3,#4 + bne CIDLoop +.endif +CIDExit: +If_Undefined_Reference__rename_main_or_AgbMain_to_each_other_in_your_C_file: + bx lr + + .ALIGN + +.ifdef __DMACopyClear +fill_val: .word 0 +reg_base: .word 0x040000d0 +.endif + + .ALIGN + .POOL + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ Interrupt Processing @ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + .ifdef __ISRinIWRAM + .SECTION .iwram + .endif + + .EXTERN IntrTable + .EXTERN InterruptProcess + .GLOBAL intr_main + .ALIGN + .ARM + +@ NOTE: Ifyou copy the following code (start: intr_main - +@ end: intr_main_end) to internal WRAM then do not forget +@ to copy everything between these two labels. The .POOL +@ data must be copied since it is used by intr_main. + +@ NOTE2: If __ISRinIWRAM is defined then the copy to +@ IWRAM is done automatically for you. + + .ifdef __InterruptSupport + + .ifdef __FastInterrupts +intr_main: + ldr r0,=InterruptProcess + bx r0 + .endif + + .ifdef __SingleInterrupts +intr_main: + @ Single interrupts support + mov r3, #0x4000000 @ REG_BASE + ldr r2, [r3,#0x200]! @ Read REG_IE + and r1, r2, r2, lsr #16 @ r1 = IE & IF + ldr r2, =IntrTable + + ands r0, r1, #1 @ V-Blank Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #2 @ H-Blank Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #4 @ V Counter Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #8 @ Timer 0 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x10 @ Timer 1 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x20 @ Timer 2 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x40 @ Timer 3 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x80 @ Serial Communication Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x100 @ DMA0 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x200 @ DMA1 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x400 @ DMA2 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x800 @ DMA3 Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x1000 @ Key Interrupt + bne jump_intr + add r2, r2, #4 + ands r0, r1, #0x2000 @ Cart Interrupt + + .ifdef __HandleCartInterrupt + strneb r0, [r3, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X) +loop: bne loop @ Infinite loop if cart removed + .endif + +jump_intr: + strh r0, [r3, #2] @ IF Clear + ldr r0, [r2] @ Jump to user IRQ process + bx r0 + .endif + + .ifdef __MultipleInterrupts +intr_main: + @ Multiple interrupts support + mov r2, #0x4000000 @ REG_BASE + ldr r3, [r2,#0x200]! @ r2 = IE : r3 = IF|IE + ldrh r1, [r2, #0x8] @ r1 = IME + mrs r0, spsr + stmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} // IF|IE + + mov r0, #1 @ IME = 1 (To permit multiple interrupts if + @ an interrupt occurs) + strh r0, [r2, #0x8] + and r1, r3, r3, lsr #16 @ r1 = IE & IF + ldr r12, =IntrTable + + ands r0, r1, #1 @ V-blank interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #2 @ H-blank interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #4 @ V-counter interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #8 @ Timer 0 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x10 @ Timer 1 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x20 @ Timer 2 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x40 @ Timer 3 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x80 @ Serial Communication Interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x100 @ DMA 0 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x200 @ DMA 1 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x400 @ DMA 2 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x800 @ DMA 3 interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x1000 @ Key interrupt + bne jump_intr + add r12,r12, #4 + ands r0, r1, #0x2000 @ Cart interrupt + + .ifdef __HandleCartInterrupt + strneb r0, [r2, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X) +loop: bne loop @ Infinite loop if cart removed + .endif + +jump_intr: + strh r0, [r2, #2] @ Clear IF + +@ Enable multiple interrupts & switch to system +@ mode if __SwitchToUserStack is defined. + + mrs r3, cpsr + .ifdef __SwitchToUserStack + bic r3, r3, #0xdf @ \__ + orr r3, r3, #0x1f @ / --> Enable IRQ & FIQ. Set CPU mode to System. + .else + bic r3, r3, #0xc0 @ Enable IRQ & FIQ + .endif + msr cpsr, r3 + + ldr r0, [r12] + + stmfd sp!, {lr} + adr lr, IntrRet + bx r0 +IntrRet: + ldmfd sp!, {lr} + +@ Disable multiple interrupts & switch to IRQ Mode +@ if __SwitchToUserStack is defined. + + mrs r3, cpsr + .ifdef __SwitchToUserStack + bic r3, r3, #0xdf @ \__ + orr r3, r3, #0x92 @ / --> Disable IRQ. Enable FIQ. Set CPU mode to IRQ. + .else + orr r3, r3, #0x80 @ Disable IRQ. + .endif + msr cpsr, r3 + + ldmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} //IF|IE +@ strh r3, [r2] @ set IE + strh r1, [r2, #0x8] @ restore REG_IME + msr spsr, r0 @ restore spsr + bx lr + + .endif + + .ifdef __AAS_MultipleInterrupts +intr_main: + @ Multiple interrupts support + mov r2, #0x4000000 @ REG_BASE + ldr r3, [r2,#0x200]! @ r2 = IE : r3 = IF|IE + ldrh r1, [r2, #0x8] @ r1 = IME + mrs r0, spsr + stmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} // IF|IE + + and r1, r3, r3, lsr #16 @ r1 = IE & IF + + ands r0, r1, #0x10 @ Timer 1 interrupt + bne jump_intr_AAS + + mov r0, #1 @ IME = 1 (To permit multiple interrupts if + @ an interrupt occurs) + strh r0, [r2, #0x8] + +AAS_intr_start: + ands r0, r1, #1 @ V-blank interrupt + blne jump_intr + ands r0, r1, #2 @ H-blank interrupt + blne jump_intr + ands r0, r1, #4 @ V-counter interrupt + blne jump_intr + ands r0, r1, #8 @ Timer 0 interrupt + blne jump_intr + ands r0, r1, #0x20 @ Timer 2 interrupt + blne jump_intr + ands r0, r1, #0x40 @ Timer 3 interrupt + blne jump_intr + ands r0, r1, #0x80 @ Serial Communication Interrupt + blne jump_intr + ands r0, r1, #0x100 @ DMA 0 interrupt + blne jump_intr + ands r0, r1, #0x200 @ DMA 1 interrupt + blne jump_intr + ands r0, r1, #0x400 @ DMA 2 interrupt + blne jump_intr + ands r0, r1, #0x800 @ DMA 3 interrupt + blne jump_intr + ands r0, r1, #0x1000 @ Key interrupt + blne jump_intr + ands r0, r1, #0x2000 @ Cart interrupt + + .ifdef __HandleCartInterrupt + strneb r0, [r2, #0x84 - 0x200] @ Stop sound if cart removed (REG_SOUNDCNT_X) +loop: bne loop @ Infinite loop if cart removed + .endif + +jump_intr: + strh r0, [r2, #2] @ Clear IF + +@ Enable multiple interrupts & switch to system +@ mode if __SwitchToUserStack is defined. + + ldr r12, =AAS_IntrTable + adr r0, AAS_intr_start+8 + sub r14, r14, r0 + mov r14, r14, lsr #3 + ldr r0, [r12, r14, lsl #2] + + mrs r3, cpsr + bic r3, r3, #0xc0 @ Enable IRQ & FIQ + .ifdef __SwitchToUserStack + orr r3, r3, #0x1f @ Set CPU mode to System. + .endif + msr cpsr, r3 + + stmfd sp!, {lr} + adr lr, IntrRet + bx r0 + +IntrRet: + ldmfd sp!, {lr} + +@ Disable multiple interrupts & switch to IRQ Mode +@ if __SwitchToUserStack is defined. + + mrs r3, cpsr + .ifdef __SwitchToUserStack + bic r3, r3, #0xdf @ \__ + orr r3, r3, #0x92 @ / --> Disable IRQ. Enable FIQ. Set CPU mode to IRQ. + .else + orr r3, r3, #0x80 @ Disable IRQ. + .endif + msr cpsr, r3 + + ldmfd sp!, {r0-r2,lr} @ {spsr, IME, REG_IE, lr} //IF|IE + strh r1, [r2, #0x8] @ restore REG_IME + msr spsr, r0 @ restore spsr + bx lr + +jump_intr_AAS: + strh r0, [r2, #2] @ Clear IF + +@ Switch to system mode if __SwitchToUserStack is defined. + + .ifdef __SwitchToUserStack + mrs r3, cpsr + orr r3, r3, #0x1f @ Set CPU mode to System. + msr cpsr, r3 + .endif + + ldr r0, =AAS_FastTimer1InterruptHandler + + stmfd sp!, {lr} + adr lr, IntrRet + bx r0 + + .endif + + .ALIGN + .POOL @ If you copy the intr_main routine, above, to internal + @ RAM then copy the pool data as well because IntrTable + @ address is stored here. Use intr_main_end as last address+1. +intr_main_end: + .endif + + .ALIGN + .POOL + + + .END + + diff --git a/lib/apex-audio-system/examples/AASExample_c++/lnkscript b/lib/apex-audio-system/examples/AASExample_c++/lnkscript new file mode 100644 index 0000000..b35df8a --- /dev/null +++ b/lib/apex-audio-system/examples/AASExample_c++/lnkscript @@ -0,0 +1,462 @@ +/*****************************************************************************\ + DevKit Advance Linker Script +\*****************************************************************************/ + +/* Administrivia: + * + * Copyright 2003, Jason Wilkins. This source code is free for any use except + * that this copyright notice and the following disclaimers remain intact when + * the source is distributed. There are absolutely no restrictions on use of + * object code generated from this source, but the disclaimers remain in force. + * + * THIS CODE WAS NOT MADE IN ASSOCIATION WITH NINTENDO AND DOES NOT MAKE USE OF + * ANY INTELLECTUAL PROPERTY CLAIMED BY NINTENDO. + * + * GAMEBOY ADVANCE IS A TRADEMARK OF NINTENDO. + * + * THIS CODE HAS BEEN PROVIDED "AS-IS" WITHOUT A WARRANTY OF ANY KIND, EITHER + * EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO IMPLIED WARRANTIES OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. THE ENTIRE RISK AS TO THE + * QUALITY OR PERFORMANCE OF THE CODE IS WITH YOU. + * + * IN NO EVENT, UNLESS AGREED TO IN WRITING, WILL ANY COPYRIGHT HOLDER, OR ANY + * OTHER PARTY, BE HELD LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OR + * INABILITY TO USE THIS CODE. + * + * See $(DEVKITADV)/docs/Credits.txt for a list of contributors. + *****************************************************************************/ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +ENTRY(_start) + +SEARCH_DIR("/devkitadv-r5-beta-3/arm-agb-elf/lib"); + + + +__memmap_ewram_start = 0x02000000; +__memmap_ewram_end = 0x02040000; + +__memmap_iwram_start = 0x03000000; +__memmap_iwram_end = 0x03008000; + +__memmap_rom_start = 0x08000000; + + +/* Added */ +__text_start = DEFINED (__gba_multiboot) ? __memmap_ewram_start : __memmap_rom_start; +/* __ewram_start = __memmap_ewram_start; */ +/* __eheap_end = __memmap_ewram_end; */ +__iwram_start = __memmap_iwram_start; +__iheap_end = __memmap_iwram_end - 0x400; +__sp_usr = __memmap_iwram_end - 0x100; +__sp_irq = __memmap_iwram_end - 0x60; +__intr_vector_buf = __memmap_iwram_end - 4; +__sp_usr_offset = __sp_usr - __iwram_start; +__intr_vect_offset = __intr_vector_buf - __sp_usr; + + +SECTIONS +{ +/*** read-only sections ***/ + + . = DEFINED(__gba_multiboot) ? __memmap_ewram_start : __memmap_rom_start ; + + .text : + { + /* crt0.o has to be the first thing in the ROM */ + *crt0.o(.text) + + *(EXCLUDE_FILE(*.rodata.* *.cartrom.o *.ewram.o *.iwram.o) .text) + *(.stub .text.* .gnu.linkonce.t*) + + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + + *(.glue_7) + *(.glue_7t) + + . = ALIGN(4); + } =0xFF + + .init : + { + *(.init) + . = ALIGN(4); + } =0xFF + + .fini : + { + *(.fini) + . = ALIGN(4); + } =0xFF + + __cartrom_start = . ; + .cartrom : + { + *(.cartrom .cartrom.*) + *.rodata.* (.text .rodata .data) /* deprecated: R4 */ + *.cartrom.o (.text .rodata .data) + + . = ALIGN(4); + } =0xFF + __cartrom_end = . ; + + __rodata_start = . ; + .rodata : + { + *(.rodata1) + *(EXCLUDE_FILE(*.rodata.* *.cartrom.o *.ewram.o *.iwram.o) .rodata) + *(.rodata.* .gnu.linkonce.r*) + *(.roda) /* deprecated: for compatibility with objcopyroda */ + + SORT(CONSTRUCTORS) + + . = ALIGN(4); + } =0xFF + __rodata_end = . ; + + .eh_frame : + { + KEEP(*(.eh_frame)) + . = ALIGN(4); + } =0xFF + + .gcc_except_table : + { + *(.gcc_except_table) + . = ALIGN(4); + } =0xFF + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP(*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP(*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + + . = ALIGN(4); + } =0xFF + + .dtors : + { + KEEP(*crtbegin.o(.dtors)) + KEEP(*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + + . = ALIGN(4); + } =0xFF + + .jcr : + { + *(.jcr) + . = ALIGN(4); + } =0xFF + + + +/*** EWRAM ***/ + + __load_start_ewram = + ADDR(.text) + + SIZEOF(.text) + + SIZEOF(.init) + + SIZEOF(.fini) + + SIZEOF(.cartrom) + + SIZEOF(.rodata) + + SIZEOF(.eh_frame) + + SIZEOF(.gcc_except_table) + + SIZEOF(.ctors) + + SIZEOF(.dtors) + + SIZEOF(.jcr); + + . = DEFINED(__gba_multiboot) ? __load_start_ewram : __memmap_ewram_start ; + + __ewram_start = . ; + .ewram : AT(__load_start_ewram) + { + *(.ewram .ewram.*) + *.ewram.o (.text .rodata .data) + . = ALIGN(4); + } =0xFF + __ewram_end = . ; + + __ewram_overlay_start = . ; + OVERLAY : NOCROSSREFS AT (__load_start_ewram + SIZEOF(.ewram)) + { + .ewram0 { *(.ewram0 .ewram0.*) . = ALIGN(4); } =0xFF + .ewram1 { *(.ewram1 .ewram1.*) . = ALIGN(4); } =0xFF + .ewram2 { *(.ewram2 .ewram2.*) . = ALIGN(4); } =0xFF + .ewram3 { *(.ewram3 .ewram3.*) . = ALIGN(4); } =0xFF + .ewram4 { *(.ewram4 .ewram4.*) . = ALIGN(4); } =0xFF + .ewram5 { *(.ewram5 .ewram5.*) . = ALIGN(4); } =0xFF + .ewram6 { *(.ewram6 .ewram6.*) . = ALIGN(4); } =0xFF + .ewram7 { *(.ewram7 .ewram7.*) . = ALIGN(4); } =0xFF + .ewram8 { *(.ewram8 .ewram8.*) . = ALIGN(4); } =0xFF + .ewram9 { *(.ewram9 .ewram9.*) . = ALIGN(4); } =0xFF + } + + /* OVERLAY should do this, but it doesn't seem to work. */ + . = __ewram_start + SIZEOF(.ewram) + + MAX(SIZEOF(.ewram0), + MAX(SIZEOF(.ewram1), + MAX(SIZEOF(.ewram2), + MAX(SIZEOF(.ewram3), + MAX(SIZEOF(.ewram4), + MAX(SIZEOF(.ewram5), + MAX(SIZEOF(.ewram6), + MAX(SIZEOF(.ewram7), + MAX(SIZEOF(.ewram8), SIZEOF(.ewram9)))))))))); + + __ewram_overlay_end = . ; + + __load_stop_ewram = + __load_start_ewram + + SIZEOF(.ewram) + + SIZEOF(.ewram0) + + SIZEOF(.ewram1) + + SIZEOF(.ewram2) + + SIZEOF(.ewram3) + + SIZEOF(.ewram4) + + SIZEOF(.ewram5) + + SIZEOF(.ewram6) + + SIZEOF(.ewram7) + + SIZEOF(.ewram8) + + SIZEOF(.ewram9); + + + +/* data */ + + . = DEFINED(__gba_ewram_data) ? __ewram_overlay_end : __memmap_iwram_start ; + + __load_start_data = __load_stop_ewram; + + __data_start = . ; + .data : AT(__load_start_data) + { + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(EXCLUDE_FILE(*.rodata.* *.cartrom.o *.ewram.o *.iwram.o) .data) + *(.data.* .gnu.linkonce.d.*) + *(.data1) + *(.tdata .tdata.* .gnu.linkonce.td.*) + *(.sdata .sdata.* .gnu.linkonce.s.*) + + . = ALIGN(4); + } =0xFF + __data_end = . ; + + __load_stop_data = __load_start_data + SIZEOF(.data); + + + +/*** IWRAM ***/ + + . = DEFINED(__gba_ewram_data) ? __memmap_iwram_start : __data_end ; + + __load_start_iwram = __load_stop_data; + + __iwram_start = . ; + .iwram : AT(__load_start_iwram) + { + *(.iwram .iwram.*) + *.iwram.o (.text .rodata .data) + . = ALIGN(4); + } =0xFF + __iwram_end = . ; + + __iwram_overlay_start = . ; + OVERLAY : NOCROSSREFS AT (__load_start_iwram + SIZEOF(.iwram)) + { + .iwram0 { *(.iwram0 .iwram0.*) . = ALIGN(4); } =0xFF + .iwram1 { *(.iwram1 .iwram1.*) . = ALIGN(4); } =0xFF + .iwram2 { *(.iwram2 .iwram2.*) . = ALIGN(4); } =0xFF + .iwram3 { *(.iwram3 .iwram3.*) . = ALIGN(4); } =0xFF + .iwram4 { *(.iwram4 .iwram4.*) . = ALIGN(4); } =0xFF + .iwram5 { *(.iwram5 .iwram5.*) . = ALIGN(4); } =0xFF + .iwram6 { *(.iwram6 .iwram6.*) . = ALIGN(4); } =0xFF + .iwram7 { *(.iwram7 .iwram7.*) . = ALIGN(4); } =0xFF + .iwram8 { *(.iwram8 .iwram8.*) . = ALIGN(4); } =0xFF + .iwram9 { *(.iwram9 .iwram9.*) . = ALIGN(4); } =0xFF + } + + /* OVERLAY should do this, but it doesn't seem to work. */ + . = __iwram_start + SIZEOF(.iwram) + + MAX(SIZEOF(.iwram0), + MAX(SIZEOF(.iwram1), + MAX(SIZEOF(.iwram2), + MAX(SIZEOF(.iwram3), + MAX(SIZEOF(.iwram4), + MAX(SIZEOF(.iwram5), + MAX(SIZEOF(.iwram6), + MAX(SIZEOF(.iwram7), + MAX(SIZEOF(.iwram8), SIZEOF(.iwram9)))))))))); + + __iwram_overlay_end = . ; + + __load_stop_iwram = + __load_start_iwram + + SIZEOF(.iwram) + + SIZEOF(.iwram0) + + SIZEOF(.iwram1) + + SIZEOF(.iwram2) + + SIZEOF(.iwram3) + + SIZEOF(.iwram4) + + SIZEOF(.iwram5) + + SIZEOF(.iwram6) + + SIZEOF(.iwram7) + + SIZEOF(.iwram8) + + SIZEOF(.iwram9); + + + +/*** footer ***/ + + . = __load_stop_iwram; + + __load_start_footer = . ; + .footer : + { + *crt0.o(.footer) + *(.footer) + . = ALIGN(4); + } + __load_stop_footer = . ; + + + +/*** bss ***/ + + . = DEFINED(__gba_ewram_data) ? (DEFINED(__gba_multiboot) ? __load_stop_footer : __data_end) : __iwram_overlay_end ; + . = ALIGN(32); + + PROVIDE(__bss_start__ = . ); + __bss_start = . ; + .bss : + { + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + + *(.bss .bss.* .gnu.linkonce.b*) + *(COMMON) + + . = ALIGN(4); + } + __bss_end = . ; + PROVIDE(_bss_end__ = . ); + PROVIDE(__bss_end__ = . ); + + + +/*** appended assets ***/ + + . = DEFINED(__gba_ewram_data) ? (DEFINED(__gba_multiboot) ? __bss_end : __load_stop_footer ) : __load_stop_footer ; + + __load_start_appended = __load_stop_footer ; + + __appended_start = . ; + .appended : AT(__load_start_appended) + { + *(.appended .appended.*) + . = ALIGN(4); + } + __appended_end = . ; + + __load_stop_appended = __load_start_appended + SIZEOF(.appended); + + + +/*** heap ***/ + + __iwram_break = DEFINED(__gba_ewram_data) ? __iwram_overlay_end : __bss_end ; + + __ewram_break = DEFINED(__gba_multiboot) ? __appended_end : (DEFINED(__gba_ewram_data) ? __bss_end : __ewram_overlay_end ) ; + + _end = DEFINED(__gba_iwram_heap) ? __iwram_break : __ewram_break ; + PROVIDE(__end__ = _end); + PROVIDE(end = _end); + + __heap_limit = DEFINED(__gba_iwram_heap) ? __memmap_iwram_end - 0x100 : __memmap_ewram_end ; + + +/* Added */ + __iwram_lma = __load_start_iwram; + __data_lma = __load_start_data; + __ewram_lma = __load_start_ewram; + + +/* discard configuration variables */ + + /DISCARD/ : + { + *(.devkitadv.config) + } + + + +/*** debugging info ***/ + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + + .comment 0 : { *(.comment) } + + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} + + + diff --git a/lib/apex-audio-system/make/common.make b/lib/apex-audio-system/make/common.make new file mode 100644 index 0000000..ef6dff8 --- /dev/null +++ b/lib/apex-audio-system/make/common.make @@ -0,0 +1,75 @@ +# Tools and flags. +CC = $(CROSS)gcc +CCPP = $(CROSS)g++ +CFLAGS = -mthumb-interwork -fomit-frame-pointer -mcpu=arm7tdmi -ffast-math -fno-exceptions +# added "-ffixed-r14" and "-mlong-calls" below to work around compiler bugs +THUMB = -mthumb -O3 -ffixed-r14 -funroll-loops +ARM = -marm -Os -mlong-calls +DEFAULT = $(THUMB) +# DEFAULT was $(THUMB) + +AS = $(CROSS)as +ASFLAGS = -mthumb-interwork + +# Graphics related raw input files (e.g. sprites, palettes). +GFX = + +# Sound related o input files. +SOUND = + +# This rule builds a .h file of all your raw input file exports. +# So this creates a file (say) 'symbol.h' which has lines like (say): +# extern const u8 _binary_bob_raw_start[]; +SYMBOLS = symbols.h +SYMBOL_PREFIX = "extern const u8 _binary_" +SYMBOL_SUFFIX1 = "_start[];" +SYMBOL_SUFFIX2 = "_end[];" + + + +# Here follow the generic build rules. +all: $(TARGET) + +# Rule to build raw files into .o files, noting their exported symbols. +%.o: %.raw + @$(CROSS)objcopy -B arm -I binary -O elf32-little $< temp.o 2> /dev/null + @$(CROSS)ld -T convert.ls temp.o -o $@ + @interflip -mthumb-interwork $@ + @echo $(CROSS)objcopy -I binary -O elf32-little $< $@ + @echo -n $(SYMBOL_PREFIX) >> $(SYMBOLS) + @echo -n "$<" | tr "[:punct:]" "_" >> $(SYMBOLS) + @echo $(SYMBOL_SUFFIX1) >> $(SYMBOLS) + @echo -n $(SYMBOL_PREFIX) >> $(SYMBOLS) + @echo -n "$<" | tr "[:punct:]" "_" >> $(SYMBOLS) + @echo $(SYMBOL_SUFFIX2) >> $(SYMBOLS) + +release: + make clean all + rm -f *.o $(NAME) $(GFX) $(SOUND) $(SYMBOLS) $(MAP) + +crt0.o: crt0.s + $(AS) -o $@ $< + +%.o: %.s + $(AS) $(ASFLAGS) -o $@ $< + +%.o: %.thumb.c + $(CC) $(THUMB) $(INCLUDES) $(CFLAGS) -c $< -o $@ + +%.o: %.arm.c + $(CC) $(ARM) $(INCLUDES) $(CFLAGS) -c $< -o $@ + +%.o: %.c + $(CC) $(DEFAULT) $(INCLUDES) $(CFLAGS) -c $< -o $@ + +%.o: %.thumb.cpp + $(CCPP) $(THUMB) $(INCLUDES) $(CFLAGS) -c $< -o $@ + +%.o: %.arm.cpp + $(CCPP) $(ARM) $(INCLUDES) $(CFLAGS) -c $< -o $@ + +%.o: %.cpp + $(CCPP) $(DEFAULT) $(INCLUDES) $(CFLAGS) -c $< -o $@ + +%.text.iwram.o: %.o + cp $< $@ diff --git a/lib/apex-audio-system/make/example.make b/lib/apex-audio-system/make/example.make new file mode 100644 index 0000000..4a5513a --- /dev/null +++ b/lib/apex-audio-system/make/example.make @@ -0,0 +1,39 @@ +# Library and include paths. +LIBS = -L../../build/aas/lib -lAAS +INCLUDES = -I../../build/aas/include + +# Files you want to go in ROM (AAS_Data.o must go first) +SRC = AAS_Data.o AASExample.o + +MAP = map.out +LDFLAGS = -mthumb-interwork -Xlinker -Map $(MAP) -nostartfiles -Tlnkscript + +# Name of output targets. +NAME = $(SHORTNAME).tmp +TARGET = $(SHORTNAME).gba + +# Files you want to go in IWRAM. +IWRAM = + +include ../../make/common.make + +CONV2AAS_FILE = conv2aas +ifeq ($(OS),Windows_NT) + CONV2AAS_FILE = conv2aas.exe +endif + +AAS_Data.o: + ../../build/conv2aas/$(CONV2AAS_FILE) AAS_Data + $(AS) $(ASFLAGS) -o $@ AAS_Data.s + +$(NAME): crt0.o $(IWRAM) $(GFX) $(SOUND) $(SRC) + touch $(MAP) + $(LD) $(LDFLAGS) -o $@ crt0.o $(SRC) $(IWRAM) $(GFX) $(SOUND) $(LIBS) + $(CROSS)size $@ + +$(TARGET): $(NAME) + $(CROSS)objcopy -v -O binary $< $@ + gbafix $@ + +clean: + rm -f *.o AAS_Data.h AAS_Data.s $(TARGET) $(NAME) $(GFX) $(SOUND) $(SYMBOLS) $(MAP) diff --git a/lib/apex-audio-system/src/aas/AAS.h b/lib/apex-audio-system/src/aas/AAS.h new file mode 100644 index 0000000..300aae4 --- /dev/null +++ b/lib/apex-audio-system/src/aas/AAS.h @@ -0,0 +1,121 @@ +// Copyright (c) 2003-2021 James Daniels +// Distributed under the MIT License +// license terms: see LICENSE file in root or http://opensource.org/licenses/MIT + +// Main AAS include +// +// See API documentation for more information. + +#ifndef __AAS__ +#define __AAS__ + +#ifdef __cplusplus +#define AAS_BEGIN_DECLS extern "C" { +#define AAS_END_DECLS } +#else +#define AAS_BEGIN_DECLS +#define AAS_END_DECLS +#endif + +AAS_BEGIN_DECLS + +#define AAS_VERSION 0x111 // v1.11 + +// Types +#define AAS_u32 unsigned int +#define AAS_s32 signed int +#define AAS_u16 unsigned short +#define AAS_s16 signed short +#define AAS_u8 unsigned char +#define AAS_s8 signed char +#define AAS_BOOL unsigned char +#define AAS_TRUE 1 +#define AAS_FALSE 0 +#define AAS_NULL 0 + +// Return values +#define AAS_OK 0 +#define AAS_ERROR_VOLUME_OUT_OF_RANGE -1 +#define AAS_ERROR_CHANNEL_NOT_AVAILABLE -2 +#define AAS_ERROR_FREQUENCY_OUT_OF_RANGE -3 +#define AAS_ERROR_MOD_DOES_NOT_EXIST -4 +#define AAS_ERROR_CALL_SET_CONFIG_FIRST -5 +#define AAS_ERROR_INVALID_CONFIG -6 +#define AAS_ERROR_INVALID_SAMPLE_ADDRESS -7 +#define AAS_ERROR_NO_MOD_PLAYING -8 +#define AAS_ERROR_NOT_ENOUGH_CHANNELS -9 +#define AAS_ERROR_CHANNEL_ACTIVE -10 +#define AAS_ERROR_CHANNEL_UNRESUMEABLE -11 +#define AAS_ERROR_INVALID_SONG_POS -12 + +// AAS_SetConfig() mix settings +#define AAS_CONFIG_MIX_32KHZ 1 +#define AAS_CONFIG_MIX_28KHZ 2 +#define AAS_CONFIG_MIX_24KHZ 3 +#define AAS_CONFIG_MIX_20KHZ 4 +#define AAS_CONFIG_MIX_16KHZ 5 +#define AAS_CONFIG_MIX_12KHZ 6 +#define AAS_CONFIG_MIX_8KHZ 7 + +// AAS_SetConfig() channel settings +#define AAS_CONFIG_CHANS_16_LOUD 6 +#define AAS_CONFIG_CHANS_8_LOUD 5 +#define AAS_CONFIG_CHANS_4_LOUD 4 +#define AAS_CONFIG_CHANS_16 3 +#define AAS_CONFIG_CHANS_8 2 +#define AAS_CONFIG_CHANS_4 1 + +// AAS_SetConfig() spatial settings +#define AAS_CONFIG_SPATIAL_STEREO 2 +#define AAS_CONFIG_SPATIAL_MONO 1 + +// AAS_SetConfig() dynamic mixing settings +#define AAS_CONFIG_DYNAMIC_OFF 0 +#define AAS_CONFIG_DYNAMIC_ON 1 + +// General commands +int AAS_SetConfig( int config_mix, int config_chans, int config_spatial, int config_dynamic ); // Must call at least once before doing anything else +void AAS_DoDMA3( void* source, void* dest, AAS_u32 flags_and_length ); +void AAS_ShowLogo(); + +// Interrupt handling commands +void AAS_Timer1InterruptHandler(); // Use when there are no other CPU-intensive interrupts +void AAS_FastTimer1InterruptHandler(); // Use when there are other CPU-intensive interrupts +void AAS_DoWork(); // Must be called at least 50 times/sec if using AAS_FastTimer1InterruptHandler() + +// Sample playing commands +int AAS_SFX_Play( int channel, int sample_volume, int sample_frequency, const AAS_s8* sample_start, const AAS_s8* sample_end, const AAS_s8* sample_restart ); +AAS_BOOL AAS_SFX_ChannelExists( int channel ); // returns AAS_TRUE only if AAS_SFX_Play will succeed for this channel +AAS_BOOL AAS_SFX_IsActive( int channel ); // returns AAS_TRUE if channel is valid and active, AAS_FALSE otherwise +int AAS_SFX_EndLoop( int channel ); // If sample was looping, will stop at end of current iteration +int AAS_SFX_SetFrequency( int channel, int sample_frequency ); +int AAS_SFX_SetVolume( int channel, int sample_volume ); +int AAS_SFX_Stop( int channel ); +int AAS_SFX_Resume( int channel ); +int AAS_SFX_GetNumChannels(); // returns number of SFX channels + +// MOD commands +int AAS_MOD_Play( int song_num ); // loops by default +int AAS_MOD_SetLoop( AAS_BOOL loop ); // specify whether current song will loop +void AAS_MOD_Stop(); +AAS_BOOL AAS_MOD_IsPlaying(); // is a song playing? +AAS_BOOL AAS_MOD_HasLooped(); // has the current song looped? +int AAS_MOD_GetVolume(); // 0: silent, 256 = max +int AAS_MOD_SetVolume( int vol ); // 0: silent, 256 = max (do not set above 256 or below 0!) +int AAS_MOD_GetSongPos(); +int AAS_MOD_SetSongPos( int song_pos ); // Immediately jumps to the specified song position. +int AAS_MOD_QueueSongPos( int song_pos ); // Jumps to the specified song position when the current pattern finishes. +int AAS_MOD_GetLineNum(); +int AAS_MOD_GetLastFilterValue(); // Returns the value specified by the most recent "E0: Set Filter" effect +void AAS_MOD_Pause(); // Stops the MOD in a way that allows it to be safely resumed +void AAS_MOD_Resume(); // Should only be used after AAS_MOD_Pause() +int AAS_MOD_GetNumChannels(); // Returns number of channels currently being reserved by the MOD + +// Misc commands +const AAS_s8* AAS_GetOutputBufferAddress( int buffer ); // buffer should be 0 or 1, otherwise will return AAS_NULL +int AAS_GetOutputBufferLength(); +int AAS_GetActualMixRate(); + +AAS_END_DECLS + +#endif diff --git a/lib/apex-audio-system/src/aas/AAS_ASM.s b/lib/apex-audio-system/src/aas/AAS_ASM.s new file mode 100644 index 0000000..bf99d4a --- /dev/null +++ b/lib/apex-audio-system/src/aas/AAS_ASM.s @@ -0,0 +1,299 @@ +@ Copyright (c) 2003-2021 James Daniels +@ Distributed under the MIT License +@ license terms: see LICENSE file in root or http://opensource.org/licenses/MIT + +.TEXT +.SECTION .text,"ax",%progbits +.ALIGN +.ARM + +.GLOBAL AAS_DoDMA3 + +.GLOBAL AAS_MixAudio_SetMode_Normal +.GLOBAL AAS_MixAudio_SetMode_Boost +.GLOBAL AAS_MixAudio_SetMode_BoostAndClip + +.GLOBAL AAS_MixAudio_SetMaxChans_2 +.GLOBAL AAS_MixAudio_SetMaxChans_4 +.GLOBAL AAS_MixAudio_SetMaxChans_8 + +.GLOBAL _AAS_vol_lookup + + +@ Volume lookup table. -1 means use multiply, 0 to 7 means use bit shift. + +_AAS_vol_lookup: + .byte 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4 + .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5 + .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6 + .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7 + +_ma_mul_r5_r0_r3: + .word 0x00000010 + mul r5,r0,r3 +_ma_mov_r5_r0_lsl_0: + .word 0x00000001 + mov r5,r0,lsl #0 +_ma_mlane_r5_r0_r3_r5: + .word 0x00000011 + mlane r5,r0,r3,r5 +_ma_add_r5_r5_r0_lsl_0: + .word 0x00000011 + add r5,r5,r0,lsl #0 + + +_ma_merge_noclip_start: + @ ma_again: + + @ Merge + ldr r14,[sp,#24] + and r5,r14,r5,lsr #8 + and r6,r14,r6,lsr #8 + and r7,r14,r7,lsr #8 + and r8,r14,r8,lsr #8 + and r9,r14,r9,lsr #8 + and r10,r14,r10,lsr #8 + and r11,r14,r11,lsr #8 + and r12,r14,r12,lsr #8 + add r5,r5,r6,lsl #8 + add r6,r7,r8,lsl #8 + add r7,r9,r10,lsl #8 + add r8,r11,r12,lsl #8 + + @ Store + stmia r4!,{r5-r8} + + @ Loop + subs r14,r14,#0x2000000 + .word 0xdaffffa5 @ ble ma_end + + @ ma_start: + str r14,[sp,#24] +_ma_merge_noclip_end: + + +_ma_merge_boostnoclip_start: + @ ma_again: + + @ Merge + ldr r14,[sp,#24] + and r5,r14,r5,lsr #7 + and r6,r14,r6,lsr #7 + and r7,r14,r7,lsr #7 + and r8,r14,r8,lsr #7 + and r9,r14,r9,lsr #7 + and r10,r14,r10,lsr #7 + and r11,r14,r11,lsr #7 + and r12,r14,r12,lsr #7 + add r5,r5,r6,lsl #8 + add r6,r7,r8,lsl #8 + add r7,r9,r10,lsl #8 + add r8,r11,r12,lsl #8 + + @ Store + stmia r4!,{r5-r8} + + @ Loop + subs r14,r14,#0x2000000 + .word 0xdaffffa5 @ ble ma_end + + @ ma_start: + str r14,[sp,#24] +_ma_merge_boostnoclip_end: + + +_ma_merge_clip_start: + _ma_mask_0x80808080: .word 0x80808080 + + .word 0,0 @ padding + + @ ma_again: + @ Merge + ldr r14,[sp,#24] + .word 0xe51f2018 @ ldr r2,_ma_mask_0x80808080 + + and r0,r14,r5,lsr #8 + and r1,r14,r6,lsr #8 + add r0,r0,r1,lsl #8 + and r5,r14,r5,lsr #7 + and r6,r14,r6,lsr #7 + add r5,r5,r6,lsl #8 + eor r0,r0,r5 + ands r0,r2,r0 + beq no_clip1 @ perhaps not worthwhile? + and r1,r2,r5 + sub r1,r2,r1,lsr #7 + sub r0,r0,r0,lsr #7 + orr r0,r0,r0,lsl #1 + bic r5,r5,r0 + and r1,r1,r0 + orr r5,r5,r1 +no_clip1: + + and r0,r14,r7,lsr #8 + and r1,r14,r8,lsr #8 + add r0,r0,r1,lsl #8 + and r7,r14,r7,lsr #7 + and r8,r14,r8,lsr #7 + add r6,r7,r8,lsl #8 + eor r0,r0,r6 + ands r0,r2,r0 + beq no_clip2 @ perhaps not worthwhile? + and r1,r2,r6 + sub r1,r2,r1,lsr #7 + sub r0,r0,r0,lsr #7 + orr r0,r0,r0,lsl #1 + bic r6,r6,r0 + and r1,r1,r0 + orr r6,r6,r1 +no_clip2: + + and r0,r14,r9,lsr #8 + and r1,r14,r10,lsr #8 + add r0,r0,r1,lsl #8 + and r9,r14,r9,lsr #7 + and r10,r14,r10,lsr #7 + add r7,r9,r10,lsl #8 + eor r0,r0,r7 + ands r0,r2,r0 + beq no_clip3 @ perhaps not worthwhile? + and r1,r2,r7 + sub r1,r2,r1,lsr #7 + sub r0,r0,r0,lsr #7 + orr r0,r0,r0,lsl #1 + bic r7,r7,r0 + and r1,r1,r0 + orr r7,r7,r1 +no_clip3: + + and r0,r14,r11,lsr #8 + and r1,r14,r12,lsr #8 + add r0,r0,r1,lsl #8 + and r11,r14,r11,lsr #7 + and r12,r14,r12,lsr #7 + add r8,r11,r12,lsl #8 + eor r0,r0,r8 + ands r0,r2,r0 + beq no_clip4 @ perhaps not worthwhile? + and r1,r2,r8 + sub r1,r2,r1,lsr #7 + sub r0,r0,r0,lsr #7 + orr r0,r0,r0,lsl #1 + bic r8,r8,r0 + and r1,r1,r0 + orr r8,r8,r1 +no_clip4: + + @ Store + stmia r4!,{r5-r8} + + @ Loop + subs r14,r14,#0x2000000 + .word 0xdaffff6d @ ble ma_end + + @ ma_start: + str r14,[sp,#24] +_ma_merge_clip_end: + +_ma_clip: +add r12,pc,#0x540 @ adr r12,ma_buffer_start +.word 0xea000091 @ b ma_start +add r0,pc,#0x248 @ adr r0,ma_again + +_ma_noclip: +add r12,pc,#0x460 @ adr r12,ma_buffer_start +.word 0xea000059 @ b ma_start +add r0,pc,#0x23c @ adr r0,ma_again + + +AAS_MixAudio_SetMode_BoostAndClip: + adr r12,_ma_clip + adr r0,_ma_merge_clip_start + mov r2,#((_ma_merge_clip_end-_ma_merge_clip_start)/4) + +do_mods: + ldr r1,=_AAS_MixAudio_mod4 + add r2,r2,#0x84000000 + mov r3,#0x04000000 + add r3,r3,#0xd4 + stmia r3,{r0-r2} + ldmia r12,{r1-r3} + ldr r0,=_AAS_MixAudio_mod1 + str r1,[r0] + ldr r0,=_AAS_MixAudio_mod2 + str r2,[r0] + ldr r0,=_AAS_MixAudio_mod3 + str r3,[r0] + bx lr + + +AAS_MixAudio_SetMode_Normal: + adr r12,_ma_noclip + adr r0,_ma_merge_noclip_start + mov r2,#((_ma_merge_noclip_end-_ma_merge_noclip_start)/4) + b do_mods + + +AAS_MixAudio_SetMode_Boost: + adr r12,_ma_noclip + adr r0,_ma_merge_boostnoclip_start + mov r2,#((_ma_merge_boostnoclip_end-_ma_merge_boostnoclip_start)/4) + b do_mods + + +_ma_2ch: +mov r6,#0x10000000 +mov r10,#2 +mov r14,#2 +sub r1,r1,#(20*2) + +_ma_4ch: +mov r6,#0x30000000 +mov r10,#4 +mov r14,#4 +sub r1,r1,#(20*4) + +_ma_8ch: +mov r6,#0x70000000 +mov r10,#8 +mov r14,#8 +sub r1,r1,#(20*8) + + +AAS_MixAudio_SetMaxChans_4: + adr r12,_ma_4ch + +do_mods2: + ldmia r12,{r0-r3} + ldr r12,=_AAS_MixAudio_mod5 + str r0,[r12] + ldr r12,=_AAS_MixAudio_mod6 + str r1,[r12] + ldr r12,=_AAS_MixAudio_mod7 + str r2,[r12] + ldr r12,=_AAS_MixAudio_mod8 + str r3,[r12] + bx lr + + +AAS_MixAudio_SetMaxChans_8: + adr r12,_ma_8ch + b do_mods2 + + +AAS_MixAudio_SetMaxChans_2: + adr r12,_ma_2ch + b do_mods2 + +.pool + + +AAS_DoDMA3: + mov r3,#0x04000000 + add r3,r3,#0xd4 + stmia r3,{r0-r2} + bx lr diff --git a/lib/apex-audio-system/src/aas/AAS_Logo.c b/lib/apex-audio-system/src/aas/AAS_Logo.c new file mode 100644 index 0000000..d37de86 --- /dev/null +++ b/lib/apex-audio-system/src/aas/AAS_Logo.c @@ -0,0 +1,153 @@ +// Copyright (c) 2003-2021 James Daniels +// Distributed under the MIT License +// license terms: see LICENSE file in root or http://opensource.org/licenses/MIT + +#include "AAS_Shared.h" + +static const AAS_u16 AAS_Logo_Palette[256] = { 0, 1057, 2114, 3171, 3207, 4228, 5285, 4231, 6342, 7399, 5288, 4234, 5320, 6312, 6344, 6345, 6377, 7401, 6346, 7402, 5292, 5294, 6348, 7407, 7433, 7434, 7436, 15591, 8456, 9513, 8458, 8459, 9483, 9514, 9515, 10539, 10570, 10571, 11627, 9516, 9519, 10540, 10543, 11597, 11598, 15690, 12654, 12684, 12685, 13741, 12686, 12687, 12718, 13742, 15756, 14798, 15855, 5265, 5299, 6322, 7408, 6354, 7381, 7382, 6360, 7419, 7440, 8441, 8496, 8467, 9553, 10547, 10576, 10578, 9525, 8503, 10551, 10581, 11638, 11664, 11666, 12688, 13746, 14800, 15856, 15857, 14803, 13748, 12695, 14773, 14775, 15860, 14807, 8473, 9530, 9560, 9562, 10555, 10585, 10587, 8509, 9534, 10556, 11645, 10622, 11677, 11679, 12696, 12699, 15832, 12701, 12703, 13791, 15869, 14815, 17639, 18663, 20678, 23783, 16681, 16747, 19720, 19819, 16780, 17870, 18861, 18894, 20810, 22825, 22891, 21900, 20975, 22924, 24014, 24807, 25864, 25930, 27945, 26987, 25005, 26062, 27020, 28143, 28936, 30026, 32107, 29068, 29167, 32173, 32206, 16895, 16912, 16913, 16945, 17937, 17969, 17971, 19984, 19026, 20083, 16949, 17974, 18006, 19028, 20084, 20085, 19030, 22065, 22098, 23056, 24179, 21140, 21141, 22164, 22197, 21143, 22198, 22199, 22231, 23188, 23254, 23255, 24278, 24311, 17948, 17951, 19004, 19007, 20063, 21119, 21144, 22232, 23256, 23257, 24312, 24313, 24314, 26161, 25203, 27185, 28275, 26293, 26359, 27317, 27350, 29200, 29266, 31248, 31281, 32272, 32305, 31314, 31347, 32338, 32371, 29332, 30422, 31380, 31413, 32404, 32437, 31446, 32470, 32503, 25368, 25369, 25401, 26392, 26425, 26427, 27416, 27482, 27483, 28506, 28539, 28540, 29497, 30587, 32536, 31578, 31611, 32602, 32635, 29596, 29597, 30620, 30653, 30654, 31677, 31710, 31711, 31743, 32734, 32767, 0, 0 }; + +static const AAS_u32 AAS_Logo_Image[2880] = { 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 3958898173UL, 4108903909UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4110286333UL, 1145459375UL, 1210597954UL, 4226130514UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1146874877UL, 1767718717UL, 1651404398UL, 1447443530UL, 4261281220UL, 4261281277UL, 4261281277UL, 4261281277UL, 4194172413UL, 4261263027UL, 4261281277UL, 4261281277UL, 3825073661UL, 3014898611UL, 4261000883UL, 4261281277UL, 4261281277UL, 3014910973UL, 4142325942UL, 4261281277UL, 4261281277UL, 3068394237UL, 4261281017UL, 4261281258UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4227726845UL, 1715357374UL, 1130852208UL, 1128218432UL, 1030517353UL, 4260864328UL, 4261281277UL, 4261281277UL, 4261281277UL, 3405643261UL, 4242963357UL, 4261281277UL, 4261281277UL, 2835217917UL, 3890733991UL, 4257906150UL, 4261281277UL, 4261281277UL, 3819415804UL, 4261281002UL, 4261281277UL, 4261281277UL, 2129067517UL, 3438667434UL, 4261281273UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 2700738045UL, 1785751365UL, 1044398145UL, 976894522UL, 1918712378UL, 3897967211UL, 4261281277UL, 4261281277UL, 4261281277UL, 2868706813UL, 4121524138UL, 4261281277UL, 4261281277UL, 2851732989UL, 3402281859UL, 4257839818UL, 4261281277UL, 4261281277UL, 3011750393UL, 4261279974UL, 4261281277UL, 4261281277UL, 2214133245UL, 3970607735UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1297873661UL, 1097101423UL, 117904446UL, 67372807UL, 976819466UL, 1379692899UL, 4261281268UL, 4261281277UL, 4261281277UL, 3337420285UL, 3866720935UL, 4261281276UL, 4261281277UL, 2247687677UL, 3400968834UL, 4257972172UL, 4261281277UL, 4261281277UL, 2860484088UL, 4260949964UL, 4261281277UL, 4261281277UL, 3438935549UL, 3869864825UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1867424253UL, 375219312UL, 118098956UL, 117704455UL, 352782087UL, 1148280121UL, 4261280160UL, 4261281277UL, 4261281277UL, 3402563069UL, 3312822696UL, 4261281269UL, 4261281277UL, 2365128189UL, 3351610752UL, 4260334791UL, 4261281277UL, 4261281277UL, 2843774200UL, 4260354248UL, 4261281277UL, 4261281277UL, 3439132157UL, 3431232901UL, 4261281276UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1919895489UL, 252857189UL, 168430092UL, 117901066UL, 67372807UL, 1902000907UL, 4261264966UL, 4261281277UL, 4261281277UL, 3452826109UL, 2290584974UL, 4261281263UL, 4261281277UL, 2398682621UL, 4042050445UL, 4261281016UL, 4261281277UL, 4261281277UL, 2861403896UL, 4261279974UL, 4261281277UL, 4261281277UL, 3640524285UL, 3464924103UL, 4261281272UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4160617981UL, 1752329296UL, 252777311UL, 168430606UL, 117705223UL, 67372804UL, 1731922692UL, 4259861080UL, 4261281277UL, 4261281277UL, 4042841341UL, 2429013228UL, 4261281245UL, 4261281277UL, 3489463805UL, 4260949141UL, 4261281277UL, 4261281277UL, 4261281277UL, 3381826552UL, 4261279980UL, 4261281277UL, 4261281277UL, 3690135037UL, 2425015270UL, 4261281265UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 2952658429UL, 1735356237UL, 252712986UL, 202116110UL, 67372807UL, 67569415UL, 1041564676UL, 4255270038UL, 4261281277UL, 4261281277UL, 4261278200UL, 2498754812UL, 4261281234UL, 4261281277UL, 3590192637UL, 4261280978UL, 4261281277UL, 4261281277UL, 4261281277UL, 3499414012UL, 4175420630UL, 4261281277UL, 4261281277UL, 4242472189UL, 2446912752UL, 4261281234UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1358626301UL, 1164604012UL, 269555998UL, 168693263UL, 67372807UL, 117704452UL, 1023870727UL, 4099042145UL, 4261281277UL, 4261281277UL, 4261281277UL, 4244438525UL, 4261281276UL, 4261281277UL, 4244504061UL, 4261281276UL, 4261281277UL, 4261281277UL, 4261281277UL, 4075942653UL, 4261215480UL, 4261281277UL, 4261281277UL, 4261281277UL, 4025547004UL, 4261281272UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1206255101UL, 661549167UL, 286858783UL, 201985808UL, 270012687UL, 117900295UL, 352782087UL, 3208933695UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261215484UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 3992320252UL, 4261281272UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1320156669UL, 693661807UL, 421404192UL, 269356049UL, 589438488UL, 117705251UL, 185009927UL, 2689036862UL, 4261281275UL, 4261281277UL, 4261281277UL, 4261209062UL, 4261281277UL, 4210949629UL, 4261279209UL, 4210687485UL, 4261281277UL, 3874881021UL, 3823363043UL, 4261279178UL, 4261281277UL, 4260030973UL, 4261281277UL, 3405184509UL, 3065427638UL, 4261280202UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1650195965UL, 692679282UL, 505422370UL, 286198808UL, 875242014UL, 117909812UL, 117901066UL, 1380870462UL, 4261281271UL, 4261281277UL, 3992845821UL, 4242766718UL, 4261281277UL, 4244504061UL, 4261275303UL, 4193648125UL, 4261281277UL, 2095513085UL, 3823559626UL, 4261193885UL, 4261281277UL, 4256412669UL, 4261281277UL, 2812870141UL, 3403932618UL, 4261262972UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1649606141UL, 692622998UL, 572662313UL, 286132752UL, 1429349150UL, 118370899UL, 168430090UL, 1331192125UL, 4261281259UL, 4261281277UL, 3338468861UL, 4119033801UL, 4261281277UL, 4177395197UL, 4261203075UL, 4193123837UL, 4261281277UL, 2060254717UL, 3823757002UL, 4260987815UL, 4261281277UL, 4239043324UL, 4261281277UL, 2810445053UL, 3874089443UL, 4261194365UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1665727485UL, 726186390UL, 690170155UL, 269355534UL, 841687576UL, 118565678UL, 168430090UL, 678125885UL, 4261281253UL, 4261281277UL, 3321429501UL, 3430515368UL, 4261281276UL, 4043177469UL, 4261005698UL, 4176477693UL, 4261281277UL, 2144075005UL, 3874351562UL, 4260922793UL, 4261281277UL, 4173703672UL, 4261281277UL, 2844129789UL, 3874878950UL, 4260939138UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1615395837UL, 743487929UL, 724249387UL, 235670031UL, 572526862UL, 118431778UL, 168430604UL, 1332438590UL, 4261280708UL, 4261281277UL, 3386375677UL, 3312822183UL, 4261281269UL, 4043177469UL, 4260939905UL, 4176608765UL, 4261281277UL, 2177629437UL, 3874876876UL, 4260924300UL, 4261281277UL, 4173827320UL, 4261281277UL, 3314284797UL, 3975739622UL, 4260939659UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1280375549UL, 861387705UL, 774581806UL, 218761753UL, 286330380UL, 168431889UL, 168562188UL, 1330538815UL, 4261280707UL, 4261281277UL, 3348364541UL, 2272693132UL, 4261281263UL, 4076731901UL, 4260417162UL, 4176608765UL, 4261281277UL, 2295856381UL, 3874549708UL, 4260924814UL, 4261281277UL, 4174222328UL, 4261281277UL, 2391668989UL, 3975213798UL, 4260939661UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1297545981UL, 1366145904UL, 774779442UL, 168232747UL, 235670538UL, 202116623UL, 302911246UL, 1330278493UL, 4261280451UL, 4261281277UL, 4025409533UL, 2311572716UL, 4261280985UL, 4177395197UL, 4243574418UL, 4176412157UL, 4261281277UL, 2430270973UL, 3438079192UL, 4260926867UL, 4261281277UL, 4241543164UL, 4261281277UL, 3449158909UL, 3975147494UL, 4261204882UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1235418109UL, 1387969639UL, 875705395UL, 67575604UL, 168232711UL, 252578826UL, 386863120UL, 1363309150UL, 4261280451UL, 4261281277UL, 4244430589UL, 2515333368UL, 4261280977UL, 4244504061UL, 3755856277UL, 4242271982UL, 4261281277UL, 2447310333UL, 3571112404UL, 4261204628UL, 4261281277UL, 4258648828UL, 4261281277UL, 2513632765UL, 3655196121UL, 4261272721UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 683801597UL, 1505606497UL, 875836242UL, 119549490UL, 168035332UL, 286331153UL, 1259343889UL, 1445424231UL, 4261280737UL, 4261281277UL, 4261281020UL, 4059889149UL, 4261281009UL, 4261281277UL, 4007649272UL, 4260950510UL, 4261281277UL, 3757243901UL, 3671776733UL, 4261278429UL, 4261281277UL, 4260491773UL, 4261281277UL, 3757637117UL, 3739213791UL, 4261280991UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1340669437UL, 3132976973UL, 875843922UL, 724251186UL, 505421602UL, 404299294UL, 1712787729UL, 2737259890UL, 4261281255UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4244504061UL, 3974753784UL, 4261281005UL, 4261281277UL, 4261281277UL, 4261281277UL, 4244504061UL, 4177329404UL, 4261281272UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 2700410365UL, 3183173160UL, 877744749UL, 724250162UL, 539108137UL, 421076510UL, 1784746769UL, 2771527529UL, 4261281258UL, 4261281277UL, 4210884093UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4193910013UL, 4261281276UL, 4261281277UL, 3924424188UL, 4261281005UL, 4261281277UL, 4261281020UL, 4261281277UL, 4261215485UL, 4177395197UL, 4261281016UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 3237608957UL, 3160885034UL, 1364352189UL, 724250162UL, 539108137UL, 421076512UL, 1885888275UL, 2991925061UL, 4261281271UL, 4261281277UL, 2828901878UL, 4207588269UL, 3019570685UL, 4261280173UL, 4261078781UL, 2644375037UL, 3820400040UL, 4143840762UL, 914140618UL, 4259755688UL, 2645097981UL, 3820401581UL, 4261281270UL, 4121787560UL, 3019439613UL, 4261260668UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 3858628093UL, 1850484636UL, 1382923708UL, 724250193UL, 539109673UL, 438181920UL, 1265789538UL, 3785109031UL, 4261281275UL, 4261281277UL, 3014883530UL, 4261013962UL, 3925736957UL, 4176065406UL, 4261277165UL, 2910374652UL, 4243180211UL, 4261281277UL, 766044669UL, 4261279203UL, 2642672125UL, 4261013942UL, 4244504061UL, 3866656170UL, 2817128693UL, 4260996989UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4110286333UL, 1277645233UL, 3099442281UL, 741101399UL, 572729643UL, 1766270754UL, 710963311UL, 4088156971UL, 4261281277UL, 4261281277UL, 2829613001UL, 4243442355UL, 4177395197UL, 3871963817UL, 4261281228UL, 2809645564UL, 3989484456UL, 4261281276UL, 2058024445UL, 4261280230UL, 2206397949UL, 4260947635UL, 4177395197UL, 2837152682UL, 2814830282UL, 4260725626UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4227726845UL, 657236964UL, 3166266958UL, 1348122812UL, 1227500104UL, 1886350926UL, 724198250UL, 4209155637UL, 4261281277UL, 4261281277UL, 1936947660UL, 4035213683UL, 4244504061UL, 3313795046UL, 4261281269UL, 1937362173UL, 2222551923UL, 4261281264UL, 2143746301UL, 4261281004UL, 2139418877UL, 4023961257UL, 4194172413UL, 2138679493UL, 2810562986UL, 4260726143UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 731493879UL, 1734363418UL, 3116088505UL, 1920112313UL, 1735366258UL, 807610189UL, 4260803736UL, 4261281277UL, 4261281277UL, 2223359480UL, 3632300418UL, 4261281277UL, 3414214125UL, 4261281272UL, 2244344061UL, 2155971202UL, 4261281240UL, 2294873341UL, 4261281261UL, 2173432061UL, 4176465094UL, 4244504061UL, 1971628744UL, 2810554793UL, 4260727937UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1437657853UL, 1192891182UL, 1919903327UL, 1869771378UL, 659384168UL, 1412375840UL, 4261276334UL, 4261281277UL, 4261281277UL, 2865556989UL, 3716655527UL, 4261281277UL, 3632977912UL, 4261281276UL, 3438149117UL, 2276042666UL, 4261281245UL, 2463759613UL, 4261281266UL, 2374891773UL, 4260949193UL, 4261281277UL, 1992740052UL, 2865139080UL, 4260926346UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 2934504957UL, 287387732UL, 1162094608UL, 1162496586UL, 555622184UL, 2891198500UL, 4261280744UL, 4261281277UL, 4261281277UL, 3874553085UL, 3750807753UL, 4261281277UL, 4053065725UL, 4261281277UL, 4043111933UL, 2429077990UL, 4261281247UL, 2497641981UL, 4261281276UL, 2476080381UL, 4261212108UL, 4261281277UL, 2462904284UL, 3435959183UL, 4261204117UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 3942383101UL, 791779760UL, 286793253UL, 504959251UL, 639901985UL, 3903887921UL, 4261281275UL, 4261281277UL, 4261281277UL, 3604733682UL, 4241871317UL, 4261281277UL, 4074107389UL, 4261281277UL, 3688821501UL, 3587298774UL, 4261281276UL, 3605986813UL, 4261281276UL, 3520462333UL, 3739014869UL, 4261281272UL, 3757636831UL, 4176539285UL, 4261272789UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 1419756275UL, 606482225UL, 606348325UL, 1412509478UL, 4260610719UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281020UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261215485UL, 4261281277UL, 4261281277UL, 4261281277UL, 4244504061UL, 4261281276UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 3051944445UL, 926456228UL, 926365495UL, 3047463736UL, 4261280231UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4194172413UL, 2964710122UL, 2964106156UL, 4192920245UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4143578109UL, 4143379446UL, 4261280761UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4143840765UL, 3942514163UL, 4210490873UL, 3942514173UL, 3942120953UL, 4260625917UL, 3942252029UL, 4143185405UL, 4261018109UL, 4261281277UL, 4261281277UL, 4159962621UL, 4261281277UL, 3941268989UL, 4260817642UL, 4210949629UL, 3941264106UL, 4261281275UL, 4261145334UL, 4261278715UL, 4261281277UL, 4261281277UL, 3941264118UL, 4261281258UL, 3941858813UL, 4260817642UL, 4194172413UL, 4142590698UL, 4261281277UL, 4261278707UL, 3942317565UL, 4226476778UL, 4261281277UL, 4261279466UL, 4261280247UL, 3942055421UL, 4260817642UL, 4261281277UL, 4261281277UL, 4260817661UL, 4261082877UL, 3942317565UL, 4226476778UL, 4093509117UL, 3941264106UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 2667445757UL, 12057859UL, 4196859192UL, 150863357UL, 3145016UL, 4247910120UL, 15203837UL, 151124714UL, 4259617789UL, 4261281277UL, 4261281277UL, 151190269UL, 4261281277UL, 788790781UL, 3875577764UL, 3942514173UL, 2678364928UL, 4261281270UL, 4255056359UL, 4261261463UL, 4261281277UL, 4261281277UL, 2762212664UL, 4261230344UL, 487194109UL, 4259357860UL, 50200061UL, 3030688823UL, 4261281277UL, 4261226022UL, 488963581UL, 4137657508UL, 4261281277UL, 4259971333UL, 4261263263UL, 2583820029UL, 4259357860UL, 4261281277UL, 4261281277UL, 4177723901UL, 4259985661UL, 15400445UL, 4137657499UL, 2935881213UL, 2671181988UL, 4261281274UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 3908959741UL, 641264128UL, 4247780617UL, 939392509UL, 52886793UL, 4256084127UL, 66977277UL, 2537375UL, 4261228537UL, 4261281277UL, 4261281277UL, 10395645UL, 4261281252UL, 2751725053UL, 3070295549UL, 3942514173UL, 4261276160UL, 4261281277UL, 939630333UL, 4261281183UL, 4261281277UL, 4261281277UL, 4261218616UL, 4261226022UL, 940178941UL, 4261281277UL, 16645629UL, 4192922283UL, 4261281277UL, 4261226022UL, 940178941UL, 4261281277UL, 4261281277UL, 4246478118UL, 4261263268UL, 3070290685UL, 4261079786UL, 4261281277UL, 4261281277UL, 805840637UL, 4259985661UL, 15400445UL, 4261281258UL, 4261281277UL, 4256628989UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 3072761603UL, 4254851584UL, 3086876157UL, 798484224UL, 4260771620UL, 654179837UL, 32127014UL, 4261228468UL, 4261281277UL, 4261281277UL, 503129341UL, 4261281060UL, 788790781UL, 3875577764UL, 3942514173UL, 926429440UL, 4261281277UL, 84540925UL, 4261281275UL, 2930048509UL, 4261281277UL, 4261218616UL, 4261226022UL, 151649789UL, 4259461176UL, 66977277UL, 134217728UL, 4261281277UL, 4261226022UL, 940178941UL, 2667657271UL, 4261281277UL, 2667705126UL, 4261263268UL, 129021UL, 4246536192UL, 4261281277UL, 4261281277UL, 15148797UL, 4259985591UL, 15400445UL, 4248254513UL, 4261281277UL, 4256628989UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4197522726UL, 4259454209UL, 4194172413UL, 2766152705UL, 4261225986UL, 2684222973UL, 486352387UL, 4261255709UL, 4261281277UL, 4261281277UL, 808985780UL, 4261276160UL, 2600730109UL, 4260817642UL, 3942514173UL, 4261276160UL, 4261281277UL, 36757757UL, 4261281080UL, 2654535165UL, 4261281277UL, 4261218616UL, 4261226022UL, 940178941UL, 4261281277UL, 4261281277UL, 60816893UL, 4261281277UL, 4261226022UL, 940178941UL, 2751725053UL, 4261281277UL, 27262246UL, 4261263255UL, 4261281277UL, 4245240061UL, 4261281277UL, 4261281277UL, 956114685UL, 4259985155UL, 15400445UL, 4261281258UL, 4261281277UL, 4256628989UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4255908004UL, 4261085468UL, 4261281277UL, 4093313289UL, 4261228544UL, 3942514173UL, 2549952512UL, 4261273600UL, 166198781UL, 4261281277UL, 4261280294UL, 4261228808UL, 2667838973UL, 4261281277UL, 3942514173UL, 3082267648UL, 4261281270UL, 3036491751UL, 4261273600UL, 4261281277UL, 4261281277UL, 3082225208UL, 4261228828UL, 638189053UL, 4259821495UL, 3086876157UL, 104314807UL, 4261281277UL, 4261226022UL, 639499773UL, 2667755447UL, 4261281277UL, 167640358UL, 4261263105UL, 3082287869UL, 4246546103UL, 838729213UL, 4261281188UL, 4210894589UL, 4259971333UL, 15400445UL, 4139235244UL, 4261281277UL, 4256628989UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261001209UL, 4261274858UL, 4261281277UL, 4261274856UL, 4261278688UL, 4261281277UL, 4143838176UL, 4261280695UL, 3086482941UL, 4261281277UL, 4261281255UL, 4261274346UL, 4091608573UL, 4261281277UL, 4194172413UL, 3082270647UL, 4261281273UL, 4261280231UL, 4261275616UL, 4261281277UL, 4261281277UL, 3082270698UL, 4261280183UL, 3085106685UL, 4260018103UL, 3774742013UL, 4088903607UL, 4261281277UL, 4261275623UL, 3086417405UL, 4091852727UL, 4261281277UL, 4143840740UL, 4261279671UL, 3082288637UL, 4260804535UL, 3892182525UL, 4261281258UL, 4261275642UL, 4261066730UL, 3086614013UL, 4189566903UL, 4261281277UL, 4260804602UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL, 4261281277UL }; + +#define REG_BG2X (*(volatile AAS_u32 *)0x4000028) +#define REG_BG2Y (*(volatile AAS_u32 *)0x400002C) +#define REG_BG2PA (*(volatile AAS_u16 *)0x4000020) +#define REG_BG2PD (*(volatile AAS_u16 *)0x4000026) + +static void AAS_AddBrightness( int add ) +{ + int i, r, g, b, val, t; + AAS_u16* dest = (AAS_u16*)0x5000000; + const AAS_u16* palette_pos = AAS_Logo_Palette; + + for( i = 256; i > 0; --i ) + { + val = *palette_pos++; + r = AAS_Min( (val>>10)+add, 31 ); + g = AAS_Min( ((val>>5)&0x1f)+add, 31 ); + b = AAS_Min( (val&0x1f)+add, 31 ); + *dest++ = r + (g<<5) + (b<<10); + } +} + +static void AAS_AddBrightness2( int add ) +{ + int i, r, g, b, val, t; + AAS_u16* dest = (AAS_u16*)0x5000000; + const AAS_u16* palette_pos = AAS_Logo_Palette; + + ++palette_pos; + ++dest; + + for( i = 255; i > 0; --i ) + { + val = *palette_pos++; + r = AAS_Min( (val>>10)+add, 31 ); + g = AAS_Min( ((val>>5)&0x1f)+add, 31 ); + b = AAS_Min( (val&0x1f)+add, 31 ); + *dest++ = r + (g<<5) + (b<<10); + } +} + +static void AAS_SetBrightness( int brightness ) +{ + int i, r, g, b, val, t; + AAS_u16* dest = (AAS_u16*)0x5000000; + const AAS_u16* palette_pos = AAS_Logo_Palette; + + for( i = 256; i > 0; --i ) + { + val = *palette_pos++; + r = ((val>>10)*brightness)>>5; + g = (((val>>5)&0x1f)*brightness)>>5; + b = ((val&0x1f)*brightness)>>5; + *dest++ = r + (g<<5) + (b<<10); + } +} + +static void AAS_BlankFrame( AAS_u32 val ) +{ + AAS_u32* dest_pos = (AAS_u32*)0x06000000; + int i; + + for( i = 9600; i > 0; --i ) + *dest_pos++ = val; +} + +static void AAS_CopyFrame() +{ + const AAS_u32* source_pos = AAS_Logo_Image; + AAS_u32* dest_pos = (AAS_u32*)(0x06000000 + (240*51)); + int i; + + for( i = 2880; i > 0; --i ) + *dest_pos++ = *source_pos++; +} + +static void AAS_WaitVBlank() +{ + while( REG_VCOUNT >= 160 ); + while( REG_VCOUNT < 160 ); +} + +void AAS_ShowLogo() +{ + int i, tmpx, tmpy; + + AAS_WaitVBlank(); + AAS_AddBrightness( 32 ); + DISPCNT = 0x0444; + AAS_BlankFrame( 0xfdfdfdfd ); + AAS_CopyFrame(); + + for( i = 31; i >= 0; --i ) + { + AAS_WaitVBlank(); + AAS_AddBrightness( i ); + } + + for( i = 120; i > 0; --i ) + { + AAS_WaitVBlank(); + } + + for( i = 0; i <= 15; ++i ) + { + AAS_WaitVBlank(); + + if ( i > 0 ) + { + tmpy = i<<10; + REG_BG2PD = tmpy; + REG_BG2Y = 20480-(80*tmpy); + } + + AAS_AddBrightness2( i ); + } + + for( i = 16; i <= 31; ++i ) + { + AAS_WaitVBlank(); + + tmpx = (i-16)<<11; + tmpy = i<<10; + REG_BG2PA = tmpx; + REG_BG2PD = tmpy; + REG_BG2X = 30720-(120*tmpx); + REG_BG2Y = 20480-(80*tmpy); + + AAS_AddBrightness2( i ); + } + + for( i = 31; i >= 0; --i ) + { + AAS_SetBrightness( i ); + AAS_WaitVBlank(); + } + + AAS_BlankFrame( 0 ); + + REG_BG2PA = 256; + REG_BG2PD = 256; + REG_BG2X = 30720-(120*256); + REG_BG2Y = 20480-(80*256); +} diff --git a/lib/apex-audio-system/src/aas/AAS_MOD.c b/lib/apex-audio-system/src/aas/AAS_MOD.c new file mode 100644 index 0000000..4e9aff8 --- /dev/null +++ b/lib/apex-audio-system/src/aas/AAS_MOD.c @@ -0,0 +1,1047 @@ +// Copyright (c) 2003-2021 James Daniels +// Distributed under the MIT License +// license terms: see LICENSE file in root or http://opensource.org/licenses/MIT + +#include "AAS_Shared.h" + +AAS_s16 AAS_mod_num AAS_IN_EWRAM = -1; +AAS_u8 AAS_mod_num_chans AAS_IN_EWRAM = 0; + +static AAS_s16 AAS_mod_num_store AAS_IN_EWRAM = -2; +static AAS_u16 AAS_mod_song_pos AAS_IN_EWRAM; +static AAS_u16 AAS_mod_line_num AAS_IN_EWRAM; + +struct AAS_MOD_Channel +{ + AAS_u32* pattern; + const AAS_u8* samp_start; + AAS_u16 effect; + AAS_u16 period; + AAS_u16 slide_target_period; + AAS_u8 samp_num; + AAS_u8 slide_rate; + AAS_u8 volume; + AAS_u8 vibrato_rate; + AAS_u8 vibrato_depth; + AAS_u8 vibrato_pos; + AAS_u8 tremolo_rate; + AAS_u8 tremolo_depth; + AAS_u8 tremolo_pos; + AAS_s8 trigger; + AAS_u8 arpeggio_pos; + AAS_u8 note; +}; // 28 bytes + +static struct AAS_MOD_Channel AAS_mod_chan[AAS_MAX_CHANNELS] AAS_IN_EWRAM; + +static AAS_s32 AAS_mod_timer AAS_IN_EWRAM; +static AAS_u32 AAS_mod_tempo AAS_IN_EWRAM; +static AAS_u8 AAS_mod_bpm AAS_IN_EWRAM; +static AAS_u8 AAS_mod_speed AAS_IN_EWRAM; +static AAS_BOOL AAS_mod_looped AAS_IN_EWRAM = AAS_FALSE; +static AAS_s16 AAS_mod_overall_volume AAS_IN_EWRAM = 256; +static AAS_u8 AAS_mod_loop_start AAS_IN_EWRAM = 0; +static AAS_s8 AAS_mod_loop_counter AAS_IN_EWRAM = 0; +static AAS_BOOL AAS_mod_loop AAS_IN_EWRAM = AAS_TRUE; +static AAS_u8 AAS_mod_last_filter_value AAS_IN_EWRAM = 0; +static AAS_BOOL AAS_mod_active_effects AAS_IN_EWRAM = AAS_FALSE; +static AAS_s8 AAS_mod_next_song_pos AAS_IN_EWRAM = -1; + +int AAS_MOD_GetNumChannels() +{ + return AAS_mod_num_chans; +} + +int AAS_MOD_GetLastFilterValue() +{ + return AAS_mod_last_filter_value; +} + +int AAS_MOD_QueueSongPos( int song_pos ) +{ + if ( AAS_mod_num >= 0 ) + { + if ( (song_pos >= 0) && (song_pos < 128) ) + { + if ( AAS_Sequence[AAS_mod_num][song_pos][0] == -1 ) + { + return AAS_ERROR_INVALID_SONG_POS; + } + else + { + AAS_mod_next_song_pos = song_pos; + + return AAS_OK; + } + } + else + { + return AAS_ERROR_INVALID_SONG_POS; + } + } + else + { + return AAS_ERROR_NO_MOD_PLAYING; + } +} + +int AAS_MOD_SetSongPos( int song_pos ) +{ + if ( AAS_mod_num >= 0 ) + { + if ( (song_pos >= 0) && (song_pos < 128) ) + { + if ( AAS_Sequence[AAS_mod_num][song_pos][0] == -1 ) + { + return AAS_ERROR_INVALID_SONG_POS; + } + else + { + struct AAS_MOD_Channel* mod_chan = AAS_mod_chan; + int chan; + + for( chan = 0; chan < AAS_mod_num_chans; ++chan ) + { + mod_chan->pattern = (AAS_u32*)(AAS_PatternData + (((int)AAS_Sequence[AAS_mod_num][song_pos][chan])<<8)); + ++mod_chan; + } + AAS_mod_line_num = 0; + AAS_mod_song_pos = song_pos; + + return AAS_OK; + } + } + else + { + return AAS_ERROR_INVALID_SONG_POS; + } + } + else + { + return AAS_ERROR_NO_MOD_PLAYING; + } +} + +int AAS_MOD_GetSongPos() +{ + if ( AAS_mod_num >= 0 ) + return AAS_mod_song_pos; + else + return AAS_ERROR_NO_MOD_PLAYING; +} + +int AAS_MOD_GetLineNum() +{ + if ( AAS_mod_num >= 0 ) + return AAS_mod_line_num; + else + return AAS_ERROR_NO_MOD_PLAYING; +} + +int AAS_MOD_GetVolume() +{ + return AAS_mod_overall_volume; +} + +int AAS_MOD_SetVolume( int vol ) +{ + if ( (vol >= 0) && (vol <= 256) ) + { + int i; + + for( i = AAS_mod_num_chans-1; i >= 0; --i ) + AAS_channels[AAS_chan_rearrange[i]].volume = (AAS_mod_chan[i].volume*vol)>>AAS_volscale; + + AAS_mod_overall_volume = vol; + + return AAS_OK; + } + else + { + return AAS_ERROR_VOLUME_OUT_OF_RANGE; + } +} + +void AAS_MOD_Pause() +{ + int i; + + AAS_mod_num_store = AAS_mod_num; + AAS_mod_num = -1; + + for( i = 0; i < AAS_mod_num_chans; ++i ) + { + AAS_channels[AAS_chan_rearrange[i]].active = AAS_FALSE; + } +} + +void AAS_MOD_Resume() +{ + if ( AAS_mod_num_store != -2 ) + { + struct AAS_Channel* ch; + int i; + + for( i = 0; i < AAS_mod_num_chans; ++i ) + { + ch = &AAS_channels[AAS_chan_rearrange[i]]; + + if ( !ch->active ) + { + if ( ch->loop_length ) + { + ch->active = AAS_TRUE; + } + else + { + if ( ch->pos < ((ch->end - (ch->delta>>6)) - 1) ) + { + ch->active = AAS_TRUE; + } + } + } + } + + AAS_mod_num = AAS_mod_num_store; + } +} + +void AAS_MOD_Stop() +{ + int i; + struct AAS_Channel* ch; + AAS_mod_num_store = -2; + AAS_mod_num = -1; + AAS_mod_next_song_pos = -1; + + for( i = 0; i < AAS_mod_num_chans; ++i ) + { + ch = &AAS_channels[AAS_chan_rearrange[i]]; + ch->active = AAS_FALSE; + ch->loop_length = 0; + ch->pos = 0; + ch->end = 0; + ch->delta = 0; + AAS_mod_chan[i].tremolo_pos = 0; + AAS_mod_chan[i].vibrato_pos = 0; + AAS_mod_chan[i].effect = 0; + AAS_mod_chan[i].volume = 0; + AAS_mod_chan[i].trigger = -1; + AAS_mod_chan[i].note = 0; + AAS_mod_chan[i].slide_target_period = 0; + } + AAS_mod_active_effects = AAS_FALSE; + AAS_mod_looped = AAS_FALSE; + AAS_mod_loop_counter = 0; + AAS_mod_loop_start = 0; + AAS_mod_last_filter_value = 0; + AAS_mod_num_chans = 0; +} + +AAS_BOOL AAS_MOD_HasLooped() +{ + return AAS_mod_looped; +} + +AAS_BOOL AAS_MOD_IsPlaying() +{ + return (AAS_mod_num>=0); +} + +int AAS_MOD_Play( int song_num ) +{ + AAS_MOD_Stop(); + + if ( AAS_initialised ) + { + if ( (song_num >= 0) && (song_num < AAS_DATA_NUM_MODS) && AAS_NumChans[song_num] ) + { + int i; + + if ( AAS_volscale == 9 ) + i = 16; + else if ( AAS_volscale == 8 ) + i = 8; + else + i = 4; + + if ( AAS_NumChans[song_num] > i ) + { + return AAS_ERROR_NOT_ENOUGH_CHANNELS; + } + else + { + //AAS_mod_num = 0; + AAS_mod_loop = AAS_TRUE; + AAS_mod_num_store = -2; + AAS_mod_song_pos = 0; + AAS_mod_num_chans = AAS_NumChans[song_num]; + + for( i = 0; i < AAS_mod_num_chans; ++i ) + AAS_mod_chan[i].pattern = (AAS_u32*)(AAS_PatternData + (((int)AAS_Sequence[song_num][0][i])<<8)); + + AAS_mod_line_num = 0; + AAS_mod_speed = 6; + AAS_mod_bpm = 125; + AAS_mod_tempo = AAS_DivTable[AAS_mod_speed]*AAS_mod_bpm; + AAS_mod_timer = 0x7d0000 - AAS_mod_tempo; + AAS_mod_num = song_num; + return AAS_OK; + } + } + else + { + return AAS_ERROR_MOD_DOES_NOT_EXIST; + } + } + else + { + return AAS_ERROR_CALL_SET_CONFIG_FIRST; + } +} + +int AAS_MOD_SetLoop( AAS_BOOL loop ) +{ + if ( AAS_initialised ) + { + if ( AAS_mod_num >= 0 ) + { + AAS_mod_loop = loop; + return AAS_OK; + } + else + { + return AAS_ERROR_NO_MOD_PLAYING; + } + } + else + { + return AAS_ERROR_CALL_SET_CONFIG_FIRST; + } +} + +void AAS_MOD_Interrupt() +{ + if ( AAS_mod_num >= 0 ) + { + AAS_mod_timer += AAS_mod_tempo; + + if ( AAS_mod_timer < 0x7d0000 ) + { + if ( AAS_mod_active_effects ) + { + const AAS_u8* chan_rearrange = AAS_chan_rearrange; + struct AAS_MOD_Channel* mod_chan = AAS_mod_chan; + int chan, num_chans; + + num_chans = AAS_mod_num_chans; + + for( chan = 0; chan < num_chans; ++chan ) + { + int effect; + + effect = mod_chan->effect; + + if ( effect ) + { + int val, tmp, output; + struct AAS_Channel* out_chan; + + tmp = chan_rearrange[chan]; + out_chan = &AAS_channels[tmp]; + output = tmp>>3; + + switch( effect>>8 ) + { + case 0xe: // extended effects + switch( effect&0xf0 ) + { + case 0xc0: // note cut + val = effect&0xf; + --val; + if ( val <= 0 ) + { + mod_chan->effect = 0; + out_chan->active = AAS_FALSE; + + AAS_changed[output] = AAS_TRUE; + } + else + { + mod_chan->effect = (effect&0xff0)+val; + } + break; + + case 0x90: // retrigger sample + case 0xd0: // delay sample + if ( mod_chan->trigger >= 0 ) + { + --mod_chan->trigger; + if ( mod_chan->trigger < 0 ) + { + const struct AAS_ModSample* samp = &AAS_ModSamples[AAS_mod_num][mod_chan->samp_num]; + int repeat = samp->repeat; + int length = samp->length; + const AAS_s8* data = AAS_SampleData + samp->data; + + mod_chan->samp_start = data; + out_chan->pos = data; + out_chan->pos_fraction = 0; + if ( repeat == 65535 ) + out_chan->loop_length = 0; + else + out_chan->loop_length = ((AAS_u32)(length - repeat))<<1; + out_chan->end = data + (length<<1); + out_chan->frequency = AAS_MOD_period_conv_table[mod_chan->period]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + out_chan->active = AAS_TRUE; + + AAS_changed[output] = AAS_TRUE; + } + } + break; + + default: + break; + } + break; + + case 0x6: // vibrato + volume slide + val = mod_chan->vibrato_pos; + val += mod_chan->vibrato_rate; + if ( val >= 64 ) + val -= 64; + mod_chan->vibrato_pos = val; + tmp = mod_chan->period + (((AAS_sin[val]*mod_chan->vibrato_depth)+32)>>6); + if ( tmp < 113 ) + tmp = 113; + if ( tmp > 856 ) + tmp = 856; + out_chan->frequency = AAS_MOD_period_conv_table[tmp]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + // Intentionally no "break;" + + case 0xa: // volume slide + val = effect&0xf0; + if ( val ) + val >>= 4; + else + val = -(effect&0xf); + tmp = mod_chan->volume; + tmp += val; + if ( tmp > 64 ) + tmp = 64; + else if ( tmp < 0 ) + tmp = 0; + mod_chan->volume = tmp; + out_chan->volume = (tmp*AAS_mod_overall_volume)>>AAS_volscale; + + AAS_changed[output] = AAS_TRUE; + break; + + case 0x1: // slide up + val = effect&0xff; + tmp = mod_chan->period - val; + if ( tmp < 113 ) + tmp = 113; + mod_chan->period = tmp; + out_chan->frequency = AAS_MOD_period_conv_table[tmp]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + + AAS_changed[output] = AAS_TRUE; + break; + + case 0x2: // slide down + val = effect&0xff; + tmp = mod_chan->period + val; + if ( tmp > 856 ) + tmp = 856; + mod_chan->period = tmp; + out_chan->frequency = AAS_MOD_period_conv_table[tmp]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + + AAS_changed[output] = AAS_TRUE; + break; + + case 0x3: // tone portamento + val = mod_chan->period; + tmp = mod_chan->slide_target_period; + if ( val < tmp ) + { + val += mod_chan->slide_rate; + if ( val >= tmp ) + { + mod_chan->effect = 0; + val = tmp; + } + } + else if ( val > tmp ) + { + val -= mod_chan->slide_rate; + if ( val <= tmp ) + { + mod_chan->effect = 0; + val = tmp; + } + } + else if ( val == tmp ) + { + mod_chan->effect = 0; + } + mod_chan->period = val; + out_chan->frequency = AAS_MOD_period_conv_table[val]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + + AAS_changed[output] = AAS_TRUE; + break; + + case 0x5: // tone portamento + volume slide + val = mod_chan->period; + tmp = mod_chan->slide_target_period; + if ( val < tmp ) + { + val += mod_chan->slide_rate; + if ( val >= tmp ) + val = tmp; + } + else if ( val > tmp ) + { + val -= mod_chan->slide_rate; + if ( val <= tmp ) + val = tmp; + } + mod_chan->period = val; + out_chan->frequency = AAS_MOD_period_conv_table[val]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + + val = effect&0xf0; + if ( val ) + val >>= 4; + else + val = -(effect&0xf); + tmp = mod_chan->volume; + tmp += val; + if ( tmp > 64 ) + tmp = 64; + else if ( tmp < 0 ) + tmp = 0; + mod_chan->volume = tmp; + out_chan->volume = (tmp*AAS_mod_overall_volume)>>AAS_volscale; + + AAS_changed[output] = AAS_TRUE; + break; + + case 0x4: // vibrato + val = mod_chan->vibrato_pos; + val += mod_chan->vibrato_rate; + if ( val >= 64 ) + val -= 64; + mod_chan->vibrato_pos = val; + tmp = mod_chan->period + (((AAS_sin[val]*mod_chan->vibrato_depth)+32)>>6); + if ( tmp < 113 ) + tmp = 113; + else if ( tmp > 856 ) + tmp = 856; + out_chan->frequency = AAS_MOD_period_conv_table[tmp]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + + AAS_changed[output] = AAS_TRUE; + break; + + case 0x7: // tremolo + val = mod_chan->tremolo_pos; + val += mod_chan->tremolo_rate; + if ( val >= 64 ) + val -= 64; + mod_chan->tremolo_pos = val; + tmp = mod_chan->volume + (((AAS_sin[val]*mod_chan->tremolo_depth)+32)>>6); + if ( tmp < 0 ) + tmp = 0; + else if ( tmp > 64 ) + tmp = 64; + out_chan->volume = (tmp*AAS_mod_overall_volume)>>AAS_volscale; + + AAS_changed[output] = AAS_TRUE; + break; + + case 0x0: // possible arpeggio + tmp = effect & 0xff; + if ( tmp ) // definite arpeggio + { + ++mod_chan->arpeggio_pos; + val = mod_chan->note; + switch( mod_chan->arpeggio_pos ) + { + case 0: + break; + + case 1: + val += tmp>>4; + break; + + case 2: + val += tmp&0xf; + // Intentionally no "break;" to allow AAS_mod_arpeggio_pos[chan] to be restarted + + default: + mod_chan->arpeggio_pos = 0; + break; + } + + if ( val ) + { + out_chan->frequency = AAS_MOD_period_conv_table[AAS_period_table[AAS_ModSamples[AAS_mod_num][mod_chan->samp_num].finetune][val-1]]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + + AAS_changed[output] = AAS_TRUE; + } + } + break; + + default: + break; + } + } + + ++mod_chan; + } + } + } + else + { + const AAS_u8* chan_rearrange = AAS_chan_rearrange; + struct AAS_MOD_Channel* mod_chan = AAS_mod_chan; + int chan, num_chans; + int samp_num, effect, period, speed, tmp; + int jump_ahead = -1; + int jump_song_pos = -1; + AAS_BOOL active_effects = AAS_FALSE; + const struct AAS_ModSample* mod_samp = AAS_ModSamples[AAS_mod_num]; + + num_chans = AAS_mod_num_chans; + + AAS_mod_timer -= 0x7d0000; + + for( chan = 0; chan < num_chans; ++chan ) + { + int output; + struct AAS_Channel* out_chan; + AAS_u32 dat; + + tmp = chan_rearrange[chan]; + out_chan = &AAS_channels[tmp]; + output = tmp>>3; + + // Tidy up after arpeggio + effect = mod_chan->effect; + if ( effect ) + { + if ( effect < 0x100 ) + { + tmp = mod_chan->note; + if ( tmp ) + { + out_chan->frequency = AAS_MOD_period_conv_table[AAS_period_table[mod_samp[mod_chan->samp_num].finetune][tmp-1]]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + + AAS_changed[output] = AAS_TRUE; + } + } + } + + dat = *mod_chan->pattern++; + samp_num = (dat>>24)-1; + period = (dat>>12)&0xfff; + effect = dat&0xfff; + + if ( samp_num >= 0 ) + { + mod_chan->samp_num = samp_num; + mod_chan->volume = tmp = mod_samp[samp_num].volume; + out_chan->volume = (tmp*AAS_mod_overall_volume)>>AAS_volscale; + + AAS_changed[output] = AAS_TRUE; + } + else + { + samp_num = mod_chan->samp_num; + } + + if ( period ) + { + if ( samp_num >= 0 ) + { + const struct AAS_ModSample* samp = &mod_samp[samp_num]; + + mod_chan->note = period; + period = AAS_period_table[samp->finetune][period-1]; + + if ( (effect > 0xed0) && (effect < 0xee0) ) // delay sample + { + mod_chan->period = period; + mod_chan->trigger = (effect&0xf)-1; + } + else + { + tmp = effect>>8; + + if ( (tmp != 0x3) && (tmp != 0x5) ) + { + int repeat = samp->repeat; + int length = samp->length; + const AAS_s8* data = AAS_SampleData + samp->data; + + mod_chan->samp_start = data; + out_chan->pos = data; + out_chan->pos_fraction = 0; + mod_chan->period = period; + if ( repeat == 65535 ) + out_chan->loop_length = 0; + else + out_chan->loop_length = ((AAS_u32)(length - repeat))<<1; + out_chan->end = data + (length<<1); + out_chan->frequency = AAS_MOD_period_conv_table[period]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + out_chan->active = AAS_TRUE; + + AAS_changed[output] = AAS_TRUE; + } + } + } + } + + if ( effect ) + { + switch( effect>>8 ) + { + case 0xf: // set speed + speed = effect&0xff; + if ( speed > 0 ) + { + if ( speed > 31 ) + AAS_mod_bpm = speed; + else + AAS_mod_speed = speed; + + //AAS_mod_tempo = (((1<<15)*AAS_mod_bpm*24)/(3000*AAS_mod_speed))<<13; // use LUT + + // approximately: + //AAS_mod_tempo = AAS_DivTable[AAS_mod_speed]*AAS_mod_bpm*33; + AAS_mod_tempo = AAS_DivTable[AAS_mod_speed]*AAS_mod_bpm; + } + effect = 0; // No need to process this effect again + break; + + case 0xe: // extended effects + switch( effect&0xf0 ) + { + case 0x00: // set filter (used to send messages to code instead) + AAS_mod_last_filter_value = effect&0xf; + effect = 0; // No need to process this effect again + break; + + case 0x10: // fine slide up + tmp = mod_chan->period - (effect&0xf); + if ( tmp < 113 ) + tmp = 113; + mod_chan->period = tmp; + out_chan->frequency = AAS_MOD_period_conv_table[tmp]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + effect = 0; // No need to process this effect again + + AAS_changed[output] = AAS_TRUE; + break; + + case 0x20: // fine slide down + tmp = mod_chan->period + (effect&0xf); + if ( tmp > 856 ) + tmp = 856; + mod_chan->period = tmp; + out_chan->frequency = AAS_MOD_period_conv_table[tmp]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + effect = 0; // No need to process this effect again + + AAS_changed[output] = AAS_TRUE; + break; + + case 0x60: // set/jump to loop + tmp = effect & 0xf; + if ( tmp ) + { + if ( AAS_mod_loop_counter ) + --AAS_mod_loop_counter; + else + AAS_mod_loop_counter = tmp; + + if ( AAS_mod_loop_counter ) + { + int i; + struct AAS_MOD_Channel* mod_chan2 = AAS_mod_chan; + + for( i = 0; i < num_chans; ++i ) + { + mod_chan2->pattern = (AAS_u32*)(AAS_PatternData + (((int)AAS_Sequence[AAS_mod_num][AAS_mod_song_pos][i])<<8)); + mod_chan2->pattern += AAS_mod_loop_start; + ++mod_chan2; + } + AAS_mod_line_num = AAS_mod_loop_start; + } + } + else + { + AAS_mod_loop_start = AAS_mod_line_num; + } + effect = 0; // No need to process this effect again + break; + + case 0x90: // retrigger sample + mod_chan->trigger = (effect&0xf)-1; + break; + + case 0xa0: // fine volume slide up + tmp = mod_chan->volume; + tmp += effect&0xf; + if ( tmp > 64 ) + tmp = 64; + mod_chan->volume = tmp; + out_chan->volume = (tmp*AAS_mod_overall_volume)>>AAS_volscale; + effect = 0; // No need to process this effect again + + AAS_changed[output] = AAS_TRUE; + break; + + case 0xb0: // fine volume slide down + tmp = mod_chan->volume; + tmp -= effect&0xf; + if ( tmp < 0 ) + tmp = 0; + mod_chan->volume = tmp; + out_chan->volume = (tmp*AAS_mod_overall_volume)>>AAS_volscale; + effect = 0; // No need to process this effect again + + AAS_changed[output] = AAS_TRUE; + break; + + case 0xc0: // note cut + if ( (effect&0xf) == 0 ) + { + effect = 0; + out_chan->active = AAS_FALSE; + AAS_changed[output] = AAS_TRUE; + } + break; + + case 0xe0: // pattern delay + AAS_mod_timer -= (effect&0xf)*0x7d0000; + effect = 0; // No need to process this effect again + break; + + default: + break; + } + break; + + case 0xd: // pattern break + //jump_ahead = (((effect>>4)&0xf)*10)+(effect&0xf); + jump_ahead = effect&0xff; + effect = 0; // No need to process this effect again + break; + + case 0xc: // set volume + mod_chan->volume = tmp = effect&0xff; + out_chan->volume = (tmp*AAS_mod_overall_volume)>>AAS_volscale; + effect = 0; // No need to process this effect again + + AAS_changed[output] = AAS_TRUE; + break; + + case 0xb: // position jump + jump_song_pos = effect&0xff; + effect = 0; // No need to process this effect again + break; + + case 0x9: // set sample offset + tmp = effect & 0xff; + if ( tmp ) + { + const AAS_s8* new_pos = mod_chan->samp_start + (tmp<<8); + + if ( new_pos >= out_chan->end ) + { + out_chan->active = AAS_FALSE; + + AAS_changed[output] = AAS_TRUE; + } + else + out_chan->pos = new_pos; + } + effect = 0; // No need to process this effect again + break; + + case 0x7: // tremolo + if ( effect & 0xf0 ) + mod_chan->tremolo_rate = (effect & 0xf0)>>4; + if ( effect & 0xf ) + mod_chan->tremolo_depth = effect & 0xf; + if ( effect & 0xff ) + mod_chan->tremolo_pos = 0; + break; + + case 0x4: // vibrato + if ( effect & 0xf0 ) + mod_chan->vibrato_rate = (effect & 0xf0)>>4; + if ( effect & 0xf ) + mod_chan->vibrato_depth = effect & 0xf; + if ( effect & 0xff ) + mod_chan->vibrato_pos = 0; + break; + + case 0x3: // tone portamento + tmp = effect & 0xff; + if ( tmp ) + mod_chan->slide_rate = tmp; + + if ( period ) + mod_chan->slide_target_period = period; + else if ( mod_chan->slide_target_period == 0 ) + effect = 0; + break; + + case 0x0: // possible arpeggio + tmp = effect & 0xff; + if ( tmp ) // definite arpeggio + { + tmp = mod_chan->note; + mod_chan->arpeggio_pos = 0; + if ( tmp ) + { + out_chan->frequency = AAS_MOD_period_conv_table[AAS_period_table[mod_samp[mod_chan->samp_num].finetune][tmp-1]]; + out_chan->delta = AAS_Min( 4095, ((out_chan->frequency*AAS_mix_scale)+32768)>>16 ); + + AAS_changed[output] = AAS_TRUE; + } + } + break; + + default: + //printf_special( "effect:%p period:%d samp:%d\n", effect, period, samp_num ); + break; + } + } + + mod_chan->effect = effect; + if ( effect ) + active_effects = AAS_TRUE; + ++mod_chan; + } + + AAS_mod_active_effects = active_effects; + + if ( jump_ahead >= 0 ) + { + AAS_mod_loop_start = 0; + ++AAS_mod_song_pos; + if ( AAS_Sequence[AAS_mod_num][AAS_mod_song_pos][0] == -1 ) + { + AAS_mod_looped = AAS_TRUE; + AAS_mod_song_pos = 0; + mod_chan = AAS_mod_chan; + for( chan = num_chans; chan > 0; --chan ) + { + mod_chan->slide_target_period = 0; + ++mod_chan; + } + } + + mod_chan = AAS_mod_chan; + for( chan = 0; chan < num_chans; ++chan ) + { + mod_chan->pattern = (AAS_u32*)(AAS_PatternData + (((int)AAS_Sequence[AAS_mod_num][AAS_mod_song_pos][chan])<<8)); + mod_chan->pattern += jump_ahead; + ++mod_chan; + } + AAS_mod_line_num = jump_ahead; + } + else if ( jump_song_pos >= 0 ) + { + AAS_mod_loop_start = 0; + if ( jump_song_pos < 128 ) + { + AAS_mod_song_pos = jump_song_pos; + if ( AAS_Sequence[AAS_mod_num][AAS_mod_song_pos][0] == -1 ) + { + AAS_mod_looped = AAS_TRUE; + mod_chan = AAS_mod_chan; + for( chan = num_chans; chan > 0; --chan ) + { + mod_chan->slide_target_period = 0; + ++mod_chan; + } + AAS_mod_song_pos = 0; + } + } + else + { + AAS_mod_looped = AAS_TRUE; + mod_chan = AAS_mod_chan; + for( chan = num_chans; chan > 0; --chan ) + { + mod_chan->slide_target_period = 0; + ++mod_chan; + } + AAS_mod_song_pos = 0; + } + + mod_chan = AAS_mod_chan; + for( chan = 0; chan < num_chans; ++chan ) + { + mod_chan->pattern = (AAS_u32*)(AAS_PatternData + (((int)AAS_Sequence[AAS_mod_num][AAS_mod_song_pos][chan])<<8)); + ++mod_chan; + } + AAS_mod_line_num = 0; + } + else + { + ++AAS_mod_line_num; + if ( AAS_mod_line_num > 63 ) + { + AAS_mod_line_num = 0; + AAS_mod_loop_start = 0; + + if ( AAS_mod_next_song_pos == -1 ) + { + ++AAS_mod_song_pos; + } + else + { + AAS_mod_song_pos = AAS_mod_next_song_pos; + AAS_mod_next_song_pos = -1; + } + + if ( AAS_Sequence[AAS_mod_num][AAS_mod_song_pos][0] == -1 ) + { + AAS_mod_looped = AAS_TRUE; + mod_chan = AAS_mod_chan; + for( chan = num_chans; chan > 0; --chan ) + { + mod_chan->slide_target_period = 0; + ++mod_chan; + } + AAS_mod_song_pos = AAS_RestartPos[AAS_mod_num]; + } + + mod_chan = AAS_mod_chan; + for( chan = 0; chan < num_chans; ++chan ) + { + mod_chan->pattern = (AAS_u32*)(AAS_PatternData + (((int)AAS_Sequence[AAS_mod_num][AAS_mod_song_pos][chan])<<8)); + ++mod_chan; + } + } + } + + if ( AAS_mod_looped ) + if ( !AAS_mod_loop ) + AAS_MOD_Stop(); + } + } +} diff --git a/lib/apex-audio-system/src/aas/AAS_Main.c b/lib/apex-audio-system/src/aas/AAS_Main.c new file mode 100644 index 0000000..3a484d6 --- /dev/null +++ b/lib/apex-audio-system/src/aas/AAS_Main.c @@ -0,0 +1,802 @@ +// Copyright (c) 2003-2021 James Daniels +// Distributed under the MIT License +// license terms: see LICENSE file in root or http://opensource.org/licenses/MIT + +#include "AAS_Shared.h" + +extern const int AAS_data_v111; +int AAS_lib_v111 AAS_IN_EWRAM; + +static AAS_BOOL AAS_da_active AAS_IN_EWRAM; +static AAS_BOOL AAS_db_active AAS_IN_EWRAM; +static AAS_BOOL AAS_dynamic_mix_rate AAS_IN_EWRAM; + +// 0 = 0 Hz mix rate +// 1 = 800 Hz mix rate, 16 byte mix buffer +// 2 = 1600 Hz mix rate, 32 byte mix buffer +// n = 800n Hz mix rate, 16n byte mix buffer +// n <= 40 +// REG_TM1D = 0x10000 - 16n; +// REG_TM0D = AAS_tick_rate[n]; // 0x10000 - ((int)(16777216/800n)); +static AAS_u8 AAS_req_mix_rate AAS_IN_EWRAM; +static AAS_u8 AAS_next_mix_rate AAS_IN_EWRAM; + +static AAS_u8* AAS_next_mixing_buffer AAS_IN_EWRAM; + +static AAS_BOOL AAS_DSA_first AAS_IN_EWRAM = AAS_TRUE; + +static AAS_u8 AAS_MaxChans AAS_IN_EWRAM = 4; + +static AAS_BOOL AAS_Loud AAS_IN_EWRAM = AAS_FALSE; +static AAS_u8 AAS_MixAudio_Mode AAS_IN_EWRAM = AAS_MIXAUDIO_MODE_NORMAL; + +void AAS_MixAudio_SetMode( int mode ) +{ + if ( mode != AAS_MixAudio_Mode ) + { + switch( mode ) + { + case AAS_MIXAUDIO_MODE_NORMAL: + AAS_MixAudio_SetMode_Normal(); + AAS_MixAudio_Mode = AAS_MIXAUDIO_MODE_NORMAL; + AAS_changed[0] = AAS_TRUE; + AAS_changed[1] = AAS_TRUE; + break; + + case AAS_MIXAUDIO_MODE_BOOST: + AAS_MixAudio_SetMode_Boost(); + AAS_MixAudio_Mode = AAS_MIXAUDIO_MODE_BOOST; + AAS_changed[0] = AAS_TRUE; + AAS_changed[1] = AAS_TRUE; + break; + + case AAS_MIXAUDIO_MODE_BOOSTANDCLIP: + AAS_MixAudio_SetMode_BoostAndClip(); + AAS_MixAudio_Mode = AAS_MIXAUDIO_MODE_BOOSTANDCLIP; + AAS_changed[0] = AAS_TRUE; + AAS_changed[1] = AAS_TRUE; + break; + + default: + break; + } + } +} + +static void AAS_DoConfig( int mix_rate, int volscale, AAS_BOOL stereo, AAS_BOOL dynamic, AAS_BOOL loud, int chans ) +{ + struct AAS_Channel* ch; + int i; + + AAS_MOD_Stop(); + + if ( !AAS_initialised ) + { + REG_SOUNDCNT_X = 0x0080; // turn sound chip on + + REG_DMA1SAD = (AAS_u32)AAS_mix_buffer; //dma1 source + REG_DMA1DAD = 0x040000a0; //write to FIFO A address + REG_DMA1CNT_H = 0xb600; //dma control: DMA enabled+ start on FIFO+32bit+repeat+increment source&dest + + REG_DMA2SAD = (AAS_u32)(AAS_mix_buffer + 160); //dma2 source + REG_DMA2DAD = 0x040000a4; //write to FIFO B address + REG_DMA2CNT_H = 0xb600; //dma control: DMA enabled+ start on FIFO+32bit+repeat+increment source&dest + + AAS_next_mixing_buffer = ((AAS_u8*)AAS_mix_buffer) + 1280; + + REG_IE |= 0x10; // Enable irq for timer 1 + REG_IME = 1; // Enable all interrupts + + AAS_da_active = AAS_FALSE; + AAS_db_active = AAS_FALSE; + } + + REG_TM0CNT = 0x0; + REG_TM1CNT = 0x0; + + if ( chans != AAS_MaxChans ) + { + switch( chans ) + { + case 8: + AAS_MixAudio_SetMaxChans_8(); + break; + + case 4: + AAS_MixAudio_SetMaxChans_4(); + break; + + default: + AAS_MixAudio_SetMaxChans_2(); + break; + } + AAS_MaxChans = chans; + } + + AAS_next_mix_rate = AAS_req_mix_rate = mix_rate; + AAS_mix_scale = ((AAS_DivTable[mix_rate]*82)+128)>>6; + AAS_dynamic_mix_rate = dynamic; + + if ( stereo ) + { + const AAS_u8 chan_rearrange[AAS_MAX_CHANNELS] = { 0, 8, 9, 1, 2, 10, 11, 3, 4, 12, 13, 5, 6, 14, 15, 7 }; + + for( i = 0; i < AAS_MAX_CHANNELS; ++i ) + { + AAS_chan_rearrange[i] = chan_rearrange[i]; + } + + REG_SOUNDCNT_H = 0x9a0d; //enable DS A&B + fifo reset + use timer0 + 100% volume to L and R + } + else + { + int a, b; + + a = 0; + for( b = 0; b < chans; ++b ) + { + AAS_chan_rearrange[a] = b; + ++a; + } + for( b = 0; b < chans; ++b ) + { + AAS_chan_rearrange[a] = b + 8; + ++a; + } + + REG_SOUNDCNT_H = 0xbb0d; //enable DS A&B + fifo reset + use timer0 + 100% volume to L and R + } + + ch = &AAS_channels[0]; + for( i = 16; i > 0; --i ) + { + ch->active = AAS_FALSE; + ch->loop_length = 0; + ch->pos = 0; + ch->end = 0; + ch->delta = 0; + ++ch; + } + + AAS_volscale = volscale; + + AAS_Loud = loud; + if ( !loud ) + AAS_MixAudio_SetMode( AAS_MIXAUDIO_MODE_NORMAL ); + + REG_TM0D = AAS_tick_rate[mix_rate]; + REG_TM0CNT = 0x0080; // Enable timer0 + + REG_TM1D = 0x10000 - (mix_rate<<4); + REG_TM1CNT = 0xC4; //enable timer1 + irq and cascade from timer 0 + + AAS_lib_v111 = AAS_data_v111; +} + +int AAS_SetConfig( int config_mix, int config_chans, int config_spatial, int config_dynamic ) +{ + int i, chans, mix_rate, volscale, ret; + AAS_BOOL stereo; + AAS_BOOL dynamic; + AAS_BOOL loud; + + ret = AAS_OK; + + switch( config_mix ) + { + case AAS_CONFIG_MIX_32KHZ: + mix_rate = 40; + break; + + case AAS_CONFIG_MIX_28KHZ: + mix_rate = 35; + break; + + case AAS_CONFIG_MIX_24KHZ: + mix_rate = 30; + break; + + case AAS_CONFIG_MIX_20KHZ: + mix_rate = 25; + break; + + case AAS_CONFIG_MIX_16KHZ: + mix_rate = 20; + break; + + case AAS_CONFIG_MIX_12KHZ: + mix_rate = 15; + break; + + case AAS_CONFIG_MIX_8KHZ: + mix_rate = 10; + break; + + default: + ret = AAS_ERROR_INVALID_CONFIG; + break; + } + + switch( config_chans ) + { + case AAS_CONFIG_CHANS_16_LOUD: + volscale = 9; + loud = AAS_TRUE; + chans = 8; + break; + + case AAS_CONFIG_CHANS_8_LOUD: + volscale = 8; + loud = AAS_TRUE; + chans = 4; + break; + + case AAS_CONFIG_CHANS_4_LOUD: + volscale = 7; + loud = AAS_TRUE; + chans = 2; + break; + + case AAS_CONFIG_CHANS_16: + volscale = 9; + loud = AAS_FALSE; + chans = 8; + break; + + case AAS_CONFIG_CHANS_8: + volscale = 8; + loud = AAS_FALSE; + chans = 4; + break; + + case AAS_CONFIG_CHANS_4: + volscale = 7; + loud = AAS_FALSE; + chans = 2; + break; + + default: + ret = AAS_ERROR_INVALID_CONFIG; + break; + } + + switch( config_spatial ) + { + case AAS_CONFIG_SPATIAL_MONO: + stereo = AAS_FALSE; + break; + + case AAS_CONFIG_SPATIAL_STEREO: + stereo = AAS_TRUE; + break; + + default: + ret = AAS_ERROR_INVALID_CONFIG; + break; + } + + switch( config_dynamic ) + { + case AAS_CONFIG_DYNAMIC_ON: + dynamic = AAS_TRUE; + break; + + case AAS_CONFIG_DYNAMIC_OFF: + dynamic = AAS_FALSE; + break; + + default: + ret = AAS_ERROR_INVALID_CONFIG; + break; + } + + if ( ret == AAS_OK ) + { + AAS_DoConfig( mix_rate, volscale, stereo, dynamic, loud, chans ); + + AAS_initialised = AAS_TRUE; + } + + return ret; +} + +const AAS_s8* AAS_GetOutputBufferAddress( int buffer ) +{ + switch( buffer ) + { + case 0: + if ( AAS_da_active ) + return AAS_next_mixing_buffer; + else + return AAS_NULL; + break; + + case 1: + if ( AAS_db_active ) + return AAS_next_mixing_buffer + 640; + else + return AAS_NULL; + break; + + default: + return AAS_NULL; + break; + } +} + +int AAS_GetOutputBufferLength() +{ + return AAS_next_mix_rate*16; +} + +const AAS_u32 AAS_zero_vols[160] = { 0 }; + +static AAS_BOOL AAS_interrupt_occured AAS_IN_EWRAM = AAS_FALSE; + +void AAS_FastTimer1InterruptHandler() +{ + if ( AAS_dynamic_mix_rate ) + { + REG_TM0CNT = 0x0; + REG_TM0D = AAS_tick_rate[AAS_next_mix_rate]; + REG_TM0CNT = 0x0080; // Enable timer0 + REG_TM1CNT = 0x0; + REG_TM1D = 0x10000 - (AAS_next_mix_rate<<4); + REG_TM1CNT = 0xC4; // Enable timer1 + irq and cascade from timer 0 + } + + REG_DMA1CNT = 0x84400004; + REG_DMA2CNT = 0x84400004; + REG_DMA1CNT_H = 0x0440; + REG_DMA2CNT_H = 0x0440; + if ( AAS_da_active ) + REG_DMA1SAD = (unsigned long)AAS_next_mixing_buffer; // DMA1 source + else + REG_DMA1SAD = (unsigned long)AAS_zero_vols; + REG_DMA1CNT_H = 0xb600; // DMA control: DMA enabled+start on FIFO+32bit+repeat+increment source&dest + // Get click on hardware when switch off DMA on Direct Sound B, so have to do it this way instead + if ( AAS_db_active ) + REG_DMA2SAD = (unsigned long)AAS_next_mixing_buffer + 640; // DMA2 source + else + REG_DMA2SAD = (unsigned long)AAS_zero_vols; // DMA2 source + REG_DMA2CNT_H = 0xb600; // DMA control: DMA enabled+start on FIFO+32bit+repeat+increment source&dest + + AAS_interrupt_occured = AAS_TRUE; +} + +#define READCH1 \ + if ( ch->active ) \ + { \ + int vol = ch->volume; \ + if ( vol == 0 ) \ + { \ + int delta = ch->delta; \ + const AAS_s8* end_addr; \ + addr = ch->pos + ((delta*curr_mix_rate)>>6); \ + end_addr = (ch->end - (delta>>6)) - 1; \ + if ( addr >= end_addr ) \ + { \ + int ll = ch->loop_length; \ + if ( ll ) \ + { \ + while( addr >= end_addr ) \ + { \ + addr -= ll; \ + } \ + } \ + else \ + { \ + ch->active = AAS_FALSE; \ + } \ + } \ + ch->pos = addr; \ + } \ + else \ + { \ + tmp1 += vol; \ + } \ + ch->effective_volume = vol; \ + } \ + else \ + { \ + ch->effective_volume = 0; \ + } \ + +#define READCH2 \ + if ( ch->active ) \ + { \ + int vol = ch->volume; \ + if ( vol == 0 ) \ + { \ + int delta = ch->delta; \ + const AAS_s8* end_addr; \ + addr = ch->pos + ((delta*curr_mix_rate)>>6); \ + end_addr = (ch->end - (delta>>6)) - 1; \ + if ( addr >= end_addr ) \ + { \ + int ll = ch->loop_length; \ + if ( ll ) \ + { \ + while( addr >= end_addr ) \ + { \ + addr -= ll; \ + } \ + } \ + else \ + { \ + ch->active = AAS_FALSE; \ + } \ + } \ + ch->pos = addr; \ + } \ + else \ + { \ + tmp2 += vol; \ + } \ + ch->effective_volume = vol; \ + } \ + else \ + { \ + ch->effective_volume = 0; \ + } \ + +void AAS_DoWork() +{ + if ( AAS_interrupt_occured ) + { + AAS_interrupt_occured = AAS_FALSE; + + if ( AAS_next_mixing_buffer == (AAS_u8*)AAS_mix_buffer ) + AAS_next_mixing_buffer = ((AAS_u8*)AAS_mix_buffer) + 1280; + else + AAS_next_mixing_buffer = ((AAS_u8*)AAS_mix_buffer); + + AAS_MOD_Interrupt(); + + { + int tmp1, tmp2, val, curr_mix_rate; + struct AAS_Channel* ch; + const AAS_s8* addr; + + curr_mix_rate = AAS_req_mix_rate; + + if ( AAS_dynamic_mix_rate ) + { + val = 0; + ch = &AAS_channels[0]; + for( tmp2 = AAS_MaxChans; tmp2 > 0; --tmp2 ) + { + if ( ch->active && (ch->volume > 0) ) + { + tmp1 = ch->frequency; + if ( tmp1 > val ) + val = tmp1; + } + ++ch; + } + + ch = &AAS_channels[8]; + for( tmp2 = AAS_MaxChans; tmp2 > 0; --tmp2 ) + { + if ( ch->active && (ch->volume > 0) ) + { + tmp1 = ch->frequency; + if ( tmp1 > val ) + val = tmp1; + } + ++ch; + } + + val = ((val * 82)>>16)+1; + if ( val < curr_mix_rate ) + curr_mix_rate = val; + + if ( AAS_next_mix_rate != curr_mix_rate ) + { + AAS_next_mix_rate = curr_mix_rate; + AAS_mix_scale = val = ((AAS_DivTable[curr_mix_rate]*82)+128)>>6; + ch = &AAS_channels[0]; + for( tmp2 = AAS_MaxChans; tmp2 > 0; --tmp2 ) + { + if ( ch->active ) + ch->delta = AAS_Min( 4095, ((ch->frequency*val)+32768)>>16 ); + ++ch; + } + + ch = &AAS_channels[8]; + for( tmp2 = AAS_MaxChans; tmp2 > 0; --tmp2 ) + { + if ( ch->active ) + ch->delta = AAS_Min( 4095, ((ch->frequency*val)+32768)>>16 ); + ++ch; + } + + AAS_changed[0] = AAS_TRUE; + AAS_changed[1] = AAS_TRUE; + } + } + + tmp1 = 0; + tmp2 = 0; + + ch = &AAS_channels[0]; + switch( AAS_MaxChans ) + { + case 8: + READCH1 + ++ch; + READCH1 + ++ch; + READCH1 + ++ch; + READCH1 + ++ch; + READCH1 + ++ch; + READCH1 + ++ch; + READCH1 + ++ch; + READCH1 + ++ch; + READCH2 + ++ch; + READCH2 + ++ch; + READCH2 + ++ch; + READCH2 + ++ch; + READCH2 + ++ch; + READCH2 + ++ch; + READCH2 + ++ch; + READCH2 + break; + + case 4: + READCH1 + ++ch; + READCH1 + ++ch; + READCH1 + ++ch; + READCH1 + ch = &AAS_channels[8]; + READCH2 + ++ch; + READCH2 + ++ch; + READCH2 + ++ch; + READCH2 + break; + + case 2: + default: + READCH1 + ++ch; + READCH1 + ch = &AAS_channels[8]; + READCH2 + ++ch; + READCH2 + break; + } + + if ( AAS_Loud ) + { + if ( AAS_DSA_first ) + { + // Direct Sound A + if ( tmp1 ) + { + if ( tmp1 > 128 ) + { + AAS_MixAudio_SetMode( AAS_MIXAUDIO_MODE_BOOSTANDCLIP ); + } + else + { + AAS_MixAudio_SetMode( AAS_MIXAUDIO_MODE_BOOST ); + } + + if ( AAS_changed[0] ) + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio, AAS_next_mixing_buffer, &AAS_channels[0], curr_mix_rate ); + } + else + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio_NoChange, AAS_next_mixing_buffer, &AAS_channels[0], curr_mix_rate ); + } + AAS_da_active = AAS_TRUE; + } + else + { + AAS_da_active = AAS_FALSE; + } + + // Direct Sound B + if ( tmp2 ) + { + if ( tmp2 > 128 ) + { + AAS_MixAudio_SetMode( AAS_MIXAUDIO_MODE_BOOSTANDCLIP ); + } + else + { + AAS_MixAudio_SetMode( AAS_MIXAUDIO_MODE_BOOST ); + } + + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio, AAS_next_mixing_buffer + 640, &AAS_channels[8], curr_mix_rate ); + } + + AAS_db_active = AAS_TRUE; + } + else + { + AAS_db_active = AAS_FALSE; + } + + AAS_DSA_first = AAS_FALSE; + } + else + { + // Direct Sound B + if ( tmp2 ) + { + if ( tmp2 > 128 ) + { + AAS_MixAudio_SetMode( AAS_MIXAUDIO_MODE_BOOSTANDCLIP ); + } + else + { + AAS_MixAudio_SetMode( AAS_MIXAUDIO_MODE_BOOST ); + } + + if ( AAS_changed[1] ) + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio, AAS_next_mixing_buffer + 640, &AAS_channels[8], curr_mix_rate ); + } + else + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio_NoChange, AAS_next_mixing_buffer + 640, &AAS_channels[8], curr_mix_rate ); + } + AAS_db_active = AAS_TRUE; + } + else + { + AAS_db_active = AAS_FALSE; + } + + // Direct Sound A + if ( tmp1 ) + { + if ( tmp1 > 128 ) + { + AAS_MixAudio_SetMode( AAS_MIXAUDIO_MODE_BOOSTANDCLIP ); + } + else + { + AAS_MixAudio_SetMode( AAS_MIXAUDIO_MODE_BOOST ); + } + + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio, AAS_next_mixing_buffer, &AAS_channels[0], curr_mix_rate ); + } + + AAS_da_active = AAS_TRUE; + } + else + { + AAS_da_active = AAS_FALSE; + } + + AAS_DSA_first = AAS_TRUE; + } + } + else + { + if ( AAS_DSA_first ) + { + // Direct Sound A + if ( tmp1 ) + { + if ( AAS_changed[0] ) + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio, AAS_next_mixing_buffer, &AAS_channels[0], curr_mix_rate ); + } + else + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio_NoChange, AAS_next_mixing_buffer, &AAS_channels[0], curr_mix_rate ); + } + AAS_da_active = AAS_TRUE; + } + else + { + AAS_da_active = AAS_FALSE; + } + + // Direct Sound B + if ( tmp2 ) + { + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio, AAS_next_mixing_buffer + 640, &AAS_channels[8], curr_mix_rate ); + } + AAS_db_active = AAS_TRUE; + } + else + { + AAS_db_active = AAS_FALSE; + } + + AAS_DSA_first = AAS_FALSE; + } + else + { + // Direct Sound B + if ( tmp2 ) + { + if ( AAS_changed[1] ) + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio, AAS_next_mixing_buffer + 640, &AAS_channels[8], curr_mix_rate ); + } + else + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio_NoChange, AAS_next_mixing_buffer + 640, &AAS_channels[8], curr_mix_rate ); + } + AAS_db_active = AAS_TRUE; + } + else + { + AAS_db_active = AAS_FALSE; + } + + // Direct Sound A + if ( tmp1 ) + { + { + AAS_INIT_BRANCH + AAS_BRANCH( AAS_MixAudio, AAS_next_mixing_buffer, &AAS_channels[0], curr_mix_rate ); + } + + AAS_da_active = AAS_TRUE; + } + else + { + AAS_da_active = AAS_FALSE; + } + + AAS_DSA_first = AAS_TRUE; + } + } + + AAS_changed[0] = AAS_FALSE; + AAS_changed[1] = AAS_FALSE; + } + } +} + +void AAS_Timer1InterruptHandler() +{ + AAS_FastTimer1InterruptHandler(); + AAS_DoWork(); +} + +int AAS_GetActualMixRate() +{ + return AAS_next_mix_rate*800; +} diff --git a/lib/apex-audio-system/src/aas/AAS_Mixer.h b/lib/apex-audio-system/src/aas/AAS_Mixer.h new file mode 100644 index 0000000..6d3897f --- /dev/null +++ b/lib/apex-audio-system/src/aas/AAS_Mixer.h @@ -0,0 +1,62 @@ +// Copyright (c) 2003-2021 James Daniels +// Distributed under the MIT License +// license terms: see LICENSE file in root or http://opensource.org/licenses/MIT + +// Mixer-specific AAS include +// +// The functions and variables declared here should only be used if you need +// to directly access AAS_MixAudio(). This is not recommended and doing so +// will make it unsafe to use any other AAS functions except AAS_ShowLogo() +// and AAS_DoDMA3(). See the "Mixer" section of the documentation for more +// information. + +#ifndef __AAS_MIXER__ +#define __AAS_MIXER__ + +#include "AAS.h" + +AAS_BEGIN_DECLS + +#define AAS_IN_IWRAM __attribute__ ((section (".iwram"))) +#define AAS_IN_EWRAM __attribute__ ((section (".ewram"))) + +struct AAS_Channel +{ + AAS_u8 effective_volume; // 0 : effective_volume = (active&volume)?volume:0 + AAS_BOOL active; // 1 : 0 = Channel inactive, 1 = channel active + AAS_u8 volume; // 2 : Total vol of chan set must be <= 256, each vol usually in range 0-64 + AAS_u8 pos_fraction; // 3 : Fraction component of pos + AAS_u16 frequency; // 4 : Frequency (Hz) + AAS_u16 delta; // 6 : Delta + const AAS_s8* pos; // 8 : Current sample address, fraction component in pos_fraction + const AAS_s8* end; // 12 : Address of end of sample + AAS_u32 loop_length; // 16 : 0 = No repeat, Other value = Bytes from end back to restart point +}; // Length = 20 bytes + +extern struct AAS_Channel AAS_channels[16] AAS_IN_EWRAM; +extern AAS_u32 AAS_mix_buffer[640] AAS_IN_EWRAM; + +#define AAS_INIT_BRANCH void (*ptr2Function)(); +#define AAS_BRANCH(a,b...) ({ ptr2Function = a; ptr2Function(b); }) + +// AAS_MixAudio() is in IWRAM, call from ROM as follows: (same for AAS_MixAudio_NoChange()) +// AAS_INIT_BRANCH +// AAS_BRANCH( AAS_MixAudio, mix_buffer, chans, iterations ); + +void AAS_MixAudio( AAS_s8* mix_buffer, struct AAS_Channel chans[], int iterations ); +void AAS_MixAudio_NoChange( AAS_s8* mix_buffer, struct AAS_Channel chans[], int iterations ); // Only call if no changes to chans[] since previous call to AAS_MixAudio(). Do not call twice in a row. + +#define AAS_MIXAUDIO_MODE_NORMAL 0 // Total vol must be <= 256, normal vol - default +#define AAS_MIXAUDIO_MODE_BOOST 1 // Total vol must be <= 128, double vol +#define AAS_MIXAUDIO_MODE_BOOSTANDCLIP 2 // Total vol must be <= 256, double vol + +void AAS_MixAudio_SetMode( int mode ); // Set mixer mode, only call if 100% sure AAS_MixAudio won't interrupt + +// Set maximum number of channels in set (lower=faster), only call if 100% sure AAS_MixAudio won't interrupt +void AAS_MixAudio_SetMaxChans_2(); +void AAS_MixAudio_SetMaxChans_4(); // Default +void AAS_MixAudio_SetMaxChans_8(); + +AAS_END_DECLS + +#endif diff --git a/lib/apex-audio-system/src/aas/AAS_Mixer.s b/lib/apex-audio-system/src/aas/AAS_Mixer.s new file mode 100644 index 0000000..7f1e20f --- /dev/null +++ b/lib/apex-audio-system/src/aas/AAS_Mixer.s @@ -0,0 +1,632 @@ +@ Copyright (c) 2003-2021 James Daniels +@ Distributed under the MIT License +@ license terms: see LICENSE file in root or http://opensource.org/licenses/MIT + +.TEXT +.SECTION .iwram,"ax",%progbits +.ALIGN +.ARM + +.GLOBAL AAS_MixAudio +.GLOBAL AAS_MixAudio_NoChange +.EXTERN AAS_DivTable + +.GLOBAL _AAS_MixAudio_mod1 +.GLOBAL _AAS_MixAudio_mod2 +.GLOBAL _AAS_MixAudio_mod3 +.GLOBAL _AAS_MixAudio_mod4 +.GLOBAL _AAS_MixAudio_mod5 +.GLOBAL _AAS_MixAudio_mod6 +.GLOBAL _AAS_MixAudio_mod7 +.GLOBAL _AAS_MixAudio_mod8 + +.pool + +_ma_mov_r3_0: mov r3,#0 +_ma_add_r0_r0_0: add r0,r0,#0 + +_ma_ldr_pc_0: .word 0xe51f0000+8 @ sort of equivalent to opcode(ldr r0,[pc,#-0]) +_ma_mov_r14_r0_lsr_6: mov r14,r0,lsr #6 +_ma_ldrsb_r0_r14_shifted: .word 0x3e1fe00d @ (opcode("ldrsb r0,[r14,#+0]!")>>4) + (3<<28) +_ma_add_r0_r0_r0_lsl_16: adds r0,r0,r0,lsl #16 @ change regs as appropriate +_ma_vol_lookup_addr: .word _AAS_vol_lookup-1 +_ma_total_iterations: .word 0x0 +_ma_total_delta: .word 0x0 +_ma_bytes_available: .word 0x0 +_ma_no_skip: .word 0x0 + + + @ AAS_CODE_IN_IWRAM void AAS_MixAudio_NoChange( AAS_s8* mix_buffer, struct AAS_Channel chans[], int iterations ); + +AAS_MixAudio_NoChange: + stmfd sp!,{r4-r11,r14} + sub sp,sp,#16 + stmfd sp!,{r0-r2} + + mov r9,#0 + str r9,_ma_no_skip + ldr r10,_ma_bytes_available + ldr r9,_ma_total_iterations + cmp r9,r2 + movhi r9,r2 + mov r11,r9 + ldr r2,_ma_total_delta + + b ma_quickstart + + + @ AAS_CODE_IN_IWRAM void AAS_MixAudio( AAS_s8* mix_buffer, struct AAS_Channel chans[], int iterations ); + +AAS_MixAudio: + stmfd sp!,{r4-r11,r14} + sub sp,sp,#16 + stmfd sp!,{r0-r2} + + @ [sp] = _ma_mix_buffer + @ [sp,#4] = _ma_chans + @ [sp,#8] = _ma_to_go + @ [sp,#12] = _ma_iterations_loop + @ [sp,#16] = _ma_iterations_buffer + @ [sp,#20] = _ma_iterations_scale_buffer + @ [sp,#24] = _ma_loop_counter + + @ r0 = temp + @ r1 = chans + @ r2 = iterations in main loop + @ r3 = _ma_add_r0_r0_r0_lsl_16 + @ r4 = temp + @ r5 = temp + @ r6 = outer loop counter/active channels found/total delta>>2 + @ r7 = temp + @ r8 = temp + @ r9 = temp + @ r10 = temp + @ r11 = temp + @ r12 = dest address + @ r14 = temp + +ma_do_setup: +_AAS_MixAudio_mod1: + adr r12,ma_buffer_start + ldr r3,_ma_add_r0_r0_r0_lsl_16 +_AAS_MixAudio_mod5: + mov r6,#0x70000000 @ was #0x30000000 + mov r2,#256 + + +ma_setup_loop: + ldrb r14,[r1],#20 @ effective_volume + + cmp r14,#0 + beq ma_skip @ skip if effective_volume == 0 + + + @ Setup volume registers: + @ r11 = increment for r4 + @ r14 = "mul r5,r0,r3"/"mov r5,r0,lsl #0"/"mlane r5,r0,r3,r5"/"add r5,r5,r0,lsl #0" + @adr r10,_ma_vol_lookup-1 + ldr r10,_ma_vol_lookup_addr + add r4,r10,#129 @ 129 = 1+_ma_mul_r5_r0_r3-_ma_vol_lookup + ldrsb r10,[r10,r14] + ands r5,r6,#0x0f000000 @ test if this is first active channel + addne r4,r4,#16 @ 16 = _ma_mlane_r5_r0_r3_r5-_ma_mul_r5_r0_r3 + @adreq r4,_ma_mul_r5_r0_r3 @ use mul/mov if this is first non-zero chan + @adrne r4,_ma_mlane_r5_r0_r3_r5 @ use mlane/add if this is first non-zero chan + cmp r10,#0 + ldrlt r11,_ma_mov_r3_0 @ read "mov r3,#vol" if vol not power of 2 + addlt r11,r11,r14 @ set #vol in "mov r3,#vol" if vol not power of 2 + strlt r11,[r12],#4 @ write "mov r3,#vol" if vol not power of 2 + addge r4,r4,#8 @ increment if vol is power of 2 + ldmia r4,{r11,r14} @ read mul/mlane/mov/add and increment + addge r14,r14,r10,lsl #7 @ set lsl #val for mov/add if vol power of 2 + + + @ r0,r4,r5,r7,r8,r9,r10 available + @ r3 = _ma_add_r0_r0_0 + @ r5 = delta/increment for r14 + @ r8 = _ma_divide_table + @ r11 = temp (was increment for r14) + @ r12 = dest address + @ r14 = "mul r5,r0,r3"/"mov r5,r0,lsl #0"/"mlane r5,r0,r3,r5"/"add r5,r5,r0,lsl #0" + + @ Setup delta registers, write delta increment instructions: + @ r5 = delta/increment for r14 + adr r7,_ma_chan_cache @ could remove + add r7,r7,r5,lsr #22 @ could remove + ldr r10,_ma_ldr_pc_0 @ could pre-subtract _ma_chan_cache from _ma_ldr_pc_0 (would need to set at runtime) + sub r10,r10,r7 @ could change to sub r10,r10,r5,lsr #22 + add r0,r10,r12 + eor r10,r10,#0x00100000 @ switch to str + ldr r7,_ma_mov_r14_r0_lsr_6 + ldrh r5,[r1,#6-20] @ delta + and r9,r5,#0xff + ldr r4,_ma_add_r0_r0_0 + add r9,r4,r9 + stmia r12!,{r0,r7,r9} + add r7,r4,#0xc00 + add r7,r7,r5,lsr #8 + tst r7,#0xff + strne r7,[r12],#4 + add r6,r6,r5,lsr #2 + add r7,r10,r12 + str r7,[r12],#4 + add r5,r11,r5,lsl #20 + + + @ Final setup: + @ r0 = delta_pos + @ r8 = x + @ r9 = x_history + @ r10 = local outer loop counter/_ma_ldrsb_r0_r14_shifted + mov r0,#0x200 @ delta_pos = 0.5 (was 0) + ldr r10,_ma_ldrsb_r0_r14_shifted + mov r8,#0 + mov r9,#0 + + + @ r0 = delta_pos + @ r1 = chans + @ r2 = iterations in main loop + @ r3 = _ma_add_r0_r0_r0_lsl_16 + @ r4 = temp + @ r5 = delta/increment for r14 + @ r6 = outer loop counter/total delta<<1 + @ r7 = temp + @ r8 = x + @ r9 = x_history + @ r10 = local outer loop counter/_ma_ldrsb_r0_r14_shifted + @ r11 = temp (was increment for r14) + @ r12 = dest address + @ r14 = "mul r5,r0,r3"/"mov r5,r0,lsl #0"/"mlane r5,r0,r3,r5"/"add r5,r5,r0,lsl #0" + + @ Write instructions: + mov r7,r10,lsl #4 + str r7,[r12],#4 + b ma_setup_inner_loop_first + .word 0,0,0 @ padding +ma_setup_outer_loop: + + @ Write delta: + add r0,r0,r5,lsr #20 + movs r4,r0,lsr #10 + beq ma_setup_inner_loop_skip1 + sub r0,r0,r4,lsl #10 + add r4,r4,r10,lsl #4 + mov r8,r7 + add r4,r4,r8,lsl #4 + str r4,[r12],#4 +ma_setup_inner_loop_skip1: + add r9,r8,r9,lsl #8 + +ma_setup_inner_loop_first: + + @ Write delta: + add r0,r0,r5,lsr #20 + movs r4,r0,lsr #10 + beq ma_setup_inner_loop_skip2 + sub r0,r0,r4,lsl #10 + add r4,r4,r10,lsl #4 + subs r8,r8,#0x100 + movlt r8,#0x200 + add r4,r4,r8,lsl #4 + str r4,[r12],#4 +ma_setup_inner_loop_skip2: + add r9,r8,r9,lsl #8 + + @ Write delta: + add r0,r0,r5,lsr #20 + movs r4,r0,lsr #10 + beq ma_setup_inner_loop_skip3 + sub r0,r0,r4,lsl #10 + add r4,r4,r10,lsl #4 + subs r8,r8,#0x100 + movlt r8,#0x200 + add r4,r4,r8,lsl #4 + str r4,[r12],#4 +ma_setup_inner_loop_skip3: + add r9,r8,r9,lsl #8 + + @ Write merge and mul/mla/mov/add: + subs r11,r8,#0x100 + movlt r11,#0x200 + add r7,r14,r11,lsr #8 + add r4,r3,r11,lsl #4 + bic r11,r9,#0x00ff0000 + add r4,r4,r11,lsr #8 + stmia r12!,{r4,r7} + add r14,r14,r5,lsl #12 + + @ Write delta: + add r0,r0,r5,lsr #20 + movs r4,r0,lsr #10 + beq ma_setup_inner_loop_skip4 + sub r0,r0,r4,lsl #10 + add r4,r4,r10,lsl #4 + subs r8,r8,#0x100 + movlt r8,#0x200 + add r4,r4,r8,lsl #4 + str r4,[r12],#4 +ma_setup_inner_loop_skip4: + add r9,r8,r9,lsl #8 + + @ Write merge: (skips if unnecessary) + subs r7,r8,#0x100 + movlt r7,#0x200 + bic r4,r9,#0x00ff0000 + cmp r4,r11 + addne r11,r3,r4,lsr #8 + addne r11,r11,r7,lsl #4 + strne r11,[r12],#4 + + @ Write mul/mla/mov/add: + add r4,r14,r7,lsr #8 + str r4,[r12],#4 + add r14,r14,r5,lsl #12 + + subs r10,r10,#0x10000000 + bge ma_setup_outer_loop + + + @ Calculate iterations until end of sample: + ldr r10,[r1,#8-20] @ pos + ldr r0,[r1,#12-20] @ end + sub r0,r0,r10 + mov r5,r5,lsr #19 + ldr r8,_ma_divide_table + ldrh r5,[r8,r5] + mul r0,r5,r0 + cmp r2,r0,lsr #10 + movhi r2,r0,lsr #10 + + add r6,r6,#0x01000000 @ increment active channels found + +ma_skip: + subs r6,r6,#0x10000000 + bge ma_setup_loop + + @ Write "b ma_again" +_AAS_MixAudio_mod3: + adr r0,ma_again + sub r0,r0,r12 + mov r0,r0,asr #2 + sub r0,r0,#2 + @bic r0,r0,#0xff000000 + @add r0,r0,#0xea000000 + adr r4,ma_buffer_end + bic r0,r0,#0x15000000 @ offset always negative, so this is equivalent to above + str r0,[r12],#4 + + sub r10,r4,r12 + and r4,r6,#0x0f000000 + sub r10,r10,r4,lsr #21 @ r10 -= 8*used_channels + @str r10,_ma_iterations_scale_buffer + @str r10,[sp,#20] + str r10,_ma_bytes_available + + ldr r11,[sp,#8] + subs r9,r2,r11 + str r9,_ma_total_iterations + @cmp r2,r11 + mov r9,#1 + movhi r9,#0 + str r9,_ma_no_skip + movhi r2,r11 + + mov r11,r2 + mov r9,r2 + bic r2,r6,#0xff000000 + str r2,_ma_total_delta + + @ r2 = total_delta>>2 + @ r9 = r11 = total_iterations - i.e. iterations until loop - argh! need to recalculate each call! + @ r10 = ((bytes_available-(8*channels_used))<<4) + + @ Could remove need to recalc total_iterations each call by not doing "total_iterations = min( iterations, total_iterations )" - do min below instead and sub "iterations" from "total_iterations" afterwards. Problem: Need to accurately calculate "total_iterations" even when it is large. (Although only need to cope with total_iterations being twice as large as it is now because only ever re-use config once.) + +ma_quickstart: + @ldr r4,_ma_mix_buffer + ldr r4,[sp] + + + @ r1 = &_ma_mix_buffer + @ r2 = total_delta>>2 + @ r3 = refill iterations<<3 + @ r4 = _ma_mix_buffer + @ r5 = temp + @ r6 = temp + @ r7 = temp + @ r8 = #0x04000000 + @ r9 = total iterations + @ r10 = ((bytes_available-(8*channels_used))<<4) + @ r11 = total iterations + @ r12 = temp + @ r14 = dest + + @ Calc iterations + @ iterations = ((bytes_available-(8*channels_used))<<4)/(total_delta>>2) + ldr r3,_ma_divide_table +ma_begin: @ called from process loop + mov r2,r2,lsl #1 + ldrh r3,[r3,r2] + mul r3,r10,r3 + @str r3,_ma_iterations_buffer + str r3,[sp,#16] +ma_begin2: + cmp r9,r3,lsr #12 @ was asr #3 + movgt r9,r3,lsr #12 @ was asr #3 + + sub r3,r11,r9 + @str r3,_ma_iterations_loop + str r3,[sp,#12] + + cmp r9,#0 + ble ma_end + + + @ r0 = temp + @ r1 = temp + @ r2 = 0xc0 + @ r3 = chans + @ r4 = _ma_mix_buffer + @ r5 = DMA address + @ r6 = 2 + @ r7 = temp + @ r8 = &_ma_chan_cache + @ r9 = iterations + @ r10 = loop counter + @ r11 = temp + @ r12 = buffer address + @ r14 = temp + + @ Fill buffer + adr r8,_ma_chan_cache + mov r5,#0x04000000 + add r5,r5,#0xd4 + mov r6,#2 +_AAS_MixAudio_mod6: + mov r10,#8 @ was #4 - could perhaps set according to max # of channels / 2? + mov r2,#0xc0 + adr r12,ma_buffer_end + @ldr r3,_ma_chans + ldr r3,[sp,#4] + +ma_fill_buffer_loop: + ldrb r14,[r3],#20 @ effective_volume + cmp r14,#0 + beq ma_fill_buffer_skip + ldr r7,[r3,#8-20] @ pos + bic r0,r7,#0x3 + ldrb r11,[r3,#3-20] @ pos_fraction + and r1,r2,r7,lsl #6 + add r1,r1,r11,lsr #2 + ldrh r14,[r3,#6-20] @ delta + mul r14,r9,r14 + add r11,r11,r14,lsl #2 + strb r11,[r3,#3-20] @ pos_fraction + add r7,r7,r11,lsr #8 + str r7,[r3,#8-20] @ pos + add r7,r6,r14,lsr #8 @ words to copy + sub r12,r12,r7,lsl #2 + add r1,r1,r12,lsl #6 + str r1,[r8],#4 @ IWRAM pos + add r14,r7,#0x84000000 + stmia r5,{r0,r12,r14} +ma_fill_buffer_skip: + subs r10,r10,#1 + bgt ma_fill_buffer_loop + + @ Setup registers for main loop + @ldr r3,_ma_to_go + ldr r3,[sp,#8] + sub r3,r3,r9 + @str r3,_ma_to_go + str r3,[sp,#8] + + @ Setup registers for main loop + @mvn r14,#0xff00 + @add r14,r14,r9,lsl #24 + mvn r14,#0xff00 + bic r14,r14,#0x1000000 + add r14,r14,r9,lsl #25 +_AAS_MixAudio_mod2: + b ma_start + +ma_end: + @ldr r9,_ma_iterations_loop + ldr r9,[sp,#12] + movs r11,r9 + @ldrne r3,_ma_iterations_buffer + ldrne r3,[sp,#16] + bne ma_begin2 + + @ldr r1,_ma_chans + ldr r1,[sp,#4] + @ should be after ble below? + + @ldr r9,_ma_to_go + ldr r9,[sp,#8] + cmp r9,#0 + ldrle r3,_ma_no_skip + cmple r3,#0 + ble ma_chan_finished + + @ change so only branch if done all iterations and no samples have ended + + @ r0 = redo setup + @ r1 = chans[] (was loop) + @ r2 = total_delta>>2 + @ r3 = divide_table + @ r4 = _ma_mix_buffer + @ r5 = temp + @ r6 = delta + @ r7 = end + @ r8 = unused + @ r9 = loops to go + @ r10 = _ma_specific_first + @ r11 = &ma_chan0_start + @ r12 = temp + @ r13 = unused + @ r14 = loop (was chans[]) + + ldr r3,_ma_divide_table +_AAS_MixAudio_mod7: + mov r14,#8 @ was #4 + mov r2,#0 + mov r0,#0 + +ma_check_chan_loop: + ldrb r7,[r1],#20 + cmp r7,#0 + beq ma_chan_done + + ldrh r7,[r1,#6-20] @ delta + ldr r12,[r1,#8-20] @ pos + ldr r6,[r1,#12-20] @ end + sub r5,r6,r7,lsr #6 + sub r5,r5,#1 + cmp r5,r12 + ble ma_chan_do_loop + +ma_chan_ok: + add r2,r2,r7,lsr #2 + sub r5,r6,r12 + mov r7,r7,lsl #1 + ldrh r7,[r3,r7] + mul r5,r7,r5 + cmp r9,r5,lsr #10 + movhi r9,r5,lsr #10 + +ma_chan_done: + subs r14,r14,#1 + bgt ma_check_chan_loop + + cmp r0,#0 + bne ma_chan_has_finished + + movs r11,r9 + @ldrgt r10,_ma_iterations_scale_buffer + @ldrgt r10,[sp,#20] + ldrgt r10,_ma_bytes_available + bgt ma_begin + +ma_chan_finished: + add sp,sp,#28 + ldmfd sp!, {r4-r11, r14} + bx lr @ Thumb interwork friendly. + +ma_chan_has_finished: + cmp r2,#0 + beq ma_chan_all_zeroes + @ldr r2,_ma_to_go + @ldr r2,[sp,#8] +_AAS_MixAudio_mod8: + sub r1,r1,#(20*8) @ was #(20*4) + @str r4,_ma_mix_buffer + str r4,[sp] + b ma_do_setup + +ma_chan_all_zeroes: @ very rare - only happens if last active channel finished during this period + @ldr r5,_ma_to_go + ldr r5,[sp,#8] @ can be 0 sometimes + movs r5,r5,lsl #2 + add r5,r5,#0x85000000 + adr r2,_ma_empty + mov r6,#0x04000000 + add r6,r6,#0xd4 + stmneia r6,{r2,r4,r5} @ r5(_ma_to_go) can be 0 sometimes + b ma_chan_finished + + + +ma_chan_do_loop: + ldr r5,[r1,#16-20] @ loop_length + cmp r5,#0 + + mov r0,#1 @ redo setup !!moved!! + + @ Loop sample + subne r12,r12,r5 + strne r12,[r1,#8-20] @ pos + bne ma_chan_ok + + @ Set inactive + strh r5,[r1,#0-20] @ effective_volume + active + @mov r0,#1 @ redo setup !!was here!! + b ma_chan_done + + +_ma_chan_cache: + .word 0,0,0,0,0,0,0,0 @ IWRAM pos, chan: 0,1,2,3,4,5,6,7 + +_ma_divide_table: .word AAS_DivTable + +_ma_empty: .word 0 +.word 0,0 @ padding + +_AAS_MixAudio_mod4: + + @ r0-r2 : temp + @ r3 : volume + @ r4 : output address + @ r5-r12 : output buffer + @ r14 : sample address/loop/mask + +ma_again: + + @ r0 = temp + @ r1 = temp2 + @ r2 = mask_0x80808080 + @@ r3 free + + @ Make sure algo is as efficient as possible + + @ Merge + @ldr r14,_ma_loop_counter + ldr r14,[sp,#24] + and r5,r14,r5,lsr #8 + and r6,r14,r6,lsr #8 + and r7,r14,r7,lsr #8 + and r8,r14,r8,lsr #8 + and r9,r14,r9,lsr #8 + and r10,r14,r10,lsr #8 + and r11,r14,r11,lsr #8 + and r12,r14,r12,lsr #8 + add r5,r5,r6,lsl #8 + add r6,r7,r8,lsl #8 + add r7,r9,r10,lsl #8 + add r8,r11,r12,lsl #8 + + @ Store + stmia r4!,{r5-r8} + + @ Loop + subs r14,r14,#0x2000000 + ble ma_end + +ma_start: + @str r14,_ma_loop_counter + str r14,[sp,#24] + +ma_buffer_start: @ 2048 bytes (1152 bytes would be equivalent to previous cache size) + + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @ 128 bytes + +ma_buffer_end: diff --git a/lib/apex-audio-system/src/aas/AAS_SFX.c b/lib/apex-audio-system/src/aas/AAS_SFX.c new file mode 100644 index 0000000..e5e2448 --- /dev/null +++ b/lib/apex-audio-system/src/aas/AAS_SFX.c @@ -0,0 +1,284 @@ +// Copyright (c) 2003-2021 James Daniels +// Distributed under the MIT License +// license terms: see LICENSE file in root or http://opensource.org/licenses/MIT + +#include "AAS_Shared.h" + +int AAS_SFX_GetNumChannels() +{ + if ( AAS_initialised ) + { + if ( AAS_volscale == 9 ) + return 16-AAS_MOD_GetNumChannels(); + else if ( AAS_volscale == 8 ) + return 8-AAS_MOD_GetNumChannels(); + else + return 4-AAS_MOD_GetNumChannels(); + } + else + { + return 0; + } +} + +struct AAS_Channel* AAS_SFX_GetChannel( int channel ) +{ + if ( AAS_volscale == 9 ) + return &AAS_channels[AAS_chan_rearrange[15-channel]]; + else if ( AAS_volscale == 8 ) + return &AAS_channels[AAS_chan_rearrange[7-channel]]; + else + return &AAS_channels[AAS_chan_rearrange[3-channel]]; +} + +int AAS_SFX_GetOutput( int channel ) +{ + if ( AAS_volscale == 9 ) + return AAS_chan_rearrange[15-channel]>>3; + else if ( AAS_volscale == 8 ) + return AAS_chan_rearrange[7-channel]>>3; + else + return AAS_chan_rearrange[3-channel]>>3; +} + +AAS_BOOL AAS_SFX_ChannelExists( int channel ) +{ + if ( (channel >= 0) && (channel < AAS_SFX_GetNumChannels()) ) + { + return AAS_TRUE; + } + else + { + return AAS_FALSE; + } +} + +int AAS_SFX_Play( int channel, int sample_volume, int sample_frequency, const AAS_s8* sample_start, const AAS_s8* sample_end, const AAS_s8* sample_restart ) +{ + if ( AAS_initialised ) + { + if ( AAS_SFX_ChannelExists( channel ) ) + { + if ( (sample_frequency >= 1) && (sample_frequency <= 65535) ) + { + if ( (sample_volume >= 0) && (sample_volume <= 64) ) + { + if ( sample_start && (sample_end > sample_start) && (sample_restart < sample_end) ) + { + struct AAS_Channel* ch; + + ch = AAS_SFX_GetChannel( channel ); + ch->active = AAS_FALSE; + ch->volume = (sample_volume<<8)>>AAS_volscale; + ch->frequency = sample_frequency; + ch->delta = AAS_Min( 4095, ((sample_frequency*AAS_mix_scale)+32768)>>16 ); + ch->pos = sample_start; + ch->pos_fraction = 0; + if ( sample_restart ) + ch->loop_length = sample_end - sample_restart; + else + ch->loop_length = 0; + ch->end = sample_end; + ch->active = AAS_TRUE; + + AAS_changed[AAS_SFX_GetOutput(channel)] = AAS_TRUE; + + return AAS_OK; + } + else + { + return AAS_ERROR_INVALID_SAMPLE_ADDRESS; + } + } + else + { + return AAS_ERROR_VOLUME_OUT_OF_RANGE; + } + } + else + { + return AAS_ERROR_FREQUENCY_OUT_OF_RANGE; + } + } + else + { + return AAS_ERROR_CHANNEL_NOT_AVAILABLE; + } + } + else + { + return AAS_ERROR_CALL_SET_CONFIG_FIRST; + } +} + +AAS_BOOL AAS_SFX_IsActive( int channel ) +{ + if ( AAS_SFX_ChannelExists( channel ) ) + { + return AAS_SFX_GetChannel( channel )->active; + } + else + { + return AAS_FALSE; + } +} + +int AAS_SFX_EndLoop( int channel ) +{ + if ( AAS_initialised ) + { + if ( AAS_SFX_ChannelExists( channel ) ) + { + AAS_SFX_GetChannel( channel )->loop_length = 0; + + return AAS_OK; + } + else + { + return AAS_ERROR_CHANNEL_NOT_AVAILABLE; + } + } + else + { + return AAS_ERROR_CALL_SET_CONFIG_FIRST; + } +} + +int AAS_SFX_SetFrequency( int channel, int sample_frequency ) +{ + if ( AAS_initialised ) + { + if ( AAS_SFX_ChannelExists( channel ) ) + { + if ( (sample_frequency >= 1) && (sample_frequency <= 65535) ) + { + struct AAS_Channel* ch; + + ch = AAS_SFX_GetChannel( channel ); + ch->frequency = sample_frequency; + ch->delta = AAS_Min( 4095, ((sample_frequency*AAS_mix_scale)+32768)>>16 ); + + AAS_changed[AAS_SFX_GetOutput(channel)] = AAS_TRUE; + + return AAS_OK; + } + else + { + return AAS_ERROR_FREQUENCY_OUT_OF_RANGE; + } + } + else + { + return AAS_ERROR_CHANNEL_NOT_AVAILABLE; + } + } + else + { + return AAS_ERROR_CALL_SET_CONFIG_FIRST; + } +} + +int AAS_SFX_SetVolume( int channel, int sample_volume ) +{ + if ( AAS_initialised ) + { + if ( AAS_SFX_ChannelExists( channel ) ) + { + if ( (sample_volume >= 0) && (sample_volume <= 64) ) + { + AAS_SFX_GetChannel( channel )->volume = (sample_volume<<8)>>AAS_volscale; + + AAS_changed[AAS_SFX_GetOutput(channel)] = AAS_TRUE; + + return AAS_OK; + } + else + { + return AAS_ERROR_VOLUME_OUT_OF_RANGE; + } + } + else + { + return AAS_ERROR_CHANNEL_NOT_AVAILABLE; + } + } + else + { + return AAS_ERROR_CALL_SET_CONFIG_FIRST; + } +} + +int AAS_SFX_Stop( int channel ) +{ + if ( AAS_initialised ) + { + if ( AAS_SFX_ChannelExists( channel ) ) + { + AAS_SFX_GetChannel( channel )->active = AAS_FALSE; + + AAS_changed[AAS_SFX_GetOutput(channel)] = AAS_TRUE; + + return AAS_OK; + } + else + { + return AAS_ERROR_CHANNEL_NOT_AVAILABLE; + } + } + else + { + return AAS_ERROR_CALL_SET_CONFIG_FIRST; + } +} + +int AAS_SFX_Resume( int channel ) +{ + if ( AAS_initialised ) + { + if ( AAS_SFX_ChannelExists( channel ) ) + { + struct AAS_Channel* ch; + + ch = AAS_SFX_GetChannel( channel ); + + if ( !ch->active ) + { + if ( ch->loop_length ) + { + ch->active = AAS_TRUE; + + AAS_changed[AAS_SFX_GetOutput(channel)] = AAS_TRUE; + + return AAS_OK; + } + else + { + if ( ch->pos < ((ch->end - (ch->delta>>6)) - 1) ) + { + ch->active = AAS_TRUE; + + AAS_changed[AAS_SFX_GetOutput(channel)] = AAS_TRUE; + + return AAS_OK; + } + else + { + return AAS_ERROR_CHANNEL_UNRESUMEABLE; + } + } + } + else + { + return AAS_ERROR_CHANNEL_ACTIVE; + } + } + else + { + return AAS_ERROR_CHANNEL_NOT_AVAILABLE; + } + } + else + { + return AAS_ERROR_CALL_SET_CONFIG_FIRST; + } +} diff --git a/lib/apex-audio-system/src/aas/AAS_Shared.c b/lib/apex-audio-system/src/aas/AAS_Shared.c new file mode 100644 index 0000000..6c1d40c --- /dev/null +++ b/lib/apex-audio-system/src/aas/AAS_Shared.c @@ -0,0 +1,126 @@ +// Copyright (c) 2003-2021 James Daniels +// Distributed under the MIT License +// license terms: see LICENSE file in root or http://opensource.org/licenses/MIT + +#include "AAS_Shared.h" + +const AAS_u16 AAS_DivTable[8192] = { 65535, 65535, 32768, 21845, 16384, 13107, 10922, 9362, 8192, 7281, 6553, 5957, 5461, 5041, 4681, 4369, 4096, 3855, 3640, 3449, 3276, 3120, 2978, 2849, 2730, 2621, 2520, 2427, 2340, 2259, 2184, 2114, 2048, 1985, 1927, 1872, 1820, 1771, 1724, 1680, 1638, 1598, 1560, 1524, 1489, 1456, 1424, 1394, 1365, 1337, 1310, 1285, 1260, 1236, 1213, 1191, 1170, 1149, 1129, 1110, 1092, 1074, 1057, 1040, 1024, 1008, 992, 978, 963, 949, 936, 923, 910, 897, 885, 873, 862, 851, 840, 829, 819, 809, 799, 789, 780, 771, 762, 753, 744, 736, 728, 720, 712, 704, 697, 689, 682, 675, 668, 661, 655, 648, 642, 636, 630, 624, 618, 612, 606, 601, 595, 590, 585, 579, 574, 569, 564, 560, 555, 550, 546, 541, 537, 532, 528, 524, 520, 516, 512, 508, 504, 500, 496, 492, 489, 485, 481, 478, 474, 471, 468, 464, 461, 458, 455, 451, 448, 445, 442, 439, 436, 434, 431, 428, 425, 422, 420, 417, 414, 412, 409, 407, 404, 402, 399, 397, 394, 392, 390, 387, 385, 383, 381, 378, 376, 374, 372, 370, 368, 366, 364, 362, 360, 358, 356, 354, 352, 350, 348, 346, 344, 343, 341, 339, 337, 336, 334, 332, 330, 329, 327, 326, 324, 322, 321, 319, 318, 316, 315, 313, 312, 310, 309, 307, 306, 304, 303, 302, 300, 299, 297, 296, 295, 293, 292, 291, 289, 288, 287, 286, 284, 283, 282, 281, 280, 278, 277, 276, 275, 274, 273, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260, 259, 258, 257, 256, 255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 240, 239, 238, 237, 236, 235, 234, 234, 233, 232, 231, 230, 229, 229, 228, 227, 226, 225, 225, 224, 223, 222, 222, 221, 220, 219, 219, 218, 217, 217, 216, 215, 214, 214, 213, 212, 212, 211, 210, 210, 209, 208, 208, 207, 206, 206, 205, 204, 204, 203, 202, 202, 201, 201, 200, 199, 199, 198, 197, 197, 196, 196, 195, 195, 194, 193, 193, 192, 192, 191, 191, 190, 189, 189, 188, 188, 187, 187, 186, 186, 185, 185, 184, 184, 183, 183, 182, 182, 181, 181, 180, 180, 179, 179, 178, 178, 177, 177, 176, 176, 175, 175, 174, 174, 173, 173, 172, 172, 172, 171, 171, 170, 170, 169, 169, 168, 168, 168, 167, 167, 166, 166, 165, 165, 165, 164, 164, 163, 163, 163, 162, 162, 161, 161, 161, 160, 160, 159, 159, 159, 158, 158, 157, 157, 157, 156, 156, 156, 155, 155, 154, 154, 154, 153, 153, 153, 152, 152, 152, 151, 151, 151, 150, 150, 149, 149, 149, 148, 148, 148, 147, 147, 147, 146, 146, 146, 145, 145, 145, 144, 144, 144, 144, 143, 143, 143, 142, 142, 142, 141, 141, 141, 140, 140, 140, 140, 139, 139, 139, 138, 138, 138, 137, 137, 137, 137, 136, 136, 136, 135, 135, 135, 135, 134, 134, 134, 134, 133, 133, 133, 132, 132, 132, 132, 131, 131, 131, 131, 130, 130, 130, 130, 129, 129, 129, 129, 128, 128, 128, 128, 127, 127, 127, 127, 126, 126, 126, 126, 125, 125, 125, 125, 124, 124, 124, 124, 123, 123, 123, 123, 122, 122, 122, 122, 122, 121, 121, 121, 121, 120, 120, 120, 120, 120, 119, 119, 119, 119, 118, 118, 118, 118, 118, 117, 117, 117, 117, 117, 116, 116, 116, 116, 115, 115, 115, 115, 115, 114, 114, 114, 114, 114, 113, 113, 113, 113, 113, 112, 112, 112, 112, 112, 112, 111, 111, 111, 111, 111, 110, 110, 110, 110, 110, 109, 109, 109, 109, 109, 109, 108, 108, 108, 108, 108, 107, 107, 107, 107, 107, 107, 106, 106, 106, 106, 106, 106, 105, 105, 105, 105, 105, 105, 104, 104, 104, 104, 104, 104, 103, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 101, 101, 101, 101, 101, 101, 100, 100, 100, 100, 100, 100, 100, 99, 99, 99, 99, 99, 99, 98, 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 96, 96, 96, 96, 96, 96, 96, 95, 95, 95, 95, 95, 95, 95, 94, 94, 94, 94, 94, 94, 94, 94, 93, 93, 93, 93, 93, 93, 93, 92, 92, 92, 92, 92, 92, 92, 92, 91, 91, 91, 91, 91, 91, 91, 91, 90, 90, 90, 90, 90, 90, 90, 90, 89, 89, 89, 89, 89, 89, 89, 89, 88, 88, 88, 88, 88, 88, 88, 88, 87, 87, 87, 87, 87, 87, 87, 87, 87, 86, 86, 86, 86, 86, 86, 86, 86, 86, 85, 85, 85, 85, 85, 85, 85, 85, 85, 84, 84, 84, 84, 84, 84, 84, 84, 84, 83, 83, 83, 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; + +const AAS_u16 AAS_MOD_period_conv_table[2048] = { 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 64488, 63337, 62226, 61153, 60116, 59114, 58145, 57207, 56299, 55420, 54567, 53740, 52938, 52160, 51404, 50669, 49956, 49262, 48587, 47931, 47291, 46669, 46063, 45473, 44897, 44336, 43788, 43254, 42733, 42224, 41728, 41242, 40768, 40305, 39852, 39409, 38976, 38553, 38138, 37732, 37335, 36946, 36565, 36192, 35827, 35468, 35117, 34773, 34435, 34104, 33779, 33461, 33148, 32841, 32540, 32244, 31954, 31668, 31388, 31113, 30842, 30576, 30315, 30058, 29805, 29557, 29313, 29072, 28836, 28603, 28375, 28149, 27928, 27710, 27495, 27283, 27075, 26870, 26668, 26469, 26273, 26080, 25889, 25702, 25517, 25334, 25155, 24978, 24803, 24631, 24461, 24293, 24128, 23965, 23804, 23645, 23489, 23334, 23182, 23031, 22883, 22736, 22591, 22448, 22307, 22168, 22030, 21894, 21760, 21627, 21496, 21366, 21238, 21112, 20987, 20864, 20742, 20621, 20502, 20384, 20267, 20152, 20038, 19926, 19815, 19704, 19596, 19488, 19381, 19276, 19172, 19069, 18967, 18866, 18766, 18667, 18570, 18473, 18377, 18282, 18189, 18096, 18004, 17913, 17823, 17734, 17646, 17558, 17472, 17386, 17301, 17217, 17134, 17052, 16970, 16889, 16809, 16730, 16652, 16574, 16497, 16420, 16345, 16270, 16195, 16122, 16049, 15977, 15905, 15834, 15763, 15694, 15625, 15556, 15488, 15421, 15354, 15288, 15222, 15157, 15093, 15029, 14965, 14902, 14840, 14778, 14717, 14656, 14596, 14536, 14477, 14418, 14359, 14301, 14244, 14187, 14131, 14074, 14019, 13964, 13909, 13855, 13801, 13747, 13694, 13641, 13589, 13537, 13486, 13435, 13384, 13334, 13284, 13234, 13185, 13136, 13088, 13040, 12992, 12944, 12897, 12851, 12804, 12758, 12712, 12667, 12622, 12577, 12533, 12489, 12445, 12401, 12358, 12315, 12272, 12230, 12188, 12146, 12105, 12064, 12023, 11982, 11942, 11902, 11862, 11822, 11783, 11744, 11705, 11667, 11629, 11591, 11553, 11515, 11478, 11441, 11404, 11368, 11331, 11295, 11259, 11224, 11188, 11153, 11118, 11084, 11049, 11015, 10981, 10947, 10913, 10880, 10846, 10813, 10780, 10748, 10715, 10683, 10651, 10619, 10587, 10556, 10524, 10493, 10462, 10432, 10401, 10371, 10340, 10310, 10280, 10251, 10221, 10192, 10163, 10133, 10105, 10076, 10047, 10019, 9991, 9963, 9935, 9907, 9879, 9852, 9825, 9798, 9771, 9744, 9717, 9690, 9664, 9638, 9612, 9586, 9560, 9534, 9509, 9483, 9458, 9433, 9408, 9383, 9358, 9333, 9309, 9285, 9260, 9236, 9212, 9188, 9165, 9141, 9117, 9094, 9071, 9048, 9025, 9002, 8979, 8956, 8934, 8911, 8889, 8867, 8845, 8823, 8801, 8779, 8757, 8736, 8714, 8693, 8672, 8650, 8629, 8608, 8588, 8567, 8546, 8526, 8505, 8485, 8465, 8444, 8424, 8404, 8385, 8365, 8345, 8326, 8306, 8287, 8267, 8248, 8229, 8210, 8191, 8172, 8153, 8135, 8116, 8097, 8079, 8061, 8042, 8024, 8006, 7988, 7970, 7952, 7934, 7917, 7899, 7881, 7864, 7847, 7829, 7812, 7795, 7778, 7761, 7744, 7727, 7710, 7693, 7677, 7660, 7644, 7627, 7611, 7595, 7578, 7562, 7546, 7530, 7514, 7498, 7482, 7467, 7451, 7435, 7420, 7404, 7389, 7374, 7358, 7343, 7328, 7313, 7298, 7283, 7268, 7253, 7238, 7223, 7209, 7194, 7179, 7165, 7150, 7136, 7122, 7108, 7093, 7079, 7065, 7051, 7037, 7023, 7009, 6995, 6982, 6968, 6954, 6941, 6927, 6914, 6900, 6887, 6873, 6860, 6847, 6834, 6820, 6807, 6794, 6781, 6768, 6755, 6743, 6730, 6717, 6704, 6692, 6679, 6667, 6654, 6642, 6629, 6617, 6605, 6592, 6580, 6568, 6556, 6544, 6532, 6520, 6508, 6496, 6484, 6472, 6460, 6448, 6437, 6425, 6413, 6402, 6390, 6379, 6367, 6356, 6345, 6333, 6322, 6311, 6299, 6288, 6277, 6266, 6255, 6244, 6233, 6222, 6211, 6200, 6190, 6179, 6168, 6157, 6147, 6136, 6125, 6115, 6104, 6094, 6083, 6073, 6063, 6052, 6042, 6032, 6021, 6011, 6001, 5991, 5981, 5971, 5961, 5951, 5941, 5931, 5921, 5911, 5901, 5891, 5882, 5872, 5862, 5852, 5843, 5833, 5824, 5814, 5805, 5795, 5786, 5776, 5767, 5757, 5748, 5739, 5730, 5720, 5711, 5702, 5693, 5684, 5675, 5665, 5656, 5647, 5638, 5629, 5621, 5612, 5603, 5594, 5585, 5576, 5568, 5559, 5550, 5542, 5533, 5524, 5516, 5507, 5499, 5490, 5482, 5473, 5465, 5456, 5448, 5440, 5431, 5423, 5415, 5406, 5398, 5390, 5382, 5374, 5365, 5357, 5349, 5341, 5333, 5325, 5317, 5309, 5301, 5293, 5285, 5278, 5270, 5262, 5254, 5246, 5239, 5231, 5223, 5216, 5208, 5200, 5193, 5185, 5177, 5170, 5162, 5155, 5147, 5140, 5132, 5125, 5118, 5110, 5103, 5096, 5088, 5081, 5074, 5066, 5059, 5052, 5045, 5038, 5031, 5023, 5016, 5009, 5002, 4995, 4988, 4981, 4974, 4967, 4960, 4953, 4946, 4939, 4933, 4926, 4919, 4912, 4905, 4899, 4892, 4885, 4878, 4872, 4865, 4858, 4852, 4845, 4838, 4832, 4825, 4819, 4812, 4806, 4799, 4793, 4786, 4780, 4773, 4767, 4760, 4754, 4748, 4741, 4735, 4729, 4722, 4716, 4710, 4704, 4697, 4691, 4685, 4679, 4673, 4666, 4660, 4654, 4648, 4642, 4636, 4630, 4624, 4618, 4612, 4606, 4600, 4594, 4588, 4582, 4576, 4570, 4564, 4558, 4553, 4547, 4541, 4535, 4529, 4524, 4518, 4512, 4506, 4501, 4495, 4489, 4484, 4478, 4472, 4467, 4461, 4455, 4450, 4444, 4439, 4433, 4428, 4422, 4417, 4411, 4406, 4400, 4395, 4389, 4384, 4378, 4373, 4368, 4362, 4357, 4352, 4346, 4341, 4336, 4330, 4325, 4320, 4314, 4309, 4304, 4299, 4294, 4288, 4283, 4278, 4273, 4268, 4263, 4257, 4252, 4247, 4242, 4237, 4232, 4227, 4222, 4217, 4212, 4207, 4202, 4197, 4192, 4187, 4182, 4177, 4172, 4167, 4163, 4158, 4153, 4148, 4143, 4138, 4133, 4129, 4124, 4119, 4114, 4109, 4105, 4100, 4095, 4090, 4086, 4081, 4076, 4072, 4067, 4062, 4058, 4053, 4048, 4044, 4039, 4035, 4030, 4025, 4021, 4016, 4012, 4007, 4003, 3998, 3994, 3989, 3985, 3980, 3976, 3971, 3967, 3963, 3958, 3954, 3949, 3945, 3940, 3936, 3932, 3927, 3923, 3919, 3914, 3910, 3906, 3901, 3897, 3893, 3889, 3884, 3880, 3876, 3872, 3867, 3863, 3859, 3855, 3851, 3846, 3842, 3838, 3834, 3830, 3826, 3822, 3817, 3813, 3809, 3805, 3801, 3797, 3793, 3789, 3785, 3781, 3777, 3773, 3769, 3765, 3761, 3757, 3753, 3749, 3745, 3741, 3737, 3733, 3729, 3725, 3721, 3717, 3714, 3710, 3706, 3702, 3698, 3694, 3690, 3687, 3683, 3679, 3675, 3671, 3667, 3664, 3660, 3656, 3652, 3649, 3645, 3641, 3637, 3634, 3630, 3626, 3622, 3619, 3615, 3611, 3608, 3604, 3600, 3597, 3593, 3589, 3586, 3582, 3579, 3575, 3571, 3568, 3564, 3561, 3557, 3554, 3550, 3546, 3543, 3539, 3536, 3532, 3529, 3525, 3522, 3518, 3515, 3511, 3508, 3504, 3501, 3497, 3494, 3491, 3487, 3484, 3480, 3477, 3473, 3470, 3467, 3463, 3460, 3457, 3453, 3450, 3446, 3443, 3440, 3436, 3433, 3430, 3426, 3423, 3420, 3417, 3413, 3410, 3407, 3403, 3400, 3397, 3394, 3390, 3387, 3384, 3381, 3377, 3374, 3371, 3368, 3365, 3361, 3358, 3355, 3352, 3349, 3346, 3342, 3339, 3336, 3333, 3330, 3327, 3324, 3321, 3317, 3314, 3311, 3308, 3305, 3302, 3299, 3296, 3293, 3290, 3287, 3284, 3281, 3278, 3275, 3272, 3269, 3266, 3263, 3260, 3257, 3254, 3251, 3248, 3245, 3242, 3239, 3236, 3233, 3230, 3227, 3224, 3221, 3218, 3215, 3212, 3209, 3206, 3204, 3201, 3198, 3195, 3192, 3189, 3186, 3183, 3181, 3178, 3175, 3172, 3169, 3166, 3164, 3161, 3158, 3155, 3152, 3149, 3147, 3144, 3141, 3138, 3136, 3133, 3130, 3127, 3125, 3122, 3119, 3116, 3114, 3111, 3108, 3105, 3103, 3100, 3097, 3095, 3092, 3089, 3086, 3084, 3081, 3078, 3076, 3073, 3070, 3068, 3065, 3062, 3060, 3057, 3055, 3052, 3049, 3047, 3044, 3041, 3039, 3036, 3034, 3031, 3028, 3026, 3023, 3021, 3018, 3016, 3013, 3010, 3008, 3005, 3003, 3000, 2998, 2995, 2993, 2990, 2988, 2985, 2983, 2980, 2978, 2975, 2973, 2970, 2968, 2965, 2963, 2960, 2958, 2955, 2953, 2950, 2948, 2945, 2943, 2941, 2938, 2936, 2933, 2931, 2928, 2926, 2924, 2921, 2919, 2916, 2914, 2912, 2909, 2907, 2904, 2902, 2900, 2897, 2895, 2893, 2890, 2888, 2886, 2883, 2881, 2878, 2876, 2874, 2871, 2869, 2867, 2865, 2862, 2860, 2858, 2855, 2853, 2851, 2848, 2846, 2844, 2842, 2839, 2837, 2835, 2832, 2830, 2828, 2826, 2823, 2821, 2819, 2817, 2814, 2812, 2810, 2808, 2806, 2803, 2801, 2799, 2797, 2795, 2792, 2790, 2788, 2786, 2784, 2781, 2779, 2777, 2775, 2773, 2771, 2768, 2766, 2764, 2762, 2760, 2758, 2755, 2753, 2751, 2749, 2747, 2745, 2743, 2741, 2738, 2736, 2734, 2732, 2730, 2728, 2726, 2724, 2722, 2720, 2717, 2715, 2713, 2711, 2709, 2707, 2705, 2703, 2701, 2699, 2697, 2695, 2693, 2691, 2689, 2687, 2685, 2682, 2680, 2678, 2676, 2674, 2672, 2670, 2668, 2666, 2664, 2662, 2660, 2658, 2656, 2654, 2652, 2650, 2648, 2646, 2644, 2642, 2641, 2639, 2637, 2635, 2633, 2631, 2629, 2627, 2625, 2623, 2621, 2619, 2617, 2615, 2613, 2611, 2609, 2608, 2606, 2604, 2602, 2600, 2598, 2596, 2594, 2592, 2590, 2588, 2587, 2585, 2583, 2581, 2579, 2577, 2575, 2573, 2572, 2570, 2568, 2566, 2564, 2562, 2560, 2559, 2557, 2555, 2553, 2551, 2549, 2548, 2546, 2544, 2542, 2540, 2538, 2537, 2535, 2533, 2531, 2529, 2528, 2526, 2524, 2522, 2520, 2519, 2517, 2515, 2513, 2511, 2510, 2508, 2506, 2504, 2503, 2501, 2499, 2497, 2496, 2494, 2492, 2490, 2489, 2487, 2485, 2483, 2482, 2480, 2478, 2476, 2475, 2473, 2471, 2469, 2468, 2466, 2464, 2463, 2461, 2459, 2458, 2456, 2454, 2452, 2451, 2449, 2447, 2446, 2444, 2442, 2441, 2439, 2437, 2436, 2434, 2432, 2431, 2429, 2427, 2426, 2424, 2422, 2421, 2419, 2417, 2416, 2414, 2412, 2411, 2409, 2407, 2406, 2404, 2403, 2401, 2399, 2398, 2396, 2394, 2393, 2391, 2390, 2388, 2386, 2385, 2383, 2382, 2380, 2378, 2377, 2375, 2374, 2372, 2370, 2369, 2367, 2366, 2364, 2363, 2361, 2359, 2358, 2356, 2355, 2353, 2352, 2350, 2348, 2347, 2345, 2344, 2342, 2341, 2339, 2338, 2336, 2335, 2333, 2331, 2330, 2328, 2327, 2325, 2324, 2322, 2321, 2319, 2318, 2316, 2315, 2313, 2312, 2310, 2309, 2307, 2306, 2304, 2303, 2301, 2300, 2298, 2297, 2295, 2294, 2292, 2291, 2289, 2288, 2286, 2285, 2283, 2282, 2280, 2279, 2278, 2276, 2275, 2273, 2272, 2270, 2269, 2267, 2266, 2264, 2263, 2262, 2260, 2259, 2257, 2256, 2254, 2253, 2251, 2250, 2249, 2247, 2246, 2244, 2243, 2242, 2240, 2239, 2237, 2236, 2234, 2233, 2232, 2230, 2229, 2227, 2226, 2225, 2223, 2222, 2220, 2219, 2218, 2216, 2215, 2214, 2212, 2211, 2209, 2208, 2207, 2205, 2204, 2203, 2201, 2200, 2198, 2197, 2196, 2194, 2193, 2192, 2190, 2189, 2188, 2186, 2185, 2184, 2182, 2181, 2180, 2178, 2177, 2176, 2174, 2173, 2172, 2170, 2169, 2168, 2166, 2165, 2164, 2162, 2161, 2160, 2158, 2157, 2156, 2154, 2153, 2152, 2150, 2149, 2148, 2147, 2145, 2144, 2143, 2141, 2140, 2139, 2137, 2136, 2135, 2134, 2132, 2131, 2130, 2128, 2127, 2126, 2125, 2123, 2122, 2121, 2120, 2118, 2117, 2116, 2115, 2113, 2112, 2111, 2109, 2108, 2107, 2106, 2104, 2103, 2102, 2101, 2099, 2098, 2097, 2096, 2095, 2093, 2092, 2091, 2090, 2088, 2087, 2086, 2085, 2083, 2082, 2081, 2080, 2079, 2077, 2076, 2075, 2074, 2072, 2071, 2070, 2069, 2068, 2066, 2065, 2064, 2063, 2062, 2060, 2059, 2058, 2057, 2056, 2054, 2053, 2052, 2051, 2050, 2049, 2047, 2046, 2045, 2044, 2043, 2041, 2040, 2039, 2038, 2037, 2036, 2034, 2033, 2032, 2031, 2030, 2029, 2027, 2026, 2025, 2024, 2023, 2022, 2021, 2019, 2018, 2017, 2016, 2015, 2014, 2012, 2011, 2010, 2009, 2008, 2007, 2006, 2005, 2003, 2002, 2001, 2000, 1999, 1998, 1997, 1996, 1994, 1993, 1992, 1991, 1990, 1989, 1988, 1987, 1985, 1984, 1983, 1982, 1981, 1980, 1979, 1978, 1977, 1975, 1974, 1973, 1972, 1971, 1970, 1969, 1968, 1967, 1966, 1965, 1963, 1962, 1961, 1960, 1959, 1958, 1957, 1956, 1955, 1954, 1953, 1952, 1950, 1949, 1948, 1947, 1946, 1945, 1944, 1943, 1942, 1941, 1940, 1939, 1938, 1937, 1936, 1935, 1933, 1932, 1931, 1930, 1929, 1928, 1927, 1926, 1925, 1924, 1923, 1922, 1921, 1920, 1919, 1918, 1917, 1916, 1915, 1914, 1913, 1912, 1911, 1910, 1908, 1907, 1906, 1905, 1904, 1903, 1902, 1901, 1900, 1899, 1898, 1897, 1896, 1895, 1894, 1893, 1892, 1891, 1890, 1889, 1888, 1887, 1886, 1885, 1884, 1883, 1882, 1881, 1880, 1879, 1878, 1877, 1876, 1875, 1874, 1873, 1872, 1871, 1870, 1869, 1868, 1867, 1866, 1865, 1864, 1863, 1862, 1861, 1860, 1859, 1858, 1857, 1857, 1856, 1855, 1854, 1853, 1852, 1851, 1850, 1849, 1848, 1847, 1846, 1845, 1844, 1843, 1842, 1841, 1840, 1839, 1838, 1837, 1836, 1835, 1834, 1833, 1833, 1832, 1831, 1830, 1829, 1828, 1827, 1826, 1825, 1824, 1823, 1822, 1821, 1820, 1819, 1818, 1817, 1817, 1816, 1815, 1814, 1813, 1812, 1811, 1810, 1809, 1808, 1807, 1806, 1805, 1805, 1804, 1803, 1802, 1801, 1800, 1799, 1798, 1797, 1796, 1795, 1794, 1794, 1793, 1792, 1791, 1790, 1789, 1788, 1787, 1786, 1785, 1785, 1784, 1783, 1782, 1781, 1780, 1779, 1778, 1777, 1777, 1776, 1775, 1774, 1773, 1772, 1771, 1770, 1769, 1769, 1768, 1767, 1766, 1765, 1764, 1763, 1762, 1761, 1761, 1760, 1759, 1758, 1757, 1756, 1755, 1755, 1754, 1753, 1752, 1751, 1750, 1749, 1748, 1748, 1747, 1746, 1745, 1744, 1743, 1742, 1742, 1741, 1740, 1739, 1738, 1737, 1736, 1736, 1735, 1734, 1733, 1732 }; + +const AAS_u16 AAS_period_table[16][60] = +{ + { + 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960 , 906, + 856 , 808 , 762 , 720 , 678 , 640 , 604 , 570 , 538 , 508 , 480 , 453, + 428 , 404 , 381 , 360 , 339 , 320 , 302 , 285 , 269 , 254 , 240 , 226, + 214 , 202 , 190 , 180 , 170 , 160 , 151 , 143 , 135 , 127 , 120 , 113, + 107 , 101 , 95 , 90 , 85 , 80 , 75 , 71 , 67 , 63 , 60 , 56 + },{ + 1700, 1604, 1514, 1430, 1348, 1274, 1202, 1134, 1070, 1010, 954 , 900, + 850 , 802 , 757 , 715 , 674 , 637 , 601 , 567 , 535 , 505 , 477 , 450, + 425 , 401 , 379 , 357 , 337 , 318 , 300 , 284 , 268 , 253 , 239 , 225, + 213 , 201 , 189 , 179 , 169 , 159 , 150 , 142 , 134 , 126 , 119 , 113, + 106 , 100 , 94 , 89 , 84 , 79 , 75 , 71 , 67 , 63 , 59 , 56 + },{ + 1688, 1592, 1504, 1418, 1340, 1264, 1194, 1126, 1064, 1004, 948 , 894, + 844 , 796 , 752 , 709 , 670 , 632 , 597 , 563 , 532 , 502 , 474 , 447, + 422 , 398 , 376 , 355 , 335 , 316 , 298 , 282 , 266 , 251 , 237 , 224, + 211 , 199 , 188 , 177 , 167 , 158 , 149 , 141 , 133 , 125 , 118 , 112, + 105 , 99 , 94 , 88 , 83 , 79 , 74 , 70 , 66 , 62 , 59 , 56 + },{ + 1676, 1582, 1492, 1408, 1330, 1256, 1184, 1118, 1056, 996 , 940 , 888, + 838 , 791 , 746 , 704 , 665 , 628 , 592 , 559 , 528 , 498 , 470 , 444, + 419 , 395 , 373 , 352 , 332 , 314 , 296 , 280 , 264 , 249 , 235 , 222, + 209 , 198 , 187 , 176 , 166 , 157 , 148 , 140 , 132 , 125 , 118 , 111, + 104 , 99 , 93 , 88 , 83 , 78 , 74 , 70 , 66 , 62 , 59 , 55 + },{ + 1664, 1570, 1482, 1398, 1320, 1246, 1176, 1110, 1048, 990 , 934 , 882, + 832 , 785 , 741 , 699 , 660 , 623 , 588 , 555 , 524 , 495 , 467 , 441, + 416 , 392 , 370 , 350 , 330 , 312 , 294 , 278 , 262 , 247 , 233 , 220, + 208 , 196 , 185 , 175 , 165 , 156 , 147 , 139 , 131 , 124 , 117 , 110, + 104 , 98 , 92 , 87 , 82 , 78 , 73 , 69 , 65 , 62 , 58 , 55 + },{ + 1652, 1558, 1472, 1388, 1310, 1238, 1168, 1102, 1040, 982 , 926 , 874, + 826 , 779 , 736 , 694 , 655 , 619 , 584 , 551 , 520 , 491 , 463 , 437, + 413 , 390 , 368 , 347 , 328 , 309 , 292 , 276 , 260 , 245 , 232 , 219, + 206 , 195 , 184 , 174 , 164 , 155 , 146 , 138 , 130 , 123 , 116 , 109, + 103 , 97 , 92 , 87 , 82 , 77 , 73 , 69 , 65 , 61 , 58 , 54 + },{ + 1640, 1548, 1460, 1378, 1302, 1228, 1160, 1094, 1032, 974 , 920 , 868, + 820 , 774 , 730 , 689 , 651 , 614 , 580 , 547 , 516 , 487 , 460 , 434, + 410 , 387 , 365 , 345 , 325 , 307 , 290 , 274 , 258 , 244 , 230 , 217, + 205 , 193 , 183 , 172 , 163 , 154 , 145 , 137 , 129 , 122 , 115 , 109, + 102 , 96 , 91 , 86 , 81 , 77 , 72 , 68 , 64 , 61 , 57 , 54 + },{ + 1628, 1536, 1450, 1368, 1292, 1220, 1150, 1086, 1026, 968 , 914 , 862, + 814 , 768 , 725 , 684 , 646 , 610 , 575 , 543 , 513 , 484 , 457 , 431, + 407 , 384 , 363 , 342 , 323 , 305 , 288 , 272 , 256 , 242 , 228 , 216, + 204 , 192 , 181 , 171 , 161 , 152 , 144 , 136 , 128 , 121 , 114 , 108, + 102 , 96 , 90 , 85 , 80 , 76 , 72 , 68 , 64 , 60 , 57 , 54 + },{ + 1814, 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, + 907 , 856 , 808 , 762 , 720 , 678 , 640 , 604 , 570 , 538 , 508 , 480, + 453 , 428 , 404 , 381 , 360 , 339 , 320 , 302 , 285 , 269 , 254 , 240, + 226 , 214 , 202 , 190 , 180 , 170 , 160 , 151 , 143 , 135 , 127 , 120, + 113 , 107 , 101 , 95 , 90 , 85 , 80 , 75 , 71 , 67 , 63 , 60 + },{ + 1800, 1700, 1604, 1514, 1430, 1350, 1272, 1202, 1134, 1070, 1010, 954, + 900 , 850 , 802 , 757 , 715 , 675 , 636 , 601 , 567 , 535 , 505 , 477, + 450 , 425 , 401 , 379 , 357 , 337 , 318 , 300 , 284 , 268 , 253 , 238, + 225 , 212 , 200 , 189 , 179 , 169 , 159 , 150 , 142 , 134 , 126 , 119, + 112 , 106 , 100 , 94 , 89 , 84 , 79 , 75 , 71 , 67 , 63 , 59 + },{ + 1788, 1688, 1592, 1504, 1418, 1340, 1264, 1194, 1126, 1064, 1004, 948, + 894 , 844 , 796 , 752 , 709 , 670 , 632 , 597 , 563 , 532 , 502 , 474, + 447 , 422 , 398 , 376 , 355 , 335 , 316 , 298 , 282 , 266 , 251 , 237, + 223 , 211 , 199 , 188 , 177 , 167 , 158 , 149 , 141 , 133 , 125 , 118, + 111 , 105 , 99 , 94 , 88 , 83 , 79 , 74 , 70 , 66 , 62 , 59 + },{ + 1774, 1676, 1582, 1492, 1408, 1330, 1256, 1184, 1118, 1056, 996 , 940, + 887 , 838 , 791 , 746 , 704 , 665 , 628 , 592 , 559 , 528 , 498 , 470, + 444 , 419 , 395 , 373 , 352 , 332 , 314 , 296 , 280 , 264 , 249 , 235, + 222 , 209 , 198 , 187 , 176 , 166 , 157 , 148 , 140 , 132 , 125 , 118, + 111 , 104 , 99 , 93 , 88 , 83 , 78 , 74 , 70 , 66 , 62 , 59 + },{ + 1762, 1664, 1570, 1482, 1398, 1320, 1246, 1176, 1110, 1048, 988 , 934, + 881 , 832 , 785 , 741 , 699 , 660 , 623 , 588 , 555 , 524 , 494 , 467, + 441 , 416 , 392 , 370 , 350 , 330 , 312 , 294 , 278 , 262 , 247 , 233, + 220 , 208 , 196 , 185 , 175 , 165 , 156 , 147 , 139 , 131 , 123 , 117, + 110 , 104 , 98 , 92 , 87 , 82 , 78 , 73 , 69 , 65 , 61 , 58 + },{ + 1750, 1652, 1558, 1472, 1388, 1310, 1238, 1168, 1102, 1040, 982 , 926, + 875 , 826 , 779 , 736 , 694 , 655 , 619 , 584 , 551 , 520 , 491 , 463, + 437 , 413 , 390 , 368 , 347 , 328 , 309 , 292 , 276 , 260 , 245 , 232, + 219 , 206 , 195 , 184 , 174 , 164 , 155 , 146 , 138 , 130 , 123 , 116, + 109 , 103 , 97 , 92 , 87 , 82 , 77 , 73 , 69 , 65 , 61 , 58 + },{ + 1736, 1640, 1548, 1460, 1378, 1302, 1228, 1160, 1094, 1032, 974 , 920, + 868 , 820 , 774 , 730 , 689 , 651 , 614 , 580 , 547 , 516 , 487 , 460, + 434 , 410 , 387 , 365 , 345 , 325 , 307 , 290 , 274 , 258 , 244 , 230, + 217 , 205 , 193 , 183 , 172 , 163 , 154 , 145 , 137 , 129 , 122 , 115, + 108 , 102 , 96 , 91 , 86 , 81 , 77 , 72 , 68 , 64 , 61 , 57 + },{ + 1724, 1628, 1536, 1450, 1368, 1292, 1220, 1150, 1086, 1026, 968 , 914, + 862 , 814 , 768 , 725 , 684 , 646 , 610 , 575 , 543 , 513 , 484 , 457, + 431 , 407 , 384 , 363 , 342 , 323 , 305 , 288 , 272 , 256 , 242 , 228, + 216 , 203 , 192 , 181 , 171 , 161 , 152 , 144 , 136 , 128 , 121 , 114, + 108 , 101 , 96 , 90 , 85 , 80 , 76 , 72 , 68 , 64 , 60 , 57 + } +}; + +const AAS_u16 AAS_tick_rate[41] = { 65535, 44565, 55051, 58546, 60294, 61342, 62041, 62541, 62915, 63206, 63439, 63630, 63789, 63923, 64039, 64138, 64226, 64303, 64371, 64433, 64488, 64538, 64583, 64625, 64663, 64698, 64730, 64760, 64788, 64813, 64837, 64860, 64881, 64901, 64920, 64937, 64954, 64970, 64985, 64999, 65012 }; + +const AAS_s8 AAS_sin[64] = { 0, -12, -24, -37, -48, -60, -71, -81, -90, -98, -106, -112, -118, -122, -125, -127, -127, -127, -125, -122, -118, -112, -106, -99, -90, -81, -71, -60, -49, -37, -25, -12, 0, 12, 24, 36, 48, 60, 70, 81, 90, 98, 106, 112, 118, 122, 125, 127, 127, 127, 125, 122, 118, 113, 106, 99, 90, 81, 71, 60, 49, 37, 25, 12 }; + +AAS_BOOL AAS_initialised AAS_IN_EWRAM = AAS_FALSE; +AAS_u8 AAS_volscale AAS_IN_EWRAM; +AAS_u16 AAS_mix_scale AAS_IN_EWRAM; +AAS_BOOL AAS_changed[2] AAS_IN_IWRAM; + +AAS_u8 AAS_chan_rearrange[AAS_MAX_CHANNELS] AAS_IN_EWRAM; + +struct AAS_Channel AAS_channels[16] AAS_IN_EWRAM; + +// 2560 bytes, must be aligned to 4 byte boundary, could be just 640 bytes if mix rate was 8KHz +AAS_u32 AAS_mix_buffer[640] AAS_IN_EWRAM; diff --git a/lib/apex-audio-system/src/aas/AAS_Shared.h b/lib/apex-audio-system/src/aas/AAS_Shared.h new file mode 100644 index 0000000..48729e8 --- /dev/null +++ b/lib/apex-audio-system/src/aas/AAS_Shared.h @@ -0,0 +1,83 @@ +// Copyright (c) 2003-2021 James Daniels +// Distributed under the MIT License +// license terms: see LICENSE file in root or http://opensource.org/licenses/MIT + +#ifndef __AAS_SHARED__ +#define __AAS_SHARED__ + +#include "AAS.h" +#include "AAS_Mixer.h" + +#define AAS_MAX_CHANNELS 16 + +#define REG_SOUNDCNT_L (*(volatile AAS_u16 *)0x4000080) +#define REG_SOUNDCNT_H (*(volatile AAS_u16 *)0x4000082) +#define REG_SOUNDCNT_X (*(volatile AAS_u16 *)0x4000084) + +#define REG_DMA1SAD (*(volatile AAS_u32 *)0x40000BC) +#define REG_DMA1DAD (*(volatile AAS_u32 *)0x40000C0) +#define REG_DMA1CNT_H (*(volatile AAS_u16 *)0x40000C6) +#define REG_DMA1CNT (*(volatile AAS_u32 *)0x40000C4) + +#define REG_DMA2SAD (*(volatile AAS_u32 *)0x40000C8) +#define REG_DMA2DAD (*(volatile AAS_u32 *)0x40000CC) +#define REG_DMA2CNT_H (*(volatile AAS_u16 *)0x40000D2) +#define REG_DMA2CNT (*(volatile AAS_u32 *)0x40000d0) + +#define REG_TM0CNT (*(volatile AAS_u16 *)0x4000102) +#define REG_TM0D (*(volatile AAS_u16 *)0x4000100) + +#define REG_TM1CNT (*(volatile AAS_u16 *)0x4000106) +#define REG_TM1D (*(volatile AAS_u16 *)0x4000104) + +#define REG_IE (*(volatile AAS_u16 *)0x4000200) +#define REG_IME (*(volatile AAS_u16 *)0x4000208) +#define REG_IF (*(volatile AAS_u16 *)0x4000202) + +#define DISPCNT (*(volatile AAS_u16 *)0x4000000) +#define REG_VCOUNT (*(volatile AAS_u16 *)0x4000006) + +struct AAS_ModSample +{ + AAS_u32 data; // offset in bytes + AAS_u16 repeat; // in halfwords + AAS_u16 length; // in halfwords + AAS_u8 finetune; + AAS_u8 volume; + AAS_u16 padding; +}; + +extern const AAS_u16 AAS_DATA_NUM_MODS; +extern const struct AAS_ModSample AAS_ModSamples[][31]; +extern const AAS_s16 AAS_Sequence[][128][16]; +extern const AAS_u8 AAS_NumChans[]; +extern const AAS_u8 AAS_RestartPos[]; +extern const AAS_u8 AAS_PatternData[]; +extern const AAS_s8 AAS_SampleData[]; + +extern const AAS_u16 AAS_DivTable[8192]; +extern const AAS_u16 AAS_MOD_period_conv_table[2048]; +extern const AAS_u16 AAS_period_table[16][60]; + +extern const AAS_u16 AAS_tick_rate[41]; + +extern const AAS_s8 AAS_sin[64]; + +extern AAS_s16 AAS_mod_num AAS_IN_EWRAM; +extern AAS_BOOL AAS_initialised AAS_IN_EWRAM; +extern AAS_u8 AAS_volscale AAS_IN_EWRAM; +extern AAS_u8 AAS_mod_num_chans AAS_IN_EWRAM; +extern AAS_u16 AAS_mix_scale AAS_IN_EWRAM; +extern AAS_BOOL AAS_changed[2] AAS_IN_IWRAM; + +extern AAS_u8 AAS_chan_rearrange[AAS_MAX_CHANNELS] AAS_IN_EWRAM; + +__inline static int AAS_Min( int a, int b ) +{ + if ( a < b ) + return a; + else + return b; +} + +#endif diff --git a/lib/apex-audio-system/src/aas/Makefile b/lib/apex-audio-system/src/aas/Makefile new file mode 100644 index 0000000..0a4f8f8 --- /dev/null +++ b/lib/apex-audio-system/src/aas/Makefile @@ -0,0 +1,23 @@ +# AAS Mix Library makefile +# NOTE: Disable printf_special in final version + +# Tools and flags. +# CROSS = arm-thumb-elf- +CROSS ?= arm-none-eabi- + +# Name of output targets. +TARGET = libAAS.a + +# Files you want to go in IWRAM. +IWRAM = AAS_Mixer.o + +# Other source files. +SRC = AAS_ASM.o AAS_Logo.o AAS_Main.o AAS_MOD.o AAS_Shared.o AAS_SFX.o + +include ../../make/common.make + +$(TARGET): $(IWRAM) $(GFX) $(SOUND) $(SRC) + $(CROSS)ar r $@ $(SRC) $(IWRAM) $(GFX) $(SOUND) $(LIBS) + +clean: + rm -f *.o $(TARGET) $(NAME) $(GFX) $(SOUND) $(SYMBOLS) $(MAP) diff --git a/lutcalc/Makefile b/lutcalc/Makefile deleted file mode 100644 index e686868..0000000 --- a/lutcalc/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -CC := clang - -%.o: %.c - $(CC) $< -Wall -o $@ - -math_divlut.h math_divlut.c: lutcalc - ./lutcalc - mv math_divlut.h ../source/math_divlut.h - mv math_divlut.c ../data/math_divlut.c diff --git a/lutcalc/lutcalc.c b/lutcalc/lutcalc.c deleted file mode 100644 index 4355853..0000000 --- a/lutcalc/lutcalc.c +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include -#include -#include - - -// fracional bits of fixed point num -#define RECIPROCAL_FRACT_SHIFT 10 -#define RECIPROCAL_FRACT_SIZE (1 << RECIPROCAL_FRACT_SHIFT) -// the integer bits -#define RECIPROCAL_INT_SHIFT (32 - RECIPROCAL_FRACT_SHIFT) -#define RECIPROCAL_INT_SIZE (1 << RECIPROCAL_INT_SHIFT) - -#define RECIPROCAL_MAX_INT (128) -// length of resulting reciprocal LUT -#define RECIPROCAL_LUT_SIZE (RECIPROCAL_FRACT_SIZE * RECIPROCAL_MAX_INT) - -int32_t divLutArray[RECIPROCAL_LUT_SIZE]; - -int32_t double2fx(double n) { - return n * RECIPROCAL_FRACT_SIZE; -} -double fx2double(uint32_t fx) { - return fx / (double) RECIPROCAL_FRACT_SIZE; -} - - -void setupDivLut() { - assert(RECIPROCAL_FRACT_SHIFT + RECIPROCAL_INT_SHIFT == 32); - assert((RECIPROCAL_LUT_SIZE & (RECIPROCAL_LUT_SIZE - 1)) == 0 ); // must be power of two - - FILE *outfile = fopen("math_divlut.c", "w"); // remove existing file first - fclose(outfile); - outfile = fopen("math_divlut.c", "a"); - - FILE *outfileHeader = fopen("math_divlut.h", "w"); // remove existing file first - fclose(outfileHeader); - outfileHeader = fopen("math_divlut.h", "a"); - - // calculate the LUT - for (uint32_t i = 1; i <= RECIPROCAL_LUT_SIZE; ++i) { - divLutArray[i - 1] = double2fx(1. / fx2double(i)); - } - - // format it into a header file (metaprogramming lol) - const char *headers = { - "#ifndef MAT_DIVLUT_H\n" - "#define MAT_DIVLUT_H\n" - "#include \n\n" - "#define RECIPROCAL_FRACT_SHIFT %d\n" - "#define RECIPROCAL_FRACT_SIZE %d\n" - "#define RECIPROCAL_MAX_INT %d\n" - "#define RECIPROCAL_LUT_SIZE %d\n\n" - "" - "extern const s32 reciprocalLUT[RECIPROCAL_LUT_SIZE];" - "\n\n#endif" - }; - fprintf(outfileHeader, headers, RECIPROCAL_FRACT_SHIFT, RECIPROCAL_FRACT_SIZE, RECIPROCAL_MAX_INT, RECIPROCAL_LUT_SIZE); - fclose(outfileHeader); - - fprintf(outfile, "#include \"../source/math_divlut.h\"\nconst s32 reciprocalLUT[RECIPROCAL_LUT_SIZE] = {"); // u16 vs fixed - for (int i = 0; i < RECIPROCAL_LUT_SIZE; ++i) { - fprintf(outfile, "%d, ", divLutArray[i]); - } - fprintf(outfile, "};"); - fclose(outfile); -} - - -int main(void) { - setupDivLut(); - return 0; -} diff --git a/source/main.c b/source/main.c index c2cd7c3..91e7a1b 100644 --- a/source/main.c +++ b/source/main.c @@ -1,4 +1,5 @@ #include +#include "AAS.h" #include "logutils.h" #include "globals.h" @@ -8,6 +9,8 @@ #include "model.h" #include "render/draw.h" +#include "../data-audio/AAS_Data.h" + static FIXED_12 g_wave_time; static FIXED g_wave_amp; @@ -23,17 +26,27 @@ void waveUpdate(void) g_wave_amp = int2fx(3) + fxmul(int2fx(6), sinFx(g_wave_time << 5)); } +void audioInit(void) +{ + AAS_SetConfig( AAS_CONFIG_MIX_24KHZ, AAS_CONFIG_CHANS_8, AAS_CONFIG_SPATIAL_MONO, AAS_CONFIG_DYNAMIC_OFF); + irq_add(II_TIMER1, AAS_FastTimer1InterruptHandler); + irq_add(II_VBLANK, AAS_DoWork); + + AAS_MOD_Play(AAS_DATA_MOD_aaa); +} + int main(void) { // REG_WAITCNT controls the pre-fetch buffer and the waitstates of the external cartridge bus. REG_WAITCNT = 0x4317; // This setting yields a *major* perf improvement over the defaults; cf. https://problemkaputt.de/gbatek.htm#gbatechnicaldata (last retrieved 2021-05-28). - sqran(1997); + sqran(2001); irq_init(NULL); - irq_add(II_VBLANK, NULL); + // irq_add(II_VBLANK, NULL); // irq_add(II_HBLANK, wave); // irq_add(II_VBLANK, waveUpdate); + audioInit(); globalsInit(); drawInit(); mathInit(); @@ -45,10 +58,10 @@ int main(void) while (1) { scenesDispatchUpdate(); scenesDispatchDraw(); - + performanceGather(); perfPrint(); - + timerTick(&g_timer); ++g_frameCount; } diff --git a/source/math.c b/source/math.c index 328deb3..68cb3cb 100644 --- a/source/math.c +++ b/source/math.c @@ -308,7 +308,12 @@ void matrix4x4Transpose(FIXED mat[16]) } -// Not my code, also not used anymore , and only included for reference. Numerical matrix inversion code: https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix +/* + The following is not my code and belongs to its respective author. (I simply converted it to use fixed point instead of floats.) + It's not used anymore, and only included as a comment for reference in case we want to invert non-orthonormal matrices one day. + It's some sort of numerical approach to matrix inversion (it worked fine, but the transpose approach is simpler, and less general). + cf. https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix (last retrieved 2021-06-29) + FIXED invf(int i,int j,const FIXED* m) { int o = 2+(j-i); @@ -349,3 +354,4 @@ bool matrix4x4Inverse(const FIXED *m, FIXED *out) return true; } +*/ \ No newline at end of file diff --git a/source/render/draw.c b/source/render/draw.c index 0c88801..b1b621a 100644 --- a/source/render/draw.c +++ b/source/render/draw.c @@ -48,7 +48,8 @@ void setDispScaleM5Scaled(void) .scr_x=0, .scr_y=5, // Vertical letterboxing. .tex_x=0, - .tex_y=0 }; + .tex_y=0 + }; BG_AFFINE bgaff; bg_rotscale_ex(&bgaff, &asx); REG_BG_AFFINE[2]= bgaff; @@ -58,6 +59,17 @@ void resetDispScale(void) { BG_AFFINE bgaff; bg_aff_identity(&bgaff); + AFF_SRC_EX asx= { + .alpha=0, + .sx=int2fx(1), + .sy=int2fx(1), + .scr_x=0, + .scr_y=-5, // Reset Vertical letterboxing. + .tex_x=0, + .tex_y=0 + }; + bg_rotscale_ex(&bgaff, &asx); + REG_BG_AFFINE[2]= bgaff; } @@ -142,7 +154,7 @@ IWRAM_CODE_ARM void drawPoints(const Camera *cam, Vec3 *points, int num, COLOR c } } -INLINE void drawTriangleWireframe(const RasterTriangle *tri) +IWRAM_CODE_ARM void drawTriangleWireframe(const RasterTriangle *tri) { if (!RASTERPOINT_IN_BOUNDS_M5(tri->vert[0]) || !RASTERPOINT_IN_BOUNDS_M5(tri->vert[1]) || !RASTERPOINT_IN_BOUNDS_M5(tri->vert[2])) { // We have to clip against the screen. for (int j = 0; j < 3; ++j) { @@ -273,7 +285,8 @@ IWRAM_CODE_ARM static void modelInstancesPrepareDraw(Camera* cam, ModelInstance // const Vec3 b = vecSub(vertsCamSpace[face.vertexIndex[2]], vertsCamSpace[face.vertexIndex[0]]); // const Vec3 triNormal = vecCross(b, a); // const Vec3 camToTri = vertsCamSpace[face.vertexIndex[2]]; - + + // Backface culling (with face normals, winding order does not matter): const Vec3 triNormal = vecTransformedRot(instanceRotMat, &face.normal); const Vec3 camToTri = vecSub(cam->pos, vertsWorldSpace[face.vertexIndex[0]]); if (vecDot(triNormal, camToTri) <= 0) { // If the angle between camera and normal is not between 90 degs and 270 degs, the face is invisible and to be culled. diff --git a/source/scenes/benchmarkScene.c b/source/scenes/benchmarkScene.c index bb719d0..724ea5f 100644 --- a/source/scenes/benchmarkScene.c +++ b/source/scenes/benchmarkScene.c @@ -8,7 +8,7 @@ #include "../timer.h" #include "../render/draw.h" -#include "../data/suzanneModel.h" +#include "../../data-models/suzanneModel.h" static Timer timer; static Camera cam; diff --git a/source/scenes/gbaScene.c b/source/scenes/gbaScene.c index 14f64e1..b1f00bd 100644 --- a/source/scenes/gbaScene.c +++ b/source/scenes/gbaScene.c @@ -7,7 +7,7 @@ #include "../timer.h" #include "../render/draw.h" -#include "../data/gbaModel.h" +#include "../../data-models/gbaModel.h" static Timer timer; diff --git a/source/scenes/testbedScene.c b/source/scenes/testbedScene.c index ca55b3e..8badaab 100644 --- a/source/scenes/testbedScene.c +++ b/source/scenes/testbedScene.c @@ -12,7 +12,7 @@ #include "../logutils.h" #include "../timer.h" -#include "../data/headModel.h" +#include "../../data-models/headModel.h" #define NUM_CUBES 9 diff --git a/source/scenes/twisterScene.c b/source/scenes/twisterScene.c index 4953b39..ab7ce84 100644 --- a/source/scenes/twisterScene.c +++ b/source/scenes/twisterScene.c @@ -70,8 +70,8 @@ IWRAM_CODE_ARM void twisterSceneUpdate(void) timerTick(&timer); int letterboxTrans = + fx12ToInt(8 * lu_sin(fx12ToInt(timer.time * TAU))); - letterboxTop = 40; - letterboxBottom = 120; + letterboxTop = 20; + letterboxBottom = 130; for (int i = 0; i < MAX_RENDER_TWISTERS; ++i) { int t = fx12ToInt(timer.time * PI / 2); @@ -175,6 +175,7 @@ IWRAM_CODE_ARM void twisterSceneDraw(void) { memset32(vid_page, quad8(CLRIDX_BLACK), 15 * M4_WIDTH/4); // TODO: REMOVE ME (only here for debugging so the fps text does not overdraw). memset32(vid_page + letterboxTop * M4_WIDTH / 2, quad8(CLRIDX_PASTEL_BLUE), (letterboxBottom - letterboxTop) * M4_WIDTH/4); + m4_rect(0, 0, 240, 20, CLRIDX_RED); renderTwisters(twistPtrs, MAX_RENDER_TWISTERS); } @@ -203,7 +204,7 @@ static void videoModeInit(void) { void twisterSceneStart(void) { - videoModeInit(); + videoModeInit(); m4_fill(CLRIDX_BLACK); timerStart(&timer); } diff --git a/source/timer.c b/source/timer.c index 995a989..122fc32 100644 --- a/source/timer.c +++ b/source/timer.c @@ -9,22 +9,20 @@ static PerformanceData performanceData[MAX_PERF_DATA]; static int currentPerformanceId; - void timerInit(void) { - REG_TM0D = 0x10000 - 4; // 4 ticks till overflow (at 16384 Hz (1024 cycles), that means we have a overflow every 4 * 16384^-1 = 2^-12 s, or 0.2 ms) - REG_TM0CNT = TM_ENABLE | TM_FREQ_1024; - REG_TM1CNT = TM_ENABLE | TM_CASCADE; // will increment in 2^-12 seconds (4098 Hz), can be used as a .12 fixed point number then, overflows every 16 seconds - - REG_TM2D = 0x10000 - 0xffff; // 0xffff ticks till overflow, or about 1 seconds (65536 Hz) - REG_TM2CNT = TM_ENABLE | TM_FREQ_256; + REG_TM2D = 0x10000 - 4; // 4 ticks till overflow (at 16384 Hz (1024 cycles), that means we have a overflow every 4 * 16384^-1 = 2^-12 s, or 0.2 ms) + REG_TM2CNT = TM_ENABLE | TM_FREQ_1024; + REG_TM3CNT = TM_ENABLE | TM_CASCADE; // will increment in 2^-12 seconds (4098 Hz), can be used as a .12 fixed point number then, overflows every 16 seconds + // REG_TM2D = 0x10000 - 0xffff; // 0xffff ticks till overflow, or about 1 seconds (65536 Hz) + // REG_TM2CNT = TM_ENABLE | TM_FREQ_256; for (int i = 0; i < MAX_PERF_DATA; ++i) { performanceData[i].avgTime = 0; } } - +// We ignore the TimerType; it's always TIMER_REGULAR for now regardless of the argument (we need Timer 0 and 1 for apex audio). Timer timerNew(FIXED_12 duration, TimerType type) { Timer timer; @@ -40,7 +38,8 @@ Timer timerNew(FIXED_12 duration, TimerType type) void timerStart(Timer *timer) { - timer->__prevTimerState = timer->type == TIMER_REGULAR ? REG_TM1D : REG_TM2D; + // timer->__prevTimerState = timer->type == TIMER_REGULAR ? REG_TM1D : REG_TM2D; + timer->__prevTimerState = REG_TM3D; timer->time = 0; timer->stopped = false; timer->done = false; @@ -54,7 +53,9 @@ void timerStop(Timer *timer) void timerResume(Timer *timer) { timer->stopped = false; - timer->__prevTimerState = timer->type == TIMER_REGULAR ? REG_TM1D : REG_TM2D; + // timer->__prevTimerState = timer->type == TIMER_REGULAR ? REG_TM1D : REG_TM2D; + timer->__prevTimerState = REG_TM3D; + } void timerRewind(Timer *timer) @@ -69,7 +70,8 @@ void timerTick(Timer *timer) return; } - FIXED_12 timerState = timer->type == TIMER_REGULAR ? REG_TM1D : REG_TM2D; + // FIXED_12 timerState = timer->type == TIMER_REGULAR ? REG_TM1D : REG_TM2D; + FIXED_12 timerState = REG_TM3D; if (timer->__prevTimerState > timerState) { timer->deltatime = (0xffff + timerState) - timer->__prevTimerState; // handle overflow @@ -130,7 +132,8 @@ void performancePrintAll(void) for (int i = 0; i < currentPerformanceId; ++i) { PerformanceData perf = performanceData[i]; if (perf.avgTime) { - int shift = perf.timer.type == TIMER_PERF ? 4 : 0; + // int shift = perf.timer.type == TIMER_PERF ? 4 : 0; + int shift = 0; mgba_printf("%s: %f ms (%d samples)", perf.name, fx12ToFloat( fx12div(perf.avgTime, int2fx12(perf.avgSamples)) * 1000 >> shift), perf.avgSamples); performanceData[i].avgSamples = 0; performanceData[i].avgTime = 0; @@ -141,6 +144,7 @@ void performancePrintAll(void) FIXED_12 performanceGetSeconds(const PerformanceData *perfData) { - int shift = perfData->timer.type == TIMER_PERF ? 4 : 0; + // int shift = perfData->timer.type == TIMER_PERF ? 4 : 0; + int shift = 0; return perfData->timer.time >> shift; } \ No newline at end of file diff --git a/tools/obj2model.py b/tools/obj2model.py index e3c4667..b54c936 100644 --- a/tools/obj2model.py +++ b/tools/obj2model.py @@ -201,7 +201,7 @@ def read_model_limits(): # With respect to the project directory. SOURCE_DIR = "source/" MODEL_DIR = "assets/models/" -OUT_DIR_DATA = "data/" +OUT_DIR_DATA = "data-models/" if __name__ == "__main__": MAX_MODEL_VERTS, MAX_MODEL_FACES = read_model_limits() @@ -231,5 +231,3 @@ def read_model_limits(): elif modelsWritten > 0 and modelsWritten < len(models): print(f"In:\t{' '.join(infile_paths)}\nOut:\t{' '.join(outfile_paths)}") print(f"Some models could not be converted, but no specific error was caught. This is a bug. {FAIL}(Failure){END}") - - diff --git a/tools/rgb2rgb15.py b/tools/rgb2rgb15.py deleted file mode 100644 index 6febb20..0000000 --- a/tools/rgb2rgb15.py +++ /dev/null @@ -1,21 +0,0 @@ -import re -import sys - -def convert(rgb): - match = re.search(r"(\d+)\D*(\d+)\D*(\d+)", rgb) - if match: - r = int(match.group(1)) - g = int(match.group(2)) - b = int(match.group(3)) - - r = round(r / 255.0 * 31) - g = round(g / 255.0 * 31) - b = round(b / 255.0 * 31) - - print(f"RGB15_SAFE({r}, {g}, {b})") - -if __name__ == "__main__": - if len(sys.argv) > 1: - convert(sys.argv[1]) - else: - print("Usage: rgb2rgb15 rgbstring") diff --git a/tools/sceneCodegen.py b/tools/sceneCodegen.py index dde77d6..5e7c811 100644 --- a/tools/sceneCodegen.py +++ b/tools/sceneCodegen.py @@ -99,7 +99,6 @@ def generate_template(name, mode=None): def generate_scene_c(): - cfiles = [scene for scene in pathlib.Path(".").joinpath(SCENE_DIR).glob("*.c")] scenes = list() for scene in cfiles: @@ -212,6 +211,8 @@ def generate_scene_c(): + +# NOTE: This was used to find the relevant functions in the source files back when we didn't use the CODEGEN block; we had to check for matching parentheses. Only here for reference. # match = re.search(r"void\s+scenesInit\s*(\s*void\s*)\s*\{", scene_c_text) # if not match: # raise ValueError("scene.c does not contain a sceneInit function, abort.")