added apex audio system
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 7 Apr 2021 05:18:59 +0000 (08:18 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 7 Apr 2021 05:18:59 +0000 (08:18 +0300)
18 files changed:
.gitignore
Makefile
libs/aas/AAS.h [new file with mode: 0644]
libs/aas/AAS_ASM.s [new file with mode: 0644]
libs/aas/AAS_MOD.c [new file with mode: 0644]
libs/aas/AAS_Main.c [new file with mode: 0644]
libs/aas/AAS_Mixer.h [new file with mode: 0644]
libs/aas/AAS_Mixer.s [new file with mode: 0644]
libs/aas/AAS_SFX.c [new file with mode: 0644]
libs/aas/AAS_Shared.c [new file with mode: 0644]
libs/aas/AAS_Shared.h [new file with mode: 0644]
libs/aas/Makefile [new file with mode: 0644]
src/data.h [new file with mode: 0644]
src/intr.c
src/intr.h
src/main.c
tools/conv2aas/Makefile [new file with mode: 0644]
tools/conv2aas/conv2aas.c [new file with mode: 0644]

index b6fae84..d7a3666 100644 (file)
@@ -4,4 +4,6 @@
 cfg.mk
 *.gba
 *.elf
+*.a
 pngdump
+conv2aas
index a312a03..3d0b9d4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,16 @@
 src = $(wildcard src/*.c)
 ssrc = $(wildcard src/*.s)
-obj = $(src:.c=.o) $(ssrc:.s=.o)
+obj = $(src:.c=.o) $(ssrc:.s=.o) $(dataobj)
 dep = $(src:.c=.d)
 name = gbajam21
 elf = $(name).elf
 bin = $(name).gba
 
+audata = data/audio/popcorn.mod
+dataobj = data/aas_data.o
+
+libs = libs/aas/libaas.a
+
 TCPREFIX = arm-none-eabi-
 
 CPP = $(TCPREFIX)cpp
@@ -17,10 +22,11 @@ EMU = vbam
 
 opt = -O3 -fomit-frame-pointer -mcpu=arm7tdmi -mtune=arm7tdmi -mthumb -mthumb-interwork
 #dbg = -g
+inc = -I. -Ilibs/aas
 
-CFLAGS = $(opt) $(dbg) -pedantic -Wall -MMD $(def)
+CFLAGS = $(opt) $(dbg) -pedantic -Wall -MMD $(def) $(inc)
 ASFLAGS = -mthumb-interwork
-LDFLAGS = -mthumb -mthumb-interwork
+LDFLAGS = -mthumb -mthumb-interwork $(libs)
 EMUFLAGS = -T 100 -f 1 --agb-print
 
 -include cfg.mk
@@ -32,7 +38,7 @@ $(bin): $(elf)
        $(OBJCOPY) -O binary $(elf) $(bin)
        gbafix -r0 $(bin)
 
-$(elf): $(obj)
+$(elf): $(obj) $(libs)
        $(CC) -o $(elf) $(obj) -specs=gba.specs $(LDFLAGS)
 
 -include $(dep)
@@ -40,6 +46,9 @@ $(elf): $(obj)
 tools/pngdump/pngdump:
        $(MAKE) -C tools/pngdump
 
+tools/conv2aas/conv2aas:
+       $(MAKE) -C tools/conv2aas
+
 #data/sprites.raw: data/sprites1.png data/sprites2.png data/sprites3.png data/sprites4.png data/sprites5.png data/sprites6.png
 #      tools/pngdump/pngdump -o $@ -n $^
 
@@ -49,6 +58,11 @@ tools/pngdump/pngdump:
 %.pal: %.png tools/pngdump/pngdump
        tools/pngdump/pngdump -o $@ -c $<
 
+data/aas_data.h: data/aas_data.s
+
+data/aas_data.s: $(audata) tools/conv2aas/conv2aas
+       tools/conv2aas/conv2aas data/audio
+
 .PHONY: clean
 clean:
        rm -f $(obj) $(bin) $(bin_mb) $(elf) $(elf_mb)
@@ -57,6 +71,10 @@ clean:
 cleandep:
        rm -f $(dep)
 
+.PHONY: cleanlibs
+cleanlibs:
+       $(MAKE) -C libs/aas clean
+
 .PHONY: install
 install: $(bin)
        if2a -n -f -W $<
@@ -72,3 +90,9 @@ simrun: $(bin)
 .PHONY: disasm
 disasm: $(elf)
        $(OBJDUMP) -d $< >$@
+
+.PHONY: libs
+libs: $(libs)
+
+libs/aas/libaas.a:
+       $(MAKE) -C libs/aas
diff --git a/libs/aas/AAS.h b/libs/aas/AAS.h
new file mode 100644 (file)
index 0000000..e92d549
--- /dev/null
@@ -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/libs/aas/AAS_ASM.s b/libs/aas/AAS_ASM.s
new file mode 100644 (file)
index 0000000..bf99d4a
--- /dev/null
@@ -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/libs/aas/AAS_MOD.c b/libs/aas/AAS_MOD.c
new file mode 100644 (file)
index 0000000..a6a2e2b
--- /dev/null
@@ -0,0 +1,932 @@
+/* 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/libs/aas/AAS_Main.c b/libs/aas/AAS_Main.c
new file mode 100644 (file)
index 0000000..dae0c73
--- /dev/null
@@ -0,0 +1,698 @@
+/* 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"
+#include "../../src/debug.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_Normal();
+void AAS_MixAudio_SetMode_Boost();
+void AAS_MixAudio_SetMode_BoostAndClip();
+void AAS_MOD_Interrupt();
+
+
+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/libs/aas/AAS_Mixer.h b/libs/aas/AAS_Mixer.h
new file mode 100644 (file)
index 0000000..646d56a
--- /dev/null
@@ -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/libs/aas/AAS_Mixer.s b/libs/aas/AAS_Mixer.s
new file mode 100644 (file)
index 0000000..7f1e20f
--- /dev/null
@@ -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/libs/aas/AAS_SFX.c b/libs/aas/AAS_SFX.c
new file mode 100644 (file)
index 0000000..f8f4c41
--- /dev/null
@@ -0,0 +1,217 @@
+/* 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/libs/aas/AAS_Shared.c b/libs/aas/AAS_Shared.c
new file mode 100644 (file)
index 0000000..b6f11d3
--- /dev/null
@@ -0,0 +1,737 @@
+/* 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/libs/aas/AAS_Shared.h b/libs/aas/AAS_Shared.h
new file mode 100644 (file)
index 0000000..877c0d2
--- /dev/null
@@ -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/libs/aas/Makefile b/libs/aas/Makefile
new file mode 100644 (file)
index 0000000..2c84074
--- /dev/null
@@ -0,0 +1,21 @@
+obj = AAS_ASM.o AAS_Main.o AAS_MOD.o AAS_Shared.o AAS_SFX.o AAS_Mixer.o
+lib_a = libaas.a
+
+TCPREFIX = arm-none-eabi-
+CC = $(TCPREFIX)gcc
+AS = $(TCPREFIX)as
+AR = $(TCPREFIX)ar
+
+CFLAGS = -mthumb -O3 -funroll-loops -mcpu=arm7tdmi -ffast-math \
+                -fno-exceptions -mthumb-interwork -fomit-frame-pointer
+ASFLAGS = -mthumb-interwork
+
+$(lib_a): $(obj)
+       $(AR) rcs $@ $(obj)
+
+%.o: %.s
+       $(AS) $(ASFLAGS) -o $@ $<
+
+.PHONY: clean
+clean:
+       rm -f $(obj) $(lib_a)
diff --git a/src/data.h b/src/data.h
new file mode 100644 (file)
index 0000000..3f92927
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef DATA_H_
+#define DATA_H_
+
+#include "data/aas_data.h"
+
+#endif /* DATA_H_ */
index 80ee066..7d8bdf2 100644 (file)
@@ -9,7 +9,7 @@ static void intr_handler(void)
        int i;
        uint16_t iflags;
 
-       clr_intr();
+       intr_disable();
        iflags = REG_IF & 0x3fff;
 
 
@@ -20,7 +20,7 @@ static void intr_handler(void)
        }
 
        REG_IF = iflags;        /* ack intr */
-       set_intr();
+       intr_enable();
 }
 
 void intr_init(void)
index d37e012..859b9a7 100644 (file)
@@ -24,9 +24,9 @@ enum {
 void intr_init(void);
 
 /* set/clear interrupts */
-#define set_intr()     \
+#define intr_enable()  \
        do { REG_IME |= 0x0001; } while(0)
-#define clr_intr()     \
+#define intr_disable() \
        do { REG_IME &= 0xfffe; } while(0)
 
 /* set an interrupt handler */
index d7a3308..03930b1 100644 (file)
@@ -3,6 +3,9 @@
 #include "intr.h"
 #include "debug.h"
 
+#include "AAS.h"
+#include "data.h"
+
 #define RGB15(r, g, b) \
        (((uint16_t)(r) & 0x1f) | \
         (((uint16_t)(g) & 0x1f) << 5) | \
@@ -17,6 +20,12 @@ int main(void)
 
        intr_init();
 
+       interrupt(INTR_TIMER1, AAS_Timer1InterruptHandler);
+       AAS_SetConfig(AAS_CONFIG_MIX_24KHZ, AAS_CONFIG_CHANS_8, AAS_CONFIG_SPATIAL_STEREO, AAS_CONFIG_DYNAMIC_ON);
+       unmask(INTR_TIMER1);
+       intr_enable();
+
+
        REG_DISPCNT = 3 | DISPCNT_BG2;
 
        vptr = (uint16_t*)VRAM_START_ADDR;
@@ -31,6 +40,8 @@ int main(void)
                }
        }
 
+       AAS_MOD_Play(AAS_DATA_MOD_popcorn);
+
        for(;;);
        return 0;
 }
diff --git a/tools/conv2aas/Makefile b/tools/conv2aas/Makefile
new file mode 100644 (file)
index 0000000..af55b98
--- /dev/null
@@ -0,0 +1,11 @@
+obj = conv2aas.o
+bin = conv2aas
+
+CFLAGS = -pedantic -Wall -g
+
+$(bin): $(obj)
+       $(CC) -o $@ $(obj) $(LDFLAGS)
+
+.PHONY: clean
+clean:
+       rm -f $(obj) $(bin)
diff --git a/tools/conv2aas/conv2aas.c b/tools/conv2aas/conv2aas.c
new file mode 100644 (file)
index 0000000..679f15d
--- /dev/null
@@ -0,0 +1,1247 @@
+/* Copyright (c) 2003-2021 James Daniels */
+/* Distributed under the MIT License */
+/* license terms: see LICENSE file in root or http://opensource.org/licenses/MIT */
+
+/* Notes: */
+/*  + Max number of MODs = 256 */
+/*  + Max total size of all samples = 33,554,432 bytes */
+/*  + Max total size of all patterns = 33,554,432 bytes */
+/*  + All functions declared static to work around problem with GCC */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#define BYTE signed char
+#define UBYTE unsigned char
+#define BOOL unsigned char
+#define UWORD unsigned short
+#define ULONG unsigned int
+#define WORD signed short
+#define TRUE 1
+#define FALSE 0
+
+__inline static int Min(int a, int b)
+{
+       if (a < b)
+               return a;
+       else
+               return b;
+}
+
+__inline static UWORD SwapUWORD( UWORD a )
+{
+       return (a>>8)+((a&0xff)<<8);
+}
+
+static int memcmp_new( UBYTE* a, UBYTE* b, int length )
+{
+       for(; length > 0; --length )
+               if ( *a++ != *b++ )
+                       return 1;
+
+       return 0;
+}
+
+static void memcpy_new( UBYTE* dest, UBYTE* source, int length )
+{
+       for(; length > 0; --length )
+               *dest++ = *source++;
+}
+
+#define MAX_DATA_LENGTH 33554432
+typedef struct data_pack
+{
+       const char* chunk_name;
+       int chunk_data_length;
+       int chunk_unique;
+       int chunk_actual;
+       unsigned char chunk_data[MAX_DATA_LENGTH];
+} DATAPACK;
+
+static DATAPACK* DATA_Create( const char* name )
+{
+       DATAPACK* new_data = (DATAPACK*)malloc(sizeof(DATAPACK));
+
+       if ( new_data )
+       {
+               /*printf( "DATA_Create( %s ): addr:%p\n", name, new_data ); */
+
+               new_data->chunk_name = name;
+               new_data->chunk_data_length = 0;
+               new_data->chunk_unique = 0;
+               new_data->chunk_actual = 0;
+       }
+       else
+       {
+               printf( "DATA_Create( %s ): Failed (address:%p length:%d)...\n", name, (void*)new_data, (int)sizeof(DATAPACK) );
+       }
+
+       return new_data;
+}
+
+static int DATA_AppendAligned( DATAPACK* curr_data, unsigned char* data, int length, int block_length )
+{
+       ++curr_data->chunk_actual;
+
+       if ( (block_length*((int)(length/block_length))) != length )
+       {
+               printf( "DATA_AppendAligned( %p, %p, %d, %d ): Warning length not exactly divisible by block_length!\n",
+                               (void*)curr_data, data, length, block_length );
+               return 0;
+       }
+       else if ( length == 0 )
+       {
+               return 0;
+       }
+       else
+       {
+               int offset = 0;
+
+               while ( (offset + block_length) <= curr_data->chunk_data_length )
+               {
+                       if ( memcmp( data, curr_data->chunk_data + offset, length ) == 0 )
+                       {
+                               return offset/block_length;
+                       }
+
+                       offset += block_length;
+               };
+
+               if ( curr_data->chunk_data_length <= (MAX_DATA_LENGTH-length) )
+               {
+                       memcpy( curr_data->chunk_data + offset, data, length );
+                       curr_data->chunk_data_length += length;
+                       ++curr_data->chunk_unique;
+                       return offset/block_length;
+               }
+               else
+               {
+                       --curr_data->chunk_actual;
+                       printf( "DATA_AppendAligned( %p, %p, %d, %d ): Data >%d bytes!\n",
+                                       (void*)curr_data, data, length, block_length, MAX_DATA_LENGTH );
+                       return 0;
+               }
+       }
+}
+
+static int DATA_Append( DATAPACK* curr_data, unsigned char* data, int length )
+{
+       ++curr_data->chunk_actual;
+
+       if ( length == 0 )
+       {
+               return 0;
+       }
+       else
+       {
+               int offset = 0;
+
+               while ( (offset + length) <= curr_data->chunk_data_length )
+               {
+                       if ( memcmp_new( data, curr_data->chunk_data + offset, length ) == 0 )
+                               return offset;
+                       ++offset;
+               };
+
+               if ( curr_data->chunk_data_length <= (MAX_DATA_LENGTH-length) )
+               {
+                       offset = curr_data->chunk_data_length;
+                       memcpy_new( curr_data->chunk_data + offset, data, length );
+                       curr_data->chunk_data_length += length;
+                       ++curr_data->chunk_unique;
+                       return offset;
+               }
+               else
+               {
+                       --curr_data->chunk_actual;
+                       printf( "DATA_Append( %p, %d ): Data >%d bytes!\n", data, length, MAX_DATA_LENGTH );
+                       return 0;
+               }
+       }
+}
+
+static void DATA_Write( DATAPACK* curr_data, FILE* out_file )
+{
+       int i, len;
+       UBYTE val;
+
+       len = curr_data->chunk_data_length;
+       if ( len & 0x3 )
+       {
+               len &= ~0x3;
+               len += 0x4;
+       }
+
+       printf( "Writing %s (Unique:%d Actual:%d Length:%d)...", curr_data->chunk_name, curr_data->chunk_unique, curr_data->chunk_actual, len );
+
+       fprintf( out_file, "\n.ALIGN\n.GLOBAL %s\n%s:\n.byte", curr_data->chunk_name, curr_data->chunk_name );
+
+       if ( len > 0 )
+       {
+               for( i = 0; i < len; ++i )
+               {
+                       if ( i >= curr_data->chunk_data_length )
+                               val = 0;
+                       else
+                               val = *(curr_data->chunk_data + i);
+                       if ( i == 0 )
+                               fprintf( out_file, " %d", val );
+                       else
+                               fprintf( out_file, ", %d", val );
+               }
+               fprintf( out_file, "\n" );
+       }
+       else
+       {
+               fprintf( out_file, " 0\n" );
+       }
+
+       printf( "Done!\n" );
+
+       free( curr_data );
+}
+
+struct ModSampleTemp
+{
+       UWORD repeat; /* in halfwords */
+       UWORD length; /* in halfwords */
+       UWORD truelen; /* in halfwords */
+       UBYTE volume;
+       UBYTE finetune;
+};
+
+struct ModSample
+{
+       ULONG data; /* offset in bytes */
+       UWORD repeat; /* in halfwords */
+       UWORD length; /* in halfwords */
+       UBYTE finetune;
+       UBYTE volume;
+};
+
+static void MISC_ProcessSound( BYTE* data, int length )
+{
+       for(; length > 0; --length )
+       {
+               int val = *data;
+
+               if ( val == -128 )
+                       val = -127;
+
+               *data++ = val;
+       }
+}
+
+static void MISC_ConvSoundToSigned( UBYTE* data, int length )
+{
+       BYTE* bdata = (BYTE*)data;
+       for(; length > 0; --length )
+       {
+               int val = *data;
+               val -= 128;
+               *bdata++ = val;
+       }
+}
+
+static void MOD_LoadSound( struct ModSample* smp, FILE* in_file, DATAPACK* samples, int length, int truelen, int repeat )
+{
+       BYTE* samp = malloc( (length<<1)+16 );
+       int data;
+
+       fread( samp+16, (length<<1), 1, in_file );
+
+       if ( truelen > 0 )
+       {
+               memset( samp, 0, 16 );
+               if ( (repeat < 65535) && (truelen > repeat) )
+                       memcpy( samp+(repeat<<1), samp+(truelen<<1), 16 ); /* should really merge, also wasteful of memory */
+               MISC_ProcessSound( samp, (truelen<<1)+16 );
+               data = DATA_Append( samples, (UBYTE*)samp, (truelen<<1)+16 );
+               smp->data = data+16;
+       }
+       else
+       {
+               smp->data = 0;
+       }
+       smp->length = truelen;
+
+       free( samp );
+}
+
+#define MAX_MODS 256
+
+static struct ModSample samps[MAX_MODS][31];
+static WORD patts[MAX_MODS][128][16]; /* [mod][pattern][channel] */
+static UBYTE mod_num_chans[MAX_MODS];
+static UBYTE mod_song_restart_pos[MAX_MODS];
+static int max_song_length = 0;
+
+static const char* effect_name[32] = { "*0: Arpeggio", "*1: Slide Up", "*2: Slide Down", "*3: Tone Portamento", "*4: Vibrato", "*5: Tone Portamento + Volume Slide", "*6: Vibrato + Volume Slide", "*7: Tremolo", "8: Set Panning Position", "*9: Set Sample Offset", "*A: Volume Slide", "*B: Position Jump", "*C: Set Volume", "*D: Pattern Break", "*F: Set Speed (BPM)", "*F: Set Speed (Ticks)", "*E0: Set Filter", "*E1: Fine Slide Up", "*E2: Fine Slide Down", "E3: Glissando Control", "E4: Set Vibrato Waveform", "E5: Set FineTune", "*E6: Set/Jump to Loop", "E7: Set Tremolo Waveform", "E8: Illegal", "*E9: Retrigger Note", "*EA: Fine Volume Slide Up", "*EB: Fine Volume Slide Down", "*EC: Note Cut", "*ED: Note Delay", "*EE: Pattern Delay", "EF: Invert Loop" };
+
+static int MOD_FindNote( int period )
+{
+       const int period_table[61] =
+       {
+               0,
+               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
+       };
+       int i, d, r;
+       int closest = 1000000000;
+
+       r = -1;
+
+       for( i = 0; i < 61; ++i )
+       {
+               d = abs( period_table[i] - period );
+               if ( d < closest )
+               {
+                       r = i;
+                       closest = d;
+               }
+       }
+
+       if ( r == -1 )
+       {
+               printf( "Can't find note with period:%d...\n", period );
+       }
+
+       return r;
+}
+
+#define FOUR_CHAR_CODE( ch0, ch1, ch2, ch3 ) \
+       ( (long)(unsigned char)(ch0) | ( (long)(unsigned char)(ch1) << 8 ) | \
+         ( (long)(unsigned char)(ch2) << 16 ) | ( (long)(unsigned char)(ch3) << 24 ) )
+
+static int MOD_GetNumChans( ULONG file_format )
+{
+       switch( file_format )
+       {
+       case FOUR_CHAR_CODE( 'T', 'D', 'Z', '1'):
+               return 1;
+               break;
+
+       case FOUR_CHAR_CODE( '2', 'C', 'H', 'N'):
+       case FOUR_CHAR_CODE( 'T', 'D', 'Z', '2'):
+               return 2;
+               break;
+
+       case FOUR_CHAR_CODE( 'T', 'D', 'Z', '3'):
+               return 3;
+               break;
+
+       case FOUR_CHAR_CODE( 'M', '.', 'K', '.'):
+       case FOUR_CHAR_CODE( 'F', 'L', 'T', '4'):
+       case FOUR_CHAR_CODE( 'M', '!', 'K', '!'):
+               return 4;
+               break;
+
+       case FOUR_CHAR_CODE( '5', 'C', 'H', 'N'):
+               return 5;
+               break;
+
+       case FOUR_CHAR_CODE( '6', 'C', 'H', 'N'):
+               return 6;
+               break;
+
+       case FOUR_CHAR_CODE( '7', 'C', 'H', 'N'):
+               return 7;
+               break;
+
+       case FOUR_CHAR_CODE( '8', 'C', 'H', 'N'):
+       case FOUR_CHAR_CODE( 'O', 'C', 'T', 'A'):
+       case FOUR_CHAR_CODE( 'C', 'D', '8', '1'):
+               return 8;
+               break;
+
+       case FOUR_CHAR_CODE( 'F', 'L', 'T', '8'):
+               return -2; /* Unsupported MOD type */
+               break;
+
+       case FOUR_CHAR_CODE( '9', 'C', 'H', 'N'):
+               return 9;
+               break;
+
+       case FOUR_CHAR_CODE( '1', '0', 'C', 'H'):
+               return 10;
+               break;
+
+       case FOUR_CHAR_CODE( '1', '1', 'C', 'H'):
+               return 11;
+               break;
+
+       case FOUR_CHAR_CODE( '1', '2', 'C', 'H'):
+               return 12;
+               break;
+
+       case FOUR_CHAR_CODE( '1', '3', 'C', 'H'):
+               return 13;
+               break;
+
+       case FOUR_CHAR_CODE( '1', '4', 'C', 'H'):
+               return 14;
+               break;
+
+       case FOUR_CHAR_CODE( '1', '5', 'C', 'H'):
+               return 15;
+               break;
+
+       case FOUR_CHAR_CODE( '1', '6', 'C', 'H'):
+               return 16;
+               break;
+
+       case FOUR_CHAR_CODE( '1', '7', 'C', 'H'):
+       case FOUR_CHAR_CODE( '1', '8', 'C', 'H'):
+       case FOUR_CHAR_CODE( '1', '9', 'C', 'H'):
+       case FOUR_CHAR_CODE( '2', '0', 'C', 'H'):
+       case FOUR_CHAR_CODE( '2', '1', 'C', 'H'):
+       case FOUR_CHAR_CODE( '2', '2', 'C', 'H'):
+       case FOUR_CHAR_CODE( '2', '3', 'C', 'H'):
+       case FOUR_CHAR_CODE( '2', '4', 'C', 'H'):
+       case FOUR_CHAR_CODE( '2', '5', 'C', 'H'):
+       case FOUR_CHAR_CODE( '2', '6', 'C', 'H'):
+       case FOUR_CHAR_CODE( '2', '7', 'C', 'H'):
+       case FOUR_CHAR_CODE( '2', '8', 'C', 'H'):
+       case FOUR_CHAR_CODE( '2', '9', 'C', 'H'):
+       case FOUR_CHAR_CODE( '3', '0', 'C', 'H'):
+       case FOUR_CHAR_CODE( '3', '1', 'C', 'H'):
+       case FOUR_CHAR_CODE( '3', '2', 'C', 'H'):
+       case FOUR_CHAR_CODE( '3', '3', 'C', 'H'):
+       case FOUR_CHAR_CODE( '3', '4', 'C', 'H'):
+       case FOUR_CHAR_CODE( '3', '5', 'C', 'H'):
+       case FOUR_CHAR_CODE( '3', '6', 'C', 'H'):
+       case FOUR_CHAR_CODE( '3', '7', 'C', 'H'):
+       case FOUR_CHAR_CODE( '3', '8', 'C', 'H'):
+       case FOUR_CHAR_CODE( '3', '9', 'C', 'H'):
+       case FOUR_CHAR_CODE( '4', '0', 'C', 'H'):
+       case FOUR_CHAR_CODE( '4', '1', 'C', 'H'):
+       case FOUR_CHAR_CODE( '4', '2', 'C', 'H'):
+       case FOUR_CHAR_CODE( '4', '3', 'C', 'H'):
+       case FOUR_CHAR_CODE( '4', '4', 'C', 'H'):
+       case FOUR_CHAR_CODE( '4', '5', 'C', 'H'):
+       case FOUR_CHAR_CODE( '4', '6', 'C', 'H'):
+       case FOUR_CHAR_CODE( '4', '7', 'C', 'H'):
+       case FOUR_CHAR_CODE( '4', '8', 'C', 'H'):
+       case FOUR_CHAR_CODE( '4', '9', 'C', 'H'):
+       case FOUR_CHAR_CODE( '5', '0', 'C', 'H'):
+       case FOUR_CHAR_CODE( '5', '1', 'C', 'H'):
+       case FOUR_CHAR_CODE( '5', '2', 'C', 'H'):
+       case FOUR_CHAR_CODE( '5', '3', 'C', 'H'):
+       case FOUR_CHAR_CODE( '5', '4', 'C', 'H'):
+       case FOUR_CHAR_CODE( '5', '5', 'C', 'H'):
+       case FOUR_CHAR_CODE( '5', '6', 'C', 'H'):
+       case FOUR_CHAR_CODE( '5', '7', 'C', 'H'):
+       case FOUR_CHAR_CODE( '5', '8', 'C', 'H'):
+       case FOUR_CHAR_CODE( '5', '9', 'C', 'H'):
+       case FOUR_CHAR_CODE( '6', '0', 'C', 'H'):
+       case FOUR_CHAR_CODE( '6', '1', 'C', 'H'):
+       case FOUR_CHAR_CODE( '6', '2', 'C', 'H'):
+       case FOUR_CHAR_CODE( '6', '3', 'C', 'H'):
+       case FOUR_CHAR_CODE( '6', '4', 'C', 'H'):
+               return -3; /* Too many channels */
+               break;
+
+       default:
+               return -1; /* Unrecognised MOD type */
+               break;
+       }
+
+       /* 'FLT4', 'FLT8': Startrekker 4/8 channel file. ('FLT6' doesn't exist) */
+       /* 'CD81'        : Falcon 8 channel MODs */
+       /* '2CHN'        : FastTracker 2 Channel MODs */
+       /* 'yyCH' where yy can be 10, 12, .. 30, 32: FastTracker yy Channel MODs */
+       /* 'yyCH' where yy can be 11, 13, 15: TakeTracker 11, 13, 15 channel MODs */
+       /* 'TDZx' where x can be 1, 2 or 3: TakeTracker 1, 2, 3 channel MODs */
+       /* ModPlug Tracker saves 33-64 channel MODs as '33CH' to '64CH' */
+}
+
+static void MOD_ConvMod( FILE* out_file, DATAPACK* samples, DATAPACK* patterns, const char* filename, int mod_num )
+{
+       FILE* in_file;
+
+       mod_num_chans[mod_num] = 0;
+
+       in_file = fopen( filename, "rb" );
+       if ( in_file )
+       {
+               struct ModSampleTemp samps_temp[32];
+               char temp[23];
+               int i, tmp, line, chan;
+               UBYTE song_length, last_pattern;
+               UBYTE song_data[128];
+               int pat[64][16];
+               UWORD tmp_uword;
+               UBYTE tmp_ubyte;
+               ULONG notes_temp[16][64];
+               int effect_count[32] = { 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 };
+               BOOL first;
+               ULONG new_temp;
+               int num_chans;
+               UBYTE song_restart_pos;
+
+               /*printf( "\nMOD_ConvMod( %s ): Reading...\n", filename ); */
+
+               fread( temp, 20, 1, in_file ); /* mod name */
+
+               for( i = 1; i <= 31; ++i )
+               {
+                       fread( temp, 22, 1, in_file ); /* sample name */
+
+                       fread( &tmp_uword, 2, 1, in_file ); /* sample length */
+                       samps_temp[i].length = SwapUWORD( tmp_uword );
+
+                       fread( &tmp_ubyte, 1, 1, in_file ); /* finetune */
+                       /*if ( tmp_ubyte & 8 ) */
+                       /*      tmp_ubyte -= 8; */
+                       /*else */
+                       /*      tmp_ubyte += 8; */
+                       samps_temp[i].finetune = tmp_ubyte;
+                       if ( tmp_ubyte > 15 )
+                               printf( "MOD_ConvMod( %s ): Error: finetune > 15...\n", filename );
+
+                       fread( &tmp_ubyte, 1, 1, in_file ); /* volume */
+                       samps_temp[i].volume = tmp_ubyte;
+
+                       if ( tmp_ubyte > 64 )
+                       {
+                               printf( "Failed! Reason: Sample vol > 64\n" );
+                               return;
+                       }
+
+                       fread( &tmp_uword, 2, 1, in_file );
+                       samps_temp[i].repeat = SwapUWORD( tmp_uword );
+
+                       fread( &tmp_uword, 2, 1, in_file );
+                       tmp = SwapUWORD( tmp_uword );
+
+                       /*samps_temp[i].truelen = samps_temp[i].length; */
+
+                       if ( tmp <= 1 )
+                       {
+                               samps_temp[i].repeat = 65535;
+                               samps_temp[i].truelen = samps_temp[i].length;
+                       }
+                       else
+                       {
+                               samps_temp[i].truelen = Min( samps_temp[i].repeat + tmp, samps_temp[i].length );
+                       }
+
+                       /*printf( "i:%d len:%d vol:%d rep:%d fine:%d\n", i, samps_temp[i].truelen, samps_temp[i].volume, samps_temp[i].repeat, samps_temp[i].finetune ); */
+               }
+
+               fread( &song_length, 1, 1, in_file );
+               fread( &song_restart_pos, 1, 1, in_file );
+
+               if ( (song_length < 1) || (song_length > 128) )
+                       printf( "MOD_ConvMod( %s ): song_length:%d\n", filename, song_length );
+
+               last_pattern = 0;
+               for( i = 0; i <= 127; ++i )
+               {
+                       fread( &tmp_ubyte, 1, 1, in_file );
+                       song_data[i] = tmp_ubyte;
+                       if ( tmp_ubyte > last_pattern )
+                               last_pattern = tmp_ubyte;
+               }
+
+               if ( last_pattern > 63 )
+                       printf( "MOD_ConvMod( %s ): last_pattern:%d\n", filename, last_pattern );
+
+               fread( &new_temp, 4, 1, in_file );
+               num_chans = MOD_GetNumChans( new_temp );
+               if ( num_chans <= 0 )
+               {
+                       switch( num_chans )
+                       {
+                       case -2: /* Unsupported MOD type */
+                               printf( "Failed! Reason: Unsupported MOD type (%x)\n", new_temp );
+                               break;
+
+                       case -3: /* Too many channels */
+                               printf( "Failed! Reason: Too many channels\n" );
+                               break;
+
+                       default: /* Unrecognised MOD type */
+                               printf( "Failed! Reason: Unrecognised MOD type (%x)\n", new_temp );
+                               break;
+                       }
+                       return;
+               }
+               else
+               {
+                       if ( num_chans == 1 )
+                               printf( "%d channel...", num_chans );
+                       else
+                               printf( "%d channels...", num_chans );
+
+                       mod_num_chans[mod_num] = num_chans;
+               }
+
+               for( i = 0; i <= last_pattern; ++i )
+               {
+                       /*curr_note = &notes_temp[0][0]; */
+                       for( line = 0; line < 64; ++line )
+                       {
+                               for( chan = 0; chan < num_chans; ++chan )
+                               {
+                                       UBYTE byte1, byte2, byte3, byte4;
+                                       int samp_num, period, effect;
+
+                                       fread( &byte1, 1, 1, in_file );
+                                       fread( &byte2, 1, 1, in_file );
+                                       fread( &byte3, 1, 1, in_file );
+                                       fread( &byte4, 1, 1, in_file );
+
+                                       samp_num = (byte1&0xf0)+(byte3>>4);
+                                       period = (((int)(byte1&0xf))<<8) + ((int)byte2);
+                                       effect = (((int)(byte3&0xf))<<8) + byte4;
+                                       if ( effect != 0 )
+                                       {
+                                               if ( (effect>>8) == 0xe )
+                                                       ++effect_count[((effect&0xf0)>>4)+16];
+                                               else
+                                               {
+                                                       if ( (effect>>8) == 0xf )
+                                                       {
+                                                               if ( (effect&0xff) > 31 )
+                                                                       ++effect_count[14];
+                                                               else
+                                                                       ++effect_count[15];
+                                                       }
+                                                       else
+                                                       {
+                                                               if ( (effect>>8) == 0xc )
+                                                                       if ( (effect&0xff) > 64 )
+                                                                               effect = 0xc40;
+                                                               if ( (effect>>8) == 0xd ) /* pattern break */
+                                                                       effect = (effect&0xf00) + (((effect>>4)&0xf)*10)+(effect&0xf);
+                                                               ++effect_count[effect>>8];
+                                                       }
+                                               }
+                                       }
+                                       notes_temp[chan][line] = (samp_num<<24) + (MOD_FindNote(period)<<12) + effect;
+                               }
+                       }
+
+                       for( chan = 0; chan < num_chans; ++chan )
+                       {
+                               pat[i][chan] = DATA_AppendAligned( patterns, (UBYTE*)(&notes_temp[chan][0]), 256, 256 );
+                       }
+               }
+
+               for( i = 0; i <= 127; ++i )
+               {
+                       if ( i >= song_length )
+                       {
+                               for( chan = 0; chan < num_chans; ++chan )
+                                       patts[mod_num][i][chan] = -1;
+                       }
+                       else
+                       {
+                               for( chan = 0; chan < num_chans; ++chan )
+                                       patts[mod_num][i][chan] = pat[song_data[i]][chan];
+                       }
+               }
+
+               if ( song_length > max_song_length )
+                       max_song_length = song_length;
+
+               if ( song_restart_pos < 127 )
+               {
+                       if ( patts[mod_num][song_restart_pos][0] == -1 )
+                               song_restart_pos = 0;
+               }
+               else
+               {
+                       song_restart_pos = 0;
+               }
+
+               mod_song_restart_pos[mod_num] = song_restart_pos;
+
+               for( i = 1; i <= 31; ++i )
+               {
+                       if ( samps_temp[i].length > 0 )
+                       {
+                               MOD_LoadSound( &samps[mod_num][i-1], in_file, samples, samps_temp[i].length, samps_temp[i].truelen, samps_temp[i].repeat );
+                               samps[mod_num][i-1].volume = samps_temp[i].volume;
+                               samps[mod_num][i-1].finetune = samps_temp[i].finetune;
+                               samps[mod_num][i-1].repeat = samps_temp[i].repeat;
+                       }
+               }
+
+               printf( "Done!\n" );
+
+               first = TRUE;
+               for( i = 0; i <= 31; ++i )
+                       if ( effect_count[i] > 0 )
+                               if ( *(effect_name[i]) != '*' )
+                               {
+                                       if ( first )
+                                       {
+                                               printf( "Unsupported effects:\n" );
+                                               first = FALSE;
+                                       }
+                                       printf( "%s (%d)\n", effect_name[i], effect_count[i] );
+                               }
+
+               printf( "song_length:%d last_pattern:%d\n\n", song_length, last_pattern );
+
+               fclose( in_file );
+       }
+       else
+       {
+               printf( "MOD_ConvMod( %s ): Unable to open file for reading...\n", filename );
+       }
+}
+
+static void MOD_WriteSamples( FILE* out_file, int num_mods )
+{
+       int i, s;
+
+       fprintf( out_file, "\n.ALIGN\n.GLOBAL AAS_ModSamples\nAAS_ModSamples:" );
+
+       for( i = 0; i < num_mods; ++i )
+       {
+               fprintf( out_file, "\n.word" );
+               for( s = 0; s < 31; ++s )
+               {
+                       if ( s == 0 )
+                               fprintf( out_file, " %u, %u, %u", samps[i][s].data, (samps[i][s].length<<16)+samps[i][s].repeat, ((samps[i][s].volume&0xff)<<8)+(samps[i][s].finetune&0xff) );
+                       else
+                               fprintf( out_file, ", %u, %u, %u", samps[i][s].data, (samps[i][s].length<<16)+samps[i][s].repeat, ((samps[i][s].volume&0xff)<<8)+(samps[i][s].finetune&0xff) );
+               }
+       }
+
+       fprintf( out_file, "\n" );
+}
+
+static void MOD_WritePatterns( FILE* out_file, int num_mods )
+{
+       int mod_num, pattern_num, channel_num;
+       BOOL first;
+
+       fprintf( out_file, "\n.ALIGN\n.GLOBAL AAS_Sequence\nAAS_Sequence:" );
+
+       for( mod_num = 0; mod_num < num_mods; ++mod_num )
+       {
+               fprintf( out_file, "\n.short" );
+               first = TRUE;
+               for( pattern_num = 0; pattern_num < 128; ++pattern_num )
+               {
+                       for( channel_num = 0; channel_num < 16; ++channel_num )
+                       {
+                               if ( first )
+                               {
+                                       first = FALSE;
+                                       fprintf( out_file, " %d", patts[mod_num][pattern_num][channel_num] );
+                               }
+                               else
+                               {
+                                       fprintf( out_file, ", %d", patts[mod_num][pattern_num][channel_num] );
+                               }
+                       }
+               }
+       }
+
+       fprintf( out_file, "\n" );
+}
+
+static void MOD_WriteNumChans( FILE* out_file, int num_mods )
+{
+       int mod_num;
+
+       fprintf( out_file, "\n.ALIGN\n.GLOBAL AAS_NumChans\nAAS_NumChans:\n.byte" );
+
+       for( mod_num = 0; mod_num < num_mods; ++mod_num )
+       {
+               if ( mod_num )
+                       fprintf( out_file, ", %d", mod_num_chans[mod_num] );
+               else
+                       fprintf( out_file, " %d", mod_num_chans[mod_num] );
+       }
+
+       fprintf( out_file, "\n" );
+}
+
+static void MOD_WriteSongRestartPos( FILE* out_file, int num_mods )
+{
+       int mod_num;
+
+       fprintf( out_file, "\n.ALIGN\n.GLOBAL AAS_RestartPos\nAAS_RestartPos:\n.byte" );
+
+       for( mod_num = 0; mod_num < num_mods; ++mod_num )
+       {
+               if ( mod_num )
+                       fprintf( out_file, ", %d", mod_song_restart_pos[mod_num] );
+               else
+                       fprintf( out_file, " %d", mod_song_restart_pos[mod_num] );
+       }
+
+       fprintf( out_file, "\n" );
+}
+
+/*
+   static void MOD_WritePeriodConvTable( FILE* out_file, int mix_rate )
+   {
+   int i, freq;
+
+   fprintf( out_file, "\nconst UWORD AAS_MOD_period_conv_table[2048] = { 65535" );
+
+   for( i = 1; i < 2048; ++i )
+   {
+   freq = (int)((((double)7093789.2)/((double)(2*i))));
+   if ( freq > 65535 )
+   freq = 65535;
+   fprintf( out_file, ", %d", freq );
+   }
+
+   fprintf( out_file, " };\n" );
+   }
+   */
+
+static int last_samp_length = 0;
+
+static int RAW_LoadSound( const char* filename, DATAPACK* sfx )
+{
+       int data = -1;
+       struct stat file_info;
+
+       if ( stat( filename, &file_info ) == 0 )
+       {
+               FILE* in_file;
+               int length;
+               length = file_info.st_size;
+
+               in_file = fopen( filename, "rb" );
+               if ( in_file )
+               {
+                       BYTE* samp = (BYTE*)malloc( length+16 );
+
+                       /*printf( "\nRAW_LoadSound( %s ): Reading...\n", filename ); */
+
+                       last_samp_length = length;
+
+                       fread( samp+16, 1, length, in_file );
+                       fclose( in_file );
+
+                       memcpy( samp, samp+length, 16 );
+
+                       MISC_ProcessSound( samp, length+16 );
+
+                       data = DATA_Append( sfx, (UBYTE*)samp, length+16 ) + 16;
+
+                       free( samp );
+
+                       printf( "Done!\n\n" );
+               }
+               else
+               {
+                       printf( "\nRAW_LoadSound( %s ): Unable to open...\n", filename );
+               }
+       }
+       else
+       {
+               printf( "\nRAW_LoadSound( %s ): Unable to open...\n", filename );
+       }
+
+       return data;
+}
+
+static int WAV_LoadSound( const char* filename, DATAPACK* sfx )
+{
+       int data = -1;
+       FILE* in_file;
+
+       last_samp_length = 0;
+
+       in_file = fopen( filename, "rb" );
+       if ( in_file )
+       {
+               ULONG tmp;
+
+               fread( &tmp, 4, 1, in_file );
+
+               if ( tmp == 0x46464952 ) /* "RIFF" */
+               {
+                       fread( &tmp, 4, 1, in_file );
+                       fread( &tmp, 4, 1, in_file );
+
+                       if ( tmp == 0x45564157 ) /* "WAVE" */
+                       {
+                               fread( &tmp, 4, 1, in_file );
+
+                               if ( tmp == 0x20746d66 ) /* "fmt " */
+                               {
+                                       unsigned short format;
+
+                                       fread( &tmp, 4, 1, in_file );
+                                       fread( &format, 2, 1, in_file );
+
+                                       if ( format == 1 ) /* PCM format */
+                                       {
+                                               unsigned short channels;
+
+                                               fread( &channels, 2, 1, in_file );
+
+                                               if ( channels == 1 ) /* mono */
+                                               {
+                                                       unsigned short bits_per_sample;
+
+                                                       fread( &tmp, 4, 1, in_file ); /* sample rate in hz */
+                                                       fread( &tmp, 4, 1, in_file );
+                                                       fread( &tmp, 2, 1, in_file );
+                                                       fread( &bits_per_sample, 2, 1, in_file );
+
+                                                       if ( bits_per_sample == 8 )
+                                                       {
+                                                               int ret, length;
+                                                               BOOL done;
+
+                                                               done = FALSE;
+                                                               length = 0;
+
+                                                               do
+                                                               {
+                                                                       ret = fread( &tmp, 4, 1, in_file );
+
+                                                                       if ( ret == 1 )
+                                                                       {
+                                                                               if ( tmp == 0x61746164 ) /* "data" */
+                                                                               {
+                                                                                       ret = fread( &length, 4, 1, in_file );
+
+                                                                                       if ( ret == 1 )
+                                                                                       {
+                                                                                               if ( length > 0 )
+                                                                                               {
+                                                                                                       done = TRUE;
+                                                                                               }
+                                                                                       }
+                                                                                       else
+                                                                                       {
+                                                                                               done = TRUE;
+                                                                                       }
+                                                                               }
+                                                                               else
+                                                                               {
+                                                                                       int size;
+
+                                                                                       ret = fread( &size, 4, 1, in_file );
+
+                                                                                       if ( ret == 1 )
+                                                                                       {
+                                                                                               fseek( in_file, size, SEEK_CUR );
+                                                                                       }
+                                                                                       else
+                                                                                       {
+                                                                                               done = TRUE;
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                                       else
+                                                                       {
+                                                                               done = TRUE;
+                                                                       }
+                                                               }
+                                                               while ( !done );
+
+                                                               if ( length > 0 )
+                                                               {
+                                                                       BYTE* samp = (BYTE*)malloc( length+16 );
+
+                                                                       last_samp_length = length;
+
+                                                                       fread( samp+16, 1, length, in_file );
+
+                                                                       memcpy( samp, samp+length, 16 );
+
+                                                                       MISC_ConvSoundToSigned( (UBYTE*)samp, length+16 );
+
+                                                                       MISC_ProcessSound( samp, length+16 );
+
+                                                                       data = DATA_Append( sfx, (UBYTE*)samp, length+16 ) + 16;
+
+                                                                       free( samp );
+
+                                                                       printf( "Done!\n\n" );
+                                                               }
+                                                               else
+                                                               {
+                                                                       printf( "Failed: Unable to find valid data subchunk...\n" );
+                                                               }
+                                                       }
+                                                       else
+                                                       {
+                                                               printf( "\nWAV_LoadSound( %s ): Failed: Not 8 bit...\n", filename );
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       printf( "\nWAV_LoadSound( %s ): Failed: Not mono...\n", filename );
+                                               }
+                                       }
+                                       else
+                                       {
+                                               printf( "\nWAV_LoadSound( %s ): Failed: Not in PCM format...\n", filename );
+                                       }
+                               }
+                               else
+                               {
+                                       printf( "\nWAV_LoadSound( %s ): Failed: Missing fmt subchunk...\n", filename );
+                               }
+                       }
+                       else
+                       {
+                               printf( "\nWAV_LoadSound( %s ): Failed: Not a WAVE file...\n", filename );
+                       }
+               }
+               else
+               {
+                       printf( "\nWAV_LoadSound( %s ): Failed: RIFF header missing...\n", filename );
+               }
+
+               fclose( in_file );
+       }
+       else
+       {
+               printf( "\nWAV_LoadSound( %s ): Failed: Unable to open...\n", filename );
+       }
+
+       return data;
+}
+
+__inline static char String_GetChar( const char* txt, int offset )
+{
+       return *(txt+offset);
+}
+
+static BOOL String_EndsWithMOD( const char* txt )
+{
+       int txt_len = strlen( txt );
+
+       if ( txt_len > 4 )
+       {
+               if ( (String_GetChar( txt, txt_len-4 ) == '.') &&
+                               ((String_GetChar( txt, txt_len-3 ) == 'm') || (String_GetChar( txt, txt_len-3 ) == 'M')) &&
+                               ((String_GetChar( txt, txt_len-2 ) == 'o') || (String_GetChar( txt, txt_len-2 ) == 'O')) &&
+                               ((String_GetChar( txt, txt_len-1 ) == 'd') || (String_GetChar( txt, txt_len-1 ) == 'D')) )
+               {
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+static BOOL String_EndsWithRAW( const char* txt )
+{
+       int txt_len = strlen( txt );
+
+       if ( txt_len > 4 )
+       {
+               if ( (String_GetChar( txt, txt_len-4 ) == '.') &&
+                               ((String_GetChar( txt, txt_len-3 ) == 'r') || (String_GetChar( txt, txt_len-3 ) == 'R')) &&
+                               ((String_GetChar( txt, txt_len-2 ) == 'a') || (String_GetChar( txt, txt_len-2 ) == 'A')) &&
+                               ((String_GetChar( txt, txt_len-1 ) == 'w') || (String_GetChar( txt, txt_len-1 ) == 'W')) )
+               {
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+static BOOL String_EndsWithWAV( const char* txt )
+{
+       int txt_len = strlen( txt );
+
+       if ( txt_len > 4 )
+       {
+               if ( (String_GetChar( txt, txt_len-4 ) == '.') &&
+                               ((String_GetChar( txt, txt_len-3 ) == 'w') || (String_GetChar( txt, txt_len-3 ) == 'W')) &&
+                               ((String_GetChar( txt, txt_len-2 ) == 'a') || (String_GetChar( txt, txt_len-2 ) == 'A')) &&
+                               ((String_GetChar( txt, txt_len-1 ) == 'v') || (String_GetChar( txt, txt_len-1 ) == 'V')) )
+               {
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+static void String_MakeSafe( char* temp )
+{
+       char c;
+
+       while( *temp != (char)0 )
+       {
+               c = *temp;
+               if ( !(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9'))) )
+                       *temp = '_';
+               ++temp;
+       }
+}
+
+static void ShowHelp()
+{
+       printf( " Usage: Conv2AAS input_dir\n\n" );
+       printf( "  input_dir  Directory containing all Protracker\n" );
+       printf( "             MODs & sample data\n\n" );
+       printf( "  Output goes to files AAS_Data.s & AAS_Data.h\n" );
+}
+
+int main( int argc, char *argv[] )
+{
+       setbuf( stdout, 0 );
+
+       printf( "\n" );
+       printf( "/---------------------------------------------\\\n" );
+       printf( "| Conv2AAS v1.11        WAV, RAW & MOD -> AAS |\n" );
+       printf( "| Copyright (c) 2005, Apex Designs            |\n" );
+       printf( "\\---------------------------------------------/\n\n" );
+
+       if ( argc < 2 )
+       {
+               ShowHelp();
+       }
+       else if ( (argc == 2) && ((strcmp( argv[1], "-help" ) == 0) || (strcmp( argv[1], "-?" ) == 0)) )
+       {
+               ShowHelp();
+       }
+       else
+       {
+               FILE* out_file_s;
+
+               out_file_s = fopen( "data/aas_data.s", "w" );
+               if ( out_file_s )
+               {
+                       FILE* out_file_h;
+
+                       out_file_h = fopen( "data/aas_data.h", "w" );
+                       if ( out_file_h )
+                       {
+                               DIR* dir_info;
+
+                               dir_info = opendir( argv[1] );
+                               if ( dir_info )
+                               {
+                                       int files_converted = 0;
+                                       int mods_found = 0;
+                                       DATAPACK* samples;
+                                       DATAPACK* patterns;
+                                       struct dirent* file_info;
+
+                                       samples = DATA_Create( "AAS_SampleData" );
+                                       patterns = DATA_Create( "AAS_PatternData" );
+
+                                       fprintf( out_file_h, "#ifndef __AAS_DATA__\n#define __AAS_DATA__\n\n#include \"AAS.h\"\n\n#if AAS_VERSION != 0x111\n#error AAS version does not match Conv2AAS version\n#endif\n\nAAS_BEGIN_DECLS\n" );
+
+                                       fprintf( out_file_s, ".TEXT\n.SECTION .rodata\n.ALIGN\n.ARM\n\n.ALIGN\n.EXTERN AAS_lib_v111\n.GLOBAL AAS_data_v111\nAAS_data_v111:\n.word AAS_lib_v111\n" );
+
+                                       do
+                                       {
+                                               file_info = readdir( dir_info );
+                                               if ( file_info )
+                                               {
+                                                       char temp[512];
+
+                                                       strcpy( temp, argv[1] );
+                                                       strcat( temp, "/" );
+                                                       strcat( temp, file_info->d_name );
+
+                                                       if ( String_EndsWithMOD( file_info->d_name ) )
+                                                       {
+                                                               ++files_converted;
+                                                               printf( "Adding MOD %s...", file_info->d_name );
+                                                               MOD_ConvMod( out_file_h, samples, patterns, temp, mods_found );
+                                                               /*printf( "Done!\n" ); */
+                                                               strcpy( temp, file_info->d_name );
+                                                               *(temp + strlen(temp) - 4) = 0;
+                                                               String_MakeSafe( temp );
+                                                               fprintf( out_file_h, "\nextern const AAS_u8 AAS_DATA_MOD_%s;\n", temp );
+                                                               fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_MOD_%s\nAAS_DATA_MOD_%s:\n.byte %d\n", temp, temp, mods_found );
+                                                               ++mods_found;
+                                                       }
+                                                       else if ( String_EndsWithRAW( file_info->d_name ) )
+                                                       {
+                                                               int val;
+                                                               ++files_converted;
+                                                               printf( "Adding RAW %s...", file_info->d_name );
+                                                               val = RAW_LoadSound( temp, samples );
+                                                               if ( val >= 0 )
+                                                               {
+                                                                       strcpy( temp, file_info->d_name );
+                                                                       *(temp + strlen(temp) - 4) = 0;
+                                                                       String_MakeSafe( temp );
+                                                                       fprintf( out_file_h, "\nextern const AAS_s8* const AAS_DATA_SFX_START_%s;\n", temp );
+                                                                       fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_SFX_START_%s\nAAS_DATA_SFX_START_%s:\n.word AAS_SampleData + %d\n", temp, temp, val );
+                                                                       fprintf( out_file_h, "\nextern const AAS_s8* const AAS_DATA_SFX_END_%s;\n", temp );
+                                                                       fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_SFX_END_%s\nAAS_DATA_SFX_END_%s:\n.word AAS_SampleData + %d\n", temp, temp, val+last_samp_length );
+                                                               }
+                                                       }
+                                                       else if ( String_EndsWithWAV( file_info->d_name ) )
+                                                       {
+                                                               int val;
+                                                               ++files_converted;
+                                                               printf( "Adding WAV %s...", file_info->d_name );
+                                                               val = WAV_LoadSound( temp, samples );
+                                                               if ( val >= 0 )
+                                                               {
+                                                                       strcpy( temp, file_info->d_name );
+                                                                       *(temp + strlen(temp) - 4) = 0;
+                                                                       String_MakeSafe( temp );
+                                                                       fprintf( out_file_h, "\nextern const AAS_s8* const AAS_DATA_SFX_START_%s;\n", temp );
+                                                                       fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_SFX_START_%s\nAAS_DATA_SFX_START_%s:\n.word AAS_SampleData + %d\n", temp, temp, val );
+                                                                       fprintf( out_file_h, "\nextern const AAS_s8* const AAS_DATA_SFX_END_%s;\n", temp );
+                                                                       fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_SFX_END_%s\nAAS_DATA_SFX_END_%s:\n.word AAS_SampleData + %d\n", temp, temp, val+last_samp_length );
+                                                               }
+                                                       }
+                                               }
+                                       } while ( file_info );
+
+                                       closedir( dir_info );
+
+                                       fprintf( out_file_s, "\n.ALIGN\n.GLOBAL AAS_DATA_NUM_MODS\nAAS_DATA_NUM_MODS:\n.short %d\n", mods_found );
+
+                                       MOD_WriteSamples( out_file_s, mods_found );
+                                       MOD_WritePatterns( out_file_s, mods_found );
+                                       MOD_WriteNumChans( out_file_s, mods_found );
+                                       MOD_WriteSongRestartPos( out_file_s, mods_found );
+
+                                       /*MOD_WritePeriodConvTable( out_file_h, 24002 ); */
+
+                                       DATA_Write( samples, out_file_s );
+                                       DATA_Write( patterns, out_file_s );
+
+                                       printf( "\n" );
+
+                                       fprintf( out_file_h, "\nAAS_END_DECLS\n\n#endif\n" );
+                               }
+                               else
+                               {
+                                       printf( "Unable to open directory %s...\n", argv[1] );
+                               }
+
+                               fclose( out_file_h );
+                       }
+                       else
+                       {
+                               printf( "Unable to open AASData.h for writing...\n" );
+                       }
+
+                       fclose( out_file_s );
+               }
+               else
+               {
+                       printf( "Unable to open AASData.s for writing...\n" );
+               }
+       }
+
+       return 0;
+}