From: John Tsiombikas Date: Tue, 13 Apr 2021 07:46:00 +0000 (+0300) Subject: dropped aas, moved to maxmod X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=gbajam21;a=commitdiff_plain;h=622fc6ef720a41a066e1bfcbdc6e003609da2da7 dropped aas, moved to maxmod --- diff --git a/.gitignore b/.gitignore index 20f6b68..bf8108b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,13 @@ cfg.mk *.elf *.a pngdump -conv2aas +mmutil tungen *.ppm *.png +*.sav +disasm +data +*.tar.gz +*.zip +pushdata diff --git a/Makefile b/Makefile index bf91267..a83188f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ src = $(wildcard src/*.c) ssrc = $(wildcard src/*.s) -obj = $(src:.c=.o) $(ssrc:.s=.o) $(dataobj) +obj = $(src:.c=.o) $(ssrc:.s=.o) dep = $(src:.c=.d) name = gbajam21 elf = $(name).elf @@ -10,9 +10,8 @@ data = data/tuncross.raw data/tuncross.pal \ data/tun.map audata = data/audio/popcorn.mod -dataobj = data/aas_data.o -libs = libs/aas/libaas.a +libs = libs/maxmod/libmm.a TCPREFIX = arm-none-eabi- @@ -25,7 +24,7 @@ EMU = vbam opt = -O3 -fomit-frame-pointer -mcpu=arm7tdmi -mtune=arm7tdmi -mthumb -mthumb-interwork dbg = -g -inc = -I. -Ilibs/aas +inc = -I. -Ilibs/maxmod CFLAGS = $(opt) $(dbg) -pedantic -Wall -MMD $(def) $(inc) ASFLAGS = -mthumb-interwork @@ -41,7 +40,7 @@ $(bin): $(elf) $(OBJCOPY) -O binary $(elf) $(bin) gbafix -r0 $(bin) -$(elf): data/aas_data.h $(obj) $(libs) +$(elf): data/snd.h $(obj) $(libs) $(CC) -o $(elf) $(obj) -specs=gba.specs $(LDFLAGS) -include $(dep) @@ -51,12 +50,12 @@ src/data.o: src/data.s $(data) tools/pngdump/pngdump: $(MAKE) -C tools/pngdump -tools/conv2aas/conv2aas: - $(MAKE) -C tools/conv2aas - tools/tungen: tools/tungen.c cc -o $@ $< -lm +tools/mmutil/mmutil: + $(MAKE) -C tools/mmutil + #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 $^ @@ -69,10 +68,10 @@ tools/tungen: tools/tungen.c data/tun.map: tools/tungen tools/tungen -s 240x160 >$@ -data/aas_data.h: data/aas_data.s +data/snd.bin: $(audata) tools/mmutil/mmutil + tools/mmutil/mmutil -o$@ -hdata/snd.h $(audata) -data/aas_data.s: $(audata) tools/conv2aas/conv2aas - tools/conv2aas/conv2aas data/audio +data/snd.h: data/snd.bin .PHONY: clean clean: @@ -84,7 +83,7 @@ cleandep: .PHONY: cleanlibs cleanlibs: - $(MAKE) -C libs/aas clean + $(MAKE) -C libs/maxmod clean .PHONY: install install: $(bin) @@ -110,5 +109,5 @@ disasm: $(elf) .PHONY: libs libs: $(libs) -libs/aas/libaas.a: - $(MAKE) -C libs/aas +libs/maxmod/libmm.a: + $(MAKE) -C libs/maxmod diff --git a/libs/aas/AAS.h b/libs/aas/AAS.h deleted file mode 100644 index e92d549..0000000 --- a/libs/aas/AAS.h +++ /dev/null @@ -1,121 +0,0 @@ -/* 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 deleted file mode 100644 index 684f71f..0000000 --- a/libs/aas/AAS_ASM.s +++ /dev/null @@ -1,299 +0,0 @@ -@ 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 - orr r3,r3,#0xd4 - stmia r3,{r0-r2} - bx lr diff --git a/libs/aas/AAS_MOD.c b/libs/aas/AAS_MOD.c deleted file mode 100644 index a6a2e2b..0000000 --- a/libs/aas/AAS_MOD.c +++ /dev/null @@ -1,932 +0,0 @@ -/* 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 deleted file mode 100644 index dae0c73..0000000 --- a/libs/aas/AAS_Main.c +++ /dev/null @@ -1,698 +0,0 @@ -/* 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 deleted file mode 100644 index 646d56a..0000000 --- a/libs/aas/AAS_Mixer.h +++ /dev/null @@ -1,62 +0,0 @@ -/* 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 deleted file mode 100644 index 7f1e20f..0000000 --- a/libs/aas/AAS_Mixer.s +++ /dev/null @@ -1,632 +0,0 @@ -@ 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 deleted file mode 100644 index f8f4c41..0000000 --- a/libs/aas/AAS_SFX.c +++ /dev/null @@ -1,217 +0,0 @@ -/* 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 deleted file mode 100644 index b6f11d3..0000000 --- a/libs/aas/AAS_Shared.c +++ /dev/null @@ -1,737 +0,0 @@ -/* 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 deleted file mode 100644 index 877c0d2..0000000 --- a/libs/aas/AAS_Shared.h +++ /dev/null @@ -1,83 +0,0 @@ -/* 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 deleted file mode 100644 index 21b4e59..0000000 --- a/libs/aas/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -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 -g -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/libs/maxmod/Makefile b/libs/maxmod/Makefile new file mode 100644 index 0000000..f7a4356 --- /dev/null +++ b/libs/maxmod/Makefile @@ -0,0 +1,17 @@ +src = $(wildcard *.S) +obj = $(src:.S=.o) +lib_a = libmm.a + +TCPREFIX ?= arm-none-eabi- +CC = $(TCPREFIX)gcc +AS = $(TCPREFIX)as +AR = $(TCPREFIX)ar + +ASFLAGS = -mcpu=arm7tdmi -mtune=arm7tdmi -mthumb -mthumb-interwork -DSYS_GBA -DUSE_IWRAM + +$(lib_a): $(obj) + $(AR) rcs $@ $(obj) + +.PHONY: clean +clean: + rm -f $(obj) $(lib_a) diff --git a/libs/maxmod/license.txt b/libs/maxmod/license.txt new file mode 100644 index 0000000..265395b --- /dev/null +++ b/libs/maxmod/license.txt @@ -0,0 +1,23 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> + +#ifdef __cplusplus +extern "C" { +#endif + +// precalculated mix buffer lengths (in bytes) +#define MM_MIXLEN_8KHZ 544 // (8121 hz) +#define MM_MIXLEN_10KHZ 704 // (10512 hz) +#define MM_MIXLEN_13KHZ 896 // (13379 hz) +#define MM_MIXLEN_16KHZ 1056 // (15768 hz) +#define MM_MIXLEN_18KHZ 1216 // (18157 hz) +#define MM_MIXLEN_21KHZ 1408 // (21024 hz) +#define MM_MIXLEN_27KHZ 1792 // (26758 hz) +#define MM_MIXLEN_31KHZ 2112 // (31536 hz) + +// measurements of channel types (bytes) +#define MM_SIZEOF_MODCH 40 +#define MM_SIZEOF_ACTCH 28 +#define MM_SIZEOF_MIXCH 24 + +/**************************************************************************** + * mmInitDefault( mm_addr soundbank, mm_word number_of_channels ) + * + * Initialize Maxmod with default settings. + ****************************************************************************/ + +void mmInitDefault( mm_addr soundbank, mm_word number_of_channels ); + +/**************************************************************************** + * mmInit( mm_gba_system* setup ) + * + * Initialize system. Call once at startup. + ****************************************************************************/ + +void mmInit( mm_gba_system* setup ); + +/**************************************************************************** + * mmVBlank() + * + * Must be linked to the VBlank IRQ. + ****************************************************************************/ + +void mmVBlank( void ); + +/**************************************************************************** + * mmSetVBlankHandler( void* function ) + * + * Install user vblank handler + * + * function : Pointer to your VBlank handler. + ****************************************************************************/ + +void mmSetVBlankHandler( void* function ); + +/**************************************************************************** + * mmSetEventHandler( mm_callback handler ) + * + * Install handler to receive song events. + ****************************************************************************/ + +void mmSetEventHandler( mm_callback handler ); + +/**************************************************************************** + * mmFrame() + * + * Work routine. _Must_ be called every frame. + ****************************************************************************/ + +void mmFrame( void ) __attribute((long_call)); + + + +/**************************************************************************** + * + * Module Playback + * + ****************************************************************************/ + + + +/**************************************************************************** + * mmStart( mm_word id, mm_pmode mode ) + * + * Start module playback. + * + * id : ID of module to play. + * mode : Playback mode (loop/once) + ****************************************************************************/ + +void mmStart( mm_word id, mm_pmode mode ); + +/**************************************************************************** + * mmPause() + * + * Pause module playback, resume with mmResume(). + ****************************************************************************/ + +void mmPause( void ); + +/**************************************************************************** + * mmResume() + * + * Resume module playback, pause with mmPause(). + ****************************************************************************/ + +void mmResume( void ); + +/**************************************************************************** + * mmStop() + * + * Stop module playback. start again with mmStart(). + ****************************************************************************/ + +void mmStop( void ); + +/**************************************************************************** + * mmGetPosition() + * + * Get playback position. + ****************************************************************************/ + +mm_word mmGetPosition( void ); + +/**************************************************************************** + * mmPosition() + * + * Set playback position. + * + * position: New position in the module sequence. + ****************************************************************************/ + +void mmPosition( mm_word position ); + +/**************************************************************************** + * mmSetPosition() + * + * Set playback position (alias for mmPosition()). + * + * position: New position in the module sequence. + ****************************************************************************/ + +inline void mmSetPosition( mm_word position ) +{ + mmPosition( position ); +} + +/**************************************************************************** + * mmActive() + * + * Returns nonzero if module is playing. + ****************************************************************************/ + +int mmActive( void ); + +/**************************************************************************** + * mmJingle( mm_word module_ID ) + * + * Play module as jingle. Jingles are limited to 4 channels only. + * + * module_ID : ID of moudle (defined in soundbank header) + ****************************************************************************/ + +void mmJingle( mm_word module_ID ); + +/**************************************************************************** + * mmActiveSub() + * + * Returns nonzero if a jingle is actively playing. + ****************************************************************************/ + +int mmActiveSub( void ); + +/**************************************************************************** + * mmSetModuleVolume( mm_word volume ) + * mmSetJingleVolume( mm_word volume ) + * + * Set volume scaler for music/jingles. + * + * volume : 0->1024 = silent..normal + ****************************************************************************/ + +void mmSetModuleVolume( mm_word volume ); +void mmSetJingleVolume( mm_word volume ); + +/***************************************************************** + * mmSetModuleTempo( mm_word tempo ) + * + * Set tempo of playback. + * + * tempo : Fixed point (Q10) value representing tempo. + * Range = 0x200 -> 0x800 = 0.5 -> 2.0 + *****************************************************************/ + +void mmSetModuleTempo( mm_word tempo ); + +/***************************************************************** + * mmSetModulePitch( mm_word pitch ) + * + * Set pitch of playback. + * + * pitch : Range = 0x200 -> 0x800 = 0.5 -> 2.0 + *****************************************************************/ + +void mmSetModulePitch( mm_word pitch ); + +/**************************************************************************** + * mmPlayModule( mm_word address, mm_word mode, mm_word layer ) + * + * Play direct MAS file + ****************************************************************************/ + +void mmPlayModule( mm_word address, mm_word mode, mm_word layer ); + + + +/**************************************************************************** + * + * Sound Effects + * + ****************************************************************************/ + + + +/**************************************************************************** + * mmEffect( mm_word sample_ID ) + * + * Play a sound effect at its default frequency with full volume and + * centered panning. + * + * sample_ID : Sound effect ID. (defined in soundbank header) + ****************************************************************************/ + +mm_sfxhand mmEffect( mm_word sample_ID ); + +/**************************************************************************** + * mmEffectEx( mm_sound_effect* sound ) + * + * Play a sound effect with all parameters. + * + * sound : Sound effect attributes. + ****************************************************************************/ + +mm_sfxhand mmEffectEx( mm_sound_effect* sound ); + +/**************************************************************************** + * mmEffectVolume( mm_sfxhand handle, mm_word volume ) + * + * Set the volume of a sound effect. + * + * handle : Sound effect handle. + * volume : 0->65535 + ****************************************************************************/ + +void mmEffectVolume( mm_sfxhand handle, mm_word volume ); + +/**************************************************************************** + * mmEffectPanning( mm_sfxhand handle, mm_word panning ) + * + * Set the panning of a sound effect. + * + * handle : Sound effect handle. + * panning : 0->255 = left..right + ****************************************************************************/ + +void mmEffectPanning( mm_sfxhand handle, mm_byte panning ); + +/**************************************************************************** + * mmEffectRate( mm_sfxhand handle, mm_word rate ) + * + * Set the playback rate of an effect. + * + * handle : Sound effect handle. + * rate: 6.10 factor + ****************************************************************************/ + +void mmEffectRate( mm_sfxhand handle, mm_word rate ); + +/**************************************************************************** + * mmEffectScaleRate( mm_sfxhand handle, mm_word factor ) + * + * Scale the playback rate of an effect. + * + * handle : Sound effect handle. + * factor : 6.10 fixed point factor. + ****************************************************************************/ + +void mmEffectScaleRate( mm_sfxhand handle, mm_word factor ); + +/**************************************************************************** + * mmEffectActive( mm_sfxhand handle ) + * + * Indicates if a sound effect is active or not. + * + * handle : Sound effect handle. + ****************************************************************************/ + +mm_bool mmEffectActive( mm_sfxhand handle ); + +/**************************************************************************** + * mmEffectCancel( mm_sfxhand handle ) + * + * Stop sound effect. + * + * handle : Sound effect handle. + ****************************************************************************/ + +void mmEffectCancel( mm_sfxhand handle ); + +/**************************************************************************** + * mmEffectRelease( mm_sfxhand handle ) + * + * Release sound effect (invalidate handle and allow interruption) + * + * handle : Sound effect handle. + ****************************************************************************/ + +void mmEffectRelease( mm_sfxhand handle ); + +/**************************************************************************** + * mmSetEffectsVolume( mm_word volume ) + * + * Set master volume scale for effect playback. + * + * volume : 0->1024 representing 0%->100% volume + ****************************************************************************/ + +void mmSetEffectsVolume( mm_word volume ); + +/**************************************************************************** + * mmEffectCancelAll() + * + * Stop all sound effects + ****************************************************************************/ + +void mmEffectCancelAll(); + + + +#ifdef __cplusplus +} +#endif + +/**************************************************************************** + * Playback events + ****************************************************************************/ + +//--------------------------------------------------------------------------- +// This happens when Maxmod reads a SFx (or mod/xm EFx) effect from a module +// It will store 'x' in param_b +//--------------------------------------------------------------------------- +#define MMCB_SONGMESSAGE 0x2A +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// A module has finished playing +// param == 0 if main module, ==1 otherwise +//--------------------------------------------------------------------------- +#define MMCB_SONGFINISHED 0x2B +//--------------------------------------------------------------------------- + +/**************************************************************************** + * etc... + ****************************************************************************/ + +extern mm_byte mp_mix_seg; // current mixing segment +extern mm_word mp_writepos; // mixer's write position + +#endif diff --git a/libs/maxmod/maxmod7.h b/libs/maxmod/maxmod7.h new file mode 100644 index 0000000..a51b2d6 --- /dev/null +++ b/libs/maxmod/maxmod7.h @@ -0,0 +1,483 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> + +//---------------------------------------------------------------- +#ifdef __cplusplus +extern "C" { +#endif +//---------------------------------------------------------------- + +/***************************************************************** + * mmInstall( channel ) + * + * Install Maxmod. + * + * channel : IPC/FIFO channel to use, usually 7. + *****************************************************************/ + +void mmInstall( int fifo_channel ); + +/***************************************************************** + * mmLockChannels( mm_word bitmask ) + * + * Lock audio channels from being used by Maxmod. + * + * bitmask : Bitmask of which channels should be locked. + * (&1 = ch0, &2 = ch1, &4 = ch2, &8 = ch4, etc...) + *****************************************************************/ + +void mmLockChannels( mm_word bitmask ); + +/***************************************************************** + * mmUnlockChannels( mm_word bitmask ) + * + * Unlock audio channels so Maxmod can use them. + * + * bitmask : Bitmask of which channels should be unlocked. + * (&1 = ch0, &2 = ch1, &4 = ch2, &8 = ch4, etc...) + *****************************************************************/ + +void mmUnlockChannels( mm_word bitmask ); + +/***************************************************************** + * mmIsInitialize() + * + * Returns whether or not the system is ready for playback. + *****************************************************************/ + +mm_bool mmIsInitialized( void ); + +/***************************************************************** + * mmSelectMode( mm_mode_enum mode ) + * + * Select audio mode + * + * mode: + * MM_MODE_A : Hardware Mixing + * MM_MODE_B : Interpolated Mixing + * MM_MODE_C : Extended Mixing + *****************************************************************/ + +void mmSelectMode( mm_mode_enum mode ); + +/***************************************************************** + * mmFrame() + * + * Work routine (called automatically) + *****************************************************************/ + +void mmFrame( void ); + +// note about using sleep functions: +// do not use during an interrupt!! it's not safe +// and do not exit sleep unless it is already sleeping. + + + +/***************************************************************** + * + * Module Playback + * + *****************************************************************/ + + + +/***************************************************************** + * mmStart( mm_word module_ID, mm_pmode mode ) + * + * Start module playback + * + * module_ID : Index of module to play. (defined in soundbank header) + * mode : Mode of playback: MM_PLAY_ONCE or MM_PLAY_LOOP + *****************************************************************/ + +void mmStart( mm_word module_ID, mm_pmode mode ); + +/***************************************************************** + * mmPause() + * + * Pause module playback. + *****************************************************************/ + +void mmPause( void ); + +/***************************************************************** + * mmResume() + * + * Resume module playback + *****************************************************************/ + +void mmResume( void ); + +/***************************************************************** + * mmStop() + * + * Stop module playback. Start again (from the beginning) + * with mmStart(...). + *****************************************************************/ + +void mmStop( void ); + +/***************************************************************** + * mmPosition( mm_word position ) + * + * Set playback position. + * + * position : New position in module sequence. + *****************************************************************/ + +void mmPosition( mm_word position ); + +/***************************************************************** + * mmActive() + * + * Returns nonzero if module is playing + *****************************************************************/ + +mm_bool mmActive( void ); + +/***************************************************************** + * mmJingle( mm_word module_ID ) + * + * Play module as jingle. Jingles are limited to 4 channels only. + * + * module_ID : ID of module (defined in soundbank header) + *****************************************************************/ + +void mmJingle( mm_word module_ID ); + +/***************************************************************** + * mmActiveSub() + * + * Returns nonzero if a jingle is actively playing. + *****************************************************************/ + +mm_bool mmActiveSub( void ); + +/***************************************************************** + * mmSetModuleVolume( mm_word volume ) + * mmSetJingleVolume( mm_word volume ) + * + * Set volume scaler for music/jingles. + * + * volume : 0->1024 = silent..normal + *****************************************************************/ + +void mmSetModuleVolume( mm_word volume ); +void mmSetJingleVolume( mm_word volume ); + +/***************************************************************** + * mmPlayModule( mm_word address, mm_word mode, mm_word layer ) + * + * Play direct MAS file + *****************************************************************/ + +void mmPlayModule( mm_word address, mm_word mode, mm_word layer ); + + + +/***************************************************************** + * + * Sound Effects + * + *****************************************************************/ + + + +/***************************************************************** + * mmEffect( mm_word sample_ID ) + * + * Play a sound effect at its default frequency with full volume + * and centered panning. Effect must be loaded first via + * mmLoadEffect. + * + * sample_ID : Sound effect ID. (defined in soundbank header) + *****************************************************************/ + +mm_sfxhand mmEffect( mm_word sample_ID ); + +/***************************************************************** + * mmEffectEx( mm_sound_effect* sound ) + * + * Play a sound effect with the parameters supplied. + * + * sound : Sound effect attributes. + *****************************************************************/ + +mm_sfxhand mmEffectEx( mm_sound_effect* sound ); + +/***************************************************************** + * mmEffectVolume( mm_sfxhand handle, mm_word volume ) + * + * Set the volume of a sound effect. + * + * handle : Sound effect handle. + * volume : 0->65535 + *****************************************************************/ + +void mmEffectVolume( mm_sfxhand handle, mm_word volume ); + +/***************************************************************** + * mmEffectPanning( mm_sfxhand handle, mm_word panning ) + * + * Set the panning of a sound effect. + * + * handle : Sound effect handle. + * panning : 0->255 = left..right + *****************************************************************/ + +void mmEffectPanning( mm_sfxhand handle, mm_byte panning ); + +/***************************************************************** + * mmEffectRate( mm_sfxhand handle, mm_word rate ) + * + * Set the playback rate of an effect. + * + * handle : Sound effect handle. + * rate: 6.10 factor + *****************************************************************/ + +void mmEffectRate( mm_sfxhand handle, mm_word rate ); + +/***************************************************************** + * mmEffectScaleRate( mm_sfxhand handle, mm_word factor ) + * + * Scale the playback rate of an effect. + * + * handle : Sound effect handle. + * factor : 6.10 fixed point factor. + *****************************************************************/ + +void mmEffectScaleRate( mm_sfxhand handle, mm_word factor ); + +/***************************************************************** + * mmEffectCancel( mm_sfxhand handle ) + * + * Stop sound effect. + * + * handle : Sound effect handle. + *****************************************************************/ + +void mmEffectCancel( mm_sfxhand handle ); + +/***************************************************************** + * mmEffectRelease( mm_sfxhand handle ) + * + * Release sound effect (invalidate handle and allow interruption) + * + * handle : Sound effect handle. + *****************************************************************/ + +void mmEffectRelease( mm_sfxhand handle ); + +/***************************************************************** + * mmSetEffectsVolume( mm_word volume ) + * + * Set master volume scale for effect playback. + * + * volume : 0->1024 representing 0%->100% volume + *****************************************************************/ + +void mmSetEffectsVolume( mm_word volume ); + +/***************************************************************** + * mmEffectCancelAll() + * + * Stop all sound effects + *****************************************************************/ + +void mmEffectCancelAll(); + + + +/***************************************************************** + * + * Streaming + * + *****************************************************************/ + + +/***************************************************************** + * mmStreamOpen( mm_stream* stream, mm_addr wavebuffer, mm_addr workbuffer ) + * + * Open audio stream. + * + * stream : Configuration struct + * wavebuffer : wave memory, must be aligned + * workbuffer : work memory, must be aligned + *****************************************************************/ + +void mmStreamOpen( mm_stream* stream, mm_addr wavebuffer, mm_addr workbuffer ); + +/***************************************************************** + * mmStreamUpdate() + * + * Fills the stream with wave data. + * This only needs to be called in 'manual' mode. It + * is called automatically in 'auto' mode. + *****************************************************************/ + +void mmStreamUpdate( void ); + +/***************************************************************** + * mmStreamClose() + * + * Close audio stream. + *****************************************************************/ + +void mmStreamClose( void ); + +/***************************************************************** + * mmStreamGetPosition() + * + * Get number of samples elapsed since the stream was opened. + * The 32-bit value will wrap every 36 hours or so (at 32khz) + *****************************************************************/ + +mm_word mmStreamGetPosition(); + + + +/***************************************************************** + * + * Reverb + * + *****************************************************************/ + + + +/***************************************************************** + * mmReverbEnable() + * + * Enable reverb system. (use before configuring!) + *****************************************************************/ + +void mmReverbEnable( void ); + +/***************************************************************** + * mmReverbConfigure( mm_reverb_cfg* config ) + * + * Configure reverb parameters. + * config : Configuration data. + *****************************************************************/ + +void mmReverbConfigure( mm_reverb_cfg* config ); + +/***************************************************************** + * mmReverbStart( mm_reverbch channels ) + * + * Start reverb output. + *****************************************************************/ + +void mmReverbStart( mm_reverbch channels ); + +/***************************************************************** + * mmReverbStop( mm_reverch channels ) + * + * Stop reverb output. + *****************************************************************/ + +void mmReverbStop( mm_reverbch channels ); + +/***************************************************************** + * mmReverbBufferSize( mm_word bit_depth, mm_word sampling_rate, + * mm_word delay ) + * + * Calculate reverb buffer size based on bit depth, delay + * and sampling rate. + * + * bit_depth : Pass 8 or 16 for 8-bit/16-bit + * sampling_rate : + * delay : In milliseconds + * + * Returns size in WORDS. + *****************************************************************/ + +static inline mm_word mmReverbBufferSize( mm_word bit_depth, mm_word sampling_rate, mm_word delay ) +{ + if( bit_depth == 16 ) + { + return ((((sampling_rate * delay * 2) / 1000) + 3) & (~3)) / 4; + } + else + { + return ((((sampling_rate * delay) / 1000) + 3) & (~3)) / 4; + } +} + +/***************************************************************** + * mmReverbDisable() + * + * Disable reverb system. + *****************************************************************/ + +void mmReverbDisable( void ); + + + +//---------------------------------------------------------------- +#ifdef __cplusplus +} +#endif +//---------------------------------------------------------------- + +/***************************************************************** + * Playback events + *****************************************************************/ + +//---------------------------------------------------------------- +// This happens when Maxmod reads an SFx (or mod/xm EFx) effect +// from a module. It will pass 'x' in param. +//---------------------------------------------------------------- +#define MMCB_SONGMESSAGE 0x2A +//---------------------------------------------------------------- + +//---------------------------------------------------------------- +// A module has finished playing. +// param == 0 if main module, ==1 otherwise +//---------------------------------------------------------------- +#define MMCB_SONGFINISHED 0x2B +//---------------------------------------------------------------- + +//======================================================================================= +// misc definitions / references +//======================================================================================= + +// main/sub layer attributes +extern mm_modlayer mmLayerMain; +extern mm_modlayer mmLayerSub; + +#endif diff --git a/libs/maxmod/mm_effect.S b/libs/maxmod/mm_effect.S new file mode 100644 index 0000000..5c92ffc --- /dev/null +++ b/libs/maxmod/mm_effect.S @@ -0,0 +1,767 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> 0x10000 = external sample + bne 1f // + ldr r0,=mmSampleBank // ID# otherwise + ldr r0, [r0] // + lsl r1, #2 // + ldr r1, [r0, r1] // + lsl r1, #8 // + lsr r1, #8 // + beq .invalid_sample + add r1, #8 // + ldr r0,=0x2000000 // + add r1, r0 // +1: // + str r1, [r3, #MIXER_CHN_SAMP] // + + + ldrh r0, [r4, #MM_SFX_RATE] // set pitch to original * pitch + ldrh r1, [r1, #C_SAMPLEC_DFREQ] // + mul r1, r0 // + lsr r1, #10 // + strh r1, [r3, #MIXER_CHN_FREQ] // + + mov r1, #0 // clear sample offset + str r1, [r3, #MIXER_CHN_READ] // + + ldrb r1, [r4, #MM_SFX_PANNING] // set panning + startbit + lsr r1, #1 // + add r1, #0x80 // + strb r1, [r3, #MIXER_CHN_CNT] // + + ldrb r1, [r4, #MM_SFX_VOLUME] // set volume + ldr r0,=mm_sfx_mastervolume + ldr r0, [r0] + mul r1, r0 +// lsr r0, #10 + lsr r2, r1, #2 +// lsl r2, r1, #8 + + strh r2, [r3, #MIXER_CHN_VOL] // + + b .valid_sample +.invalid_sample: + mov r0, #0 + str r0, [r3, #MIXER_CHN_SAMP] + +.valid_sample: + +#endif + + mov r0, r5 // return handle + pop {r4-r6} // + ret1 // + +.no_available_channels: + mov r0, #0 // return bad + pop {r4-r6} // + ret1 // + + + +/*********************************************************************** + * mme_get_channel_index + * + * Test handle and return mixing channel index + ***********************************************************************/ + .thumb_func +mme_get_channel_index: + + lsl r1, r0, #24 // mask and test channel# + lsr r1, #24-1 // + cmp r1, #0 // + beq .invalid_handle // + cmp r1, #channelCount*2 // + bgt .invalid_handle // + + ldr r2,=mm_sfx_channels-2 // check if instances match + ldrh r3, [r2, r1] // + lsr r1, r3, #8 // + lsr r2, r0, #8 // + cmp r1, r2 // + bne .invalid_handle // + + lsl r3, #24 // mask channel# + lsr r3, #24 // + sub r3, #1 // + bx lr // + +.invalid_handle: // return invalid handle + mov r3, #0 // + mvn r3, r3 // + bx lr // + +/*********************************************************************** + * mmEffectActive( handle ) + * + * Indicates if a sound effect is active or not + ***********************************************************************/ + .global mmEffectActive + .thumb_func +mmEffectActive: + push {lr} // + bl mme_get_channel_index // + cmp r3, #0 // if r3 >= 0, it is active + bge .active // + mov r0, #0 // return false + pop {r3} // + bx r3 // + +.active: // + mov r0, #1 // return true + pop {r3} // + bx r3 // + +/*********************************************************************** + * mme_clear_channel(ch) + * + * Clear channel entry and bitmask + * r3 preserved + ***********************************************************************/ + .thumb_func +mme_clear_channel: + mov r1, #0 + ldr r2,=mm_sfx_channels // clear effect channel + lsl r0, #1 // + strh r1, [r2, r0] // + + mov r1, #1 // clear effect bitmask + lsr r0, #1 // + lsl r1, r0 // + ldr r2,=mm_sfx_bitmask // + ldr r0, [r2, #4] + orr r0, r1 + str r0, [r2, #4] + ldr r0, [r2] // + bic r0, r1 // + str r0, [r2] // + bx lr + +/*********************************************************************** + * mmEffectVolume( handle, volume ) + * + * Set effect volume + * + * volume 0..255 + ***********************************************************************/ + .global mmEffectVolume + .thumb_func +mmEffectVolume: + + push {r1, lr} + + bl mme_get_channel_index + pop {r1} + bmi 1f + + ldr r0,=mm_sfx_mastervolume + ldr r0, [r0] + mul r1, r0 + + #ifdef SYS_NDS + + lsr r1, #2 + + #endif + + #ifdef SYS_GBA + + lsr r1, #10 + + #endif + + mov r0, r3 + + bl mmMixerSetVolume + +1: ret0 + +/*********************************************************************** + * mmEffectPanning( handle, panning ) + * + * Set effect panning + * + * panning 0..255 + ***********************************************************************/ + .global mmEffectPanning + .thumb_func +mmEffectPanning: + + push {r1, lr} + bl mme_get_channel_index + pop {r1} + bmi 1f + + mov r0, r3 + bl mmMixerSetPan + +1: ret0 + +/*********************************************************************** + * mmEffectRate( handle, rate ) + * + * Set effect playback rate + ***********************************************************************/ + .global mmEffectRate + .thumb_func +mmEffectRate: + + push {r1, lr} + bl mme_get_channel_index + pop {r1} + bmi 1f + + mov r0, r3 + bl mmMixerSetFreq + +1: ret0 + +/*********************************************************************** + * mmEffectCancel( handle ) + * + * Stop sound effect + ***********************************************************************/ + .global mmEffectCancel + .thumb_func +mmEffectCancel: + + push {r0, lr} + + bl mme_get_channel_index + + pop {r0} + + bmi 1f + + mov r1, #MCA_SIZE // free achannel + mul r1, r3 // + ldr r2,=mm_achannels // + ldr r2, [r2] // + add r2, r1 // + mov r1, #ACHN_BACKGROUND // + strb r1, [r2, #MCA_TYPE] // + mov r1, #0 // + strb r1, [r2, #MCA_FVOL] // clear volume for channel allocator + + lsl r0, #24 + lsr r0, #24 + sub r0, #1 + bl mme_clear_channel + + mov r1, #0 // zero voice volume + mov r0, r3 // + bl mmMixerSetVolume // + + mov r0, #1 + ret1 +1: + mov r0, #0 + ret1 + +/*********************************************************************** + * mmEffectRelease( channel ) + * + * Release sound effect (allow interruption) + ***********************************************************************/ + .global mmEffectRelease + .thumb_func +mmEffectRelease: + + push {r0, lr} + + bl mme_get_channel_index + pop {r0} + + bmi 1f + + mov r1, #MCA_SIZE // release achannel + mul r1, r3 // + ldr r2,=mm_achannels // + ldr r2, [r2] // + add r2, r1 // + mov r1, #ACHN_BACKGROUND // + strb r1, [r2, #MCA_TYPE] // + + lsl r0, #24 + lsr r0, #24 + sub r0, #1 + bl mme_clear_channel + +1: ret0 + +/*********************************************************************** + * mmEffectScaleRate( channel, factor ) + * + * Scale sampling rate by 6.10 factor + ***********************************************************************/ + .global mmEffectScaleRate + .thumb_func +mmEffectScaleRate: + + push {r1,lr} + + bl mme_get_channel_index + pop {r1} + + bmi 1f + + mov r0, r3 + bl mmMixerMulFreq + +1: ret0 + +/*********************************************************************** + * mmSetEffectsVolume( volume ) + * + * set master volume scale, 0->1024 + ***********************************************************************/ + .global mmSetEffectsVolume + .thumb_func +mmSetEffectsVolume: + + lsr r1, r0, #10 + beq 1f + mov r0, #1 + lsl r0, #10 + +1: ldr r1,=mm_sfx_mastervolume + str r0, [r1] + bx lr + +/*********************************************************************** + * mmEffectCancelAll() + * + * Stop all sound effects + ***********************************************************************/ + .global mmEffectCancelAll + .thumb_func +mmEffectCancelAll: + + push {r4-r7,lr} + + ldr r4,=mm_sfx_bitmask + ldr r4, [r4] + ldr r6,=mm_sfx_channels + mov r5, #0 + + + lsr r4, #1 + bcc .mmeca_next +.mmeca_process: + + ldrb r7, [r6, r5] + sub r7, #1 + bmi .mmeca_next + + mov r0, r7 + mov r1, #0 + bl mmMixerSetVolume + + ldr r0,=mm_achannels // free achannel + ldr r0, [r0] // + mov r1, #MCA_SIZE // + mul r1, r7 // + add r0, r1 // + mov r1, #ACHN_BACKGROUND // + strb r1, [r0, #MCA_TYPE] // + mov r1, #0 + strb r1, [r0, #MCA_FVOL] // + +.mmeca_next: + add r5, #2 + lsr r4, #1 + bcs .mmeca_process + bne .mmeca_next + + bl mmResetEffects + + POP {r4-r7} + pop {r3} + bx r3 + +/*********************************************************************** + * mmUpdateEffects() + * + * Update sound effects + ***********************************************************************/ + .global mmUpdateEffects + .thumb_func +mmUpdateEffects: + + push {r4-r6,lr} + + ldr r4,=mm_sfx_bitmask + ldr r4, [r4] + ldr r6,=mm_sfx_channels + mov r5, #0 + + lsr r4, #1 + bcc .next_channel +.process_channel: + + ldrb r0, [r6, r5] // get channel index + sub r0, #1 // + bmi .next_channel // + + GET_MIXCH r1 + + mov r2, #MIXER_CHN_SIZE // get mixing channel pointer + mul r2, r0 // + add r1, r2 // + + #ifdef SYS_NDS // test if channel is still active + // + ldr r2, [r1, #MIXER_CHN_SAMP] // + lsl r2, #8 // + bne .next_channel // + // + #else // + // + ldr r2, [r1, #MIXER_CHN_SRC] // + asr r2, #31 // + beq .next_channel // + // + #endif // + + ldr r1,=mm_achannels // free achannel + ldr r1, [r1] // + mov r2, #MCA_SIZE // + mul r2, r0 // + add r1, r2 // + mov r0, #0 // + strb r0, [r1, #MCA_TYPE] // + strb r0, [r1, #MCA_FLAGS] // + strb r0, [r6, r5] + +.next_channel: + add r5, #2 // look for another set bit + lsr r4, #1 // + bcs .process_channel // + add r5, #2 // + lsr r4, #1 // + bcs .process_channel // + bne .next_channel // + + mov r4, #0 + mov r5, #1 + lsl r5, #32-channelCount + ldr r6,=mm_sfx_channels + +.build_new_bitmask: + ldrb r0, [r6] + add r6, #2 + cmp r0, #0 + beq 1f + orr r4, r5 +1: lsl r5, #1 + bne .build_new_bitmask + + lsr r4, #32-channelCount + ldr r0,=mm_sfx_bitmask + ldr r1, [r0] // r1 = bits that change from 1->0 + mov r2, r1 + eor r1, r4 + and r1, r2 + + str r4, [r0] + ldr r4, [r0, #4] + orr r4, r1 + str r4, [r0, #4] // write 1->0 mask + + pop {r4-r6,pc} + +.pool + +.end diff --git a/libs/maxmod/mm_init_default.S b/libs/maxmod/mm_init_default.S new file mode 100644 index 0000000..d5b3cd0 --- /dev/null +++ b/libs/maxmod/mm_init_default.S @@ -0,0 +1,97 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> mixlen? + blt .mpf_mix_adv @ no, mix and process tick + b .mpf_mix @ yes, mix the rest of samples + +.mpf_mix_adv: + + mov r1, #MPL_SAMPCOUNT @ reset sample counter + mov r7, #0 @ + strh r7, [r0,r1] @ + sub r4, r5 @ subtract from #samples to mix + + PROF_START + + mov r0, r5 + ldr r7,=mmMixerMix @ mix samples + bl _call_via_r7 + + PROF_END 0 + + ldr r7,=mppProcessTick + bl _call_via_r7 + + b .mpf_mix_advr @ process more samples +.mpf_mix: + +@ add samples remaining to SAMPCOUNT +@ and mix more samples + + mov r1, #MPL_SAMPCOUNT + add r6, r4 + strh r6, [r0, r1] + mov r0, r4 + PROF_START + ldr r1,=mmMixerMix + bl _call_via_r1 + PROF_END 0 + + pop {r4-r7} + ret1 @ return to user + +.mpf_no_mainlayer: + +@ main layer isn't active, +@ mix full amount + + mov r0, r4 + + PROF_START + ldr r1,=mmMixerMix + bl _call_via_r1 + PROF_END 0 + + pop {r4-r7} + ret1 + +.pool + +//----------------------------------------------------------------------------- +#endif +//----------------------------------------------------------------------------- + + + +/****************************************************************************** + * + * NDS + * + ******************************************************************************/ + + + +//----------------------------------------------------------------------------- +#ifdef SYS_NDS +//----------------------------------------------------------------------------- + + .TEXT + .THUMB + .ALIGN 2 + +/****************************************************************************** + * mmSuspendIRQ_t + * + * Function to disable interrupts via the status register + ******************************************************************************/ + .global mmSuspendIRQ_t + .thumb_func +mmSuspendIRQ_t: + ldr r0,=1f + bx r0 + +.arm +.align 2 +1: mrs r0, cpsr + and r1, r0, #0x80 + orr r0, #0x80 + msr cpsr, r0 + str r1, previous_irq_state + bx lr +.thumb + +/****************************************************************************** + * mmRestoreIRQ_t + * + * Function to enable interrupts via the status register + ******************************************************************************/ + .global mmRestoreIRQ_t + .thumb_func +mmRestoreIRQ_t: + ldr r0,=1f + bx r0 + +.arm +.align 2 +1: mrs r0, cpsr + ldr r1, previous_irq_state + bic r0, #0x80 + orr r0, r1 + msr cpsr, r0 + bx lr + +.thumb + +previous_irq_state: + .space 4 + + .thumb_func +/****************************************************************************** + * mmIsInitialized() + * + * Returns true if the system is ready for playback + ******************************************************************************/ + .global mmIsInitialized + .thumb_func +mmIsInitialized: + ldr r0,=mmInitialized + ldrb r0, [r0] + bx lr + +/****************************************************************************** + * mmInit7() + * + * Initialize system + ******************************************************************************/ + .global mmInit7 + .thumb_func +mmInit7: + push {lr} + mov r0, #0x08 + ldr r1,=mmFrame + bl irqSet + + mov r0, #0x08 + bl irqEnable + + ldr r0,=0x400 // set volumes + bl mmSetModuleVolume // + ldr r0,=0x400 // + bl mmSetJingleVolume // + ldr r0,=0x400 // + bl mmSetEffectsVolume // + + ldr r0,=mmInitialized // set initialized flag + mov r1, #42 // + strb r1, [r0] // + + ldr r0,=0xFFFF // select all hardware channels + bl mmUnlockChannels // + + ldr r0,=mm_achannels // setup channel addresses + ldr r1,=mm_rds_achannels // + str r1, [r0] // + ldr r1,=mm_rds_pchannels // + str r1, [r0,#4] // + mov r1, #32 // 32 channels + str r1, [r0,#8] // + str r1, [r0,#12] // + + ldr r0,=0x400 + bl mmSetModuleTempo + + ldr r0,=0x400 + bl mmSetModulePitch + + bl mmResetEffects + + bl mmMixerInit // setup mixer + + ldr r0,=mmEventForwarder // forward events + bl mmSetEventHandler + + ldr r0,=mmInitialized // set initialized flag + mov r1, #42 // + strb r1, [r0] // + +.exit_r3: + pop {r3} + bx r3 + +/****************************************************************************** + * mmInstall( channel ) + * + * Install ARM7 system + ******************************************************************************/ + .global mmInstall + .thumb_func +mmInstall: + push {lr} + + ldr r1,=mmInitialized // not initialized until we get soundbank data + mov r2, #0 // + strb r2, [r1] // + + bl mmSetupComms // setup communication + + b .exit_r3 + +/****************************************************************************** + * mmEventForwarder( msg, param ) + * + * Forward event to arm9 + ******************************************************************************/ + .thumb_func +mmEventForwarder: + + push {lr} + lsl r1, #8 + orr r0, r1 + mov r1, #1 + lsl r1, #20 + orr r0, r1 + bl mmARM9msg + pop {pc} + +/****************************************************************************** + * mmGetSoundBank( n_songs, bank ) + * + * Load sound bank address + ******************************************************************************/ + .global mmGetSoundBank + .thumb_func +mmGetSoundBank: + ldr r2,=mmModuleCount // save data + stmia r2!, {r0,r1} // + + lsl r0, #2 // also sample bank address + add r1, r0 // + stmia r2!, {r1} // + +//------------------------------------------------ +// initialize system +//------------------------------------------------ + + b mmInit7 + +/****************************************************************************** + * mmFrame() + * + * Routine function + ******************************************************************************/ + .global mmFrame + .thumb_func +mmFrame: + + push {lr} + + ldr r0,=mmInitialized // catch not-initialized + ldrb r0, [r0] // + cmp r0, #42 // + bne 1f // + + bl mmMixerPre // <-- critical timing + + ldr r0,=0x4000208 // enable irq + mov r1, #1 // + strh r1, [r0] // + + bl mmUpdateEffects // update sound effects + bl mmPulse // update module playback + bl mmMixerMix // update audio + + + bl mmSendUpdateToARM9 + +1: bl mmProcessComms // process communications + + ret1 + +.pool + +//----------------------------------------------------------------------------- +#endif +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +.end +//----------------------------------------------------------------------------- + diff --git a/libs/maxmod/mm_mas.S b/libs/maxmod/mm_mas.S new file mode 100644 index 0000000..9cc9c9e --- /dev/null +++ b/libs/maxmod/mm_mas.S @@ -0,0 +1,4960 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> 1024 + ******************************************************************************/ + .global mmSetModuleVolume + .thumb_func +mmSetModuleVolume: + +@ clamp volume 0->1024 + lsr r1, r0, #10 + beq 1f + mov r0, #1 + lsl r0, #10 + +@ set volume +1: ldr r1,=mmLayerMain + mov r2, #MPL_VOLUME + strh r0, [r1, r2] + bx lr + +/****************************************************************************** + * mmSetJingleVolume( volume ) + * + * Set master jingle volume. + * + * volume : 0->1024 + ******************************************************************************/ + .global mmSetJingleVolume + .thumb_func +mmSetJingleVolume: + +@ clamp volume 0->1024 + lsr r1, r0, #10 + beq 1f + mov r0, #1 + lsl r0, #10 + +@ set volume +1: ldr r1,=mmLayerSub @mpp_layerB + mov r2, #MPL_VOLUME + strh r0, [r1, r2] + bx lr + +/****************************************************************************** + * mppStop() [[internal function]] + * + * Stop module playback. + ******************************************************************************/ + .thumb_func +mppStop: + + push {lr} + + ldr r0,=mpp_clayer + ldrb r0, [r0] + + cmp r0, #0 + beq 1f + ldr r5,=mmLayerSub + ldr r6,=mm_schannels + mov r7, #MP_SCHANNELS + b 2f +1: ldr r5,=mmLayerMain + @ldr r6,=mpp_pchannels + ldr r6,=mm_pchannels + ldr r6,[r6] + @mov r7, #MP_MCHANNELS + ldr r7,=mm_num_mch + ldr r7,[r7] +2: + + mov r0, #0 + strb r0, [r5, #MPL_ISPLAYING] + + mov r1, #MPL_VALID + strb r0, [r5, r1] + + bl mpp_resetchannels + pop {r0} + bx r0 + +/****************************************************************************** + * mmGetPosition() + * + * Get playback position + ******************************************************************************/ + .global mmGetPosition + .thumb_func +mmGetPosition: + + ldr r1,=mmLayerMain + ldrb r0, [r1, #MPL_POSITION] + bx lr + +/****************************************************************************** + * mmPosition( position ) + * + * Set playback position + ******************************************************************************/ + .global mmPosition + .thumb_func +mmPosition: + + push {r4-r7,lr} + ldr r5,=mmLayerMain + ldr r6,=mm_pchannels + ldr r6,[r6] + ldr r7,=mm_num_mch + ldr r7, [r7] + + push {r0} +// bl mpp_resetchannels + + pop {r0} + bl mpp_setposition + + pop {r4-r7} + pop {r3} + bx r3 + +/****************************************************************************** + * mmSetModuleTempo( tempo ) + * + * Set master tempo + * + * tempo : x.10 fixed point tempo, 0.5->2.0 + ******************************************************************************/ + .global mmSetModuleTempo + .thumb_func +mmSetModuleTempo: + + push {r5,lr} + + mov r1, #1 // clamp value: 512->2048 + lsl r1, #11 // + cmp r0, r1 // + ble 1f // + mov r0, r1 // +1: mov r1, #1 // + lsl r1, #9 // + cmp r0, r1 // + bge 1f // + mov r0, r1 // +1: + + ldr r1,=mm_mastertempo + str r0, [r1] + + ldr r5,=mmLayerMain + ldr r0,=mpp_clayer + mov r1, #0 + strb r1, [r0] + + ldrb r0, [r5, #MPL_BPM] + cmp r0, #0 + beq 1f + bl mpp_setbpm + +1: pop {r5} + pop {r3} + bx r3 + +/****************************************************************************** + * mmSetModulePitch( pitch ) + * + * Set master pitch + * + * pitch : x.10 fixed point value, range = 0.5->2.0 + ******************************************************************************/ + .global mmSetModulePitch + .thumb_func +mmSetModulePitch: + push {r5,lr} + + mov r1, #1 // clamp value: 512->2048 + lsl r1, #11 // + cmp r0, r1 // + ble 1f // + mov r0, r1 // +1: mov r1, #1 // + lsl r1, #9 // + cmp r0, r1 // + bge 1f // + mov r0, r1 // +1: + + ldr r1,=mm_masterpitch + str r0, [r1] + +1: pop {r5} + pop {r3} + bx r3 + +.pool + +//----------------------------------------------------------------------------- +#ifdef SYS_NDS7 +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mmSetResolution( divider ) + * + * Set update resolution + ******************************************************************************/ + .global mmSetResolution + .thumb_func +mmSetResolution: + + push {r5, lr} + + ldr r1,=mpp_resolution + str r0, [r1] + + ldr r5,=mmLayerMain + + ldr r0,=mpp_clayer + mov r1, #0 + strb r1, [r0] + + ldrb r0, [r5, #MPL_BPM] + cmp r0, #0 + beq 1f + bl mpp_setbpm +1: ldr r5,=mmLayerSub + + ldr r0,=mpp_clayer + mov r1, #1 + strb r1, [r0] + + ldrb r0, [r5, #MPL_BPM] + cmp r0, #0 + beq 1f + bl mpp_setbpm +1: pop {r5} + pop {r3} + bx r3 + +#endif + +/****************************************************************************** + * mmStop() + * + * Stop module playback. + ******************************************************************************/ + .global mmStop + .thumb_func +mmStop: + + push {r4-r7,lr} + ldr r1,=mpp_clayer + mov r0, #0 + strb r0, [r1] + bl mppStop + pop {r4-r7} + ret3 + +/****************************************************************************** + * mpp_resetvars() + * + * Reset pattern variables + * Input r5 = layer + ******************************************************************************/ + .thumb_func +mpp_resetvars: + + mov r0, #255 + strb r0, [r5, #MPL_PATTJUMP] + mov r0, #0 + strb r0, [r5, #MPL_PATTJUMP_ROW] + bx lr + +/****************************************************************************** + * mpp_setbpm( bpm ) + * + * Set BPM. bpm = 32..255 + * Input r5 = layer + ******************************************************************************/ + .thumb_func +mpp_setbpm: + + strb r0, [r5, #MPL_BPM] + +#ifdef SYS_GBA + + ldr r1,=mpp_clayer + ldrb r1, [r1] + cmp r1, #0 + bne 1f + + ldr r1,=mm_mastertempo // multiply by master tempo + ldr r1, [r1] // + mul r1, r0 // + lsr r1, #10 // + + ldr r0,=mm_bpmdv @ samples per tick ~= mixfreq / (bpm/2.5) ~= mixfreq*2.5/bpm + ldr r0,[r0] + + swi SWI_DIVIDE @ SWI 07h, divide r1/r0 + lsr r0, #1 @ multiple of two + lsl r0, #1 @ --------------- + mov r1, #MPL_TICKRATE + strh r0, [r5, r1] @ + mov r1, #MPL_SAMPCOUNT +// mov r0, #0 +// strh r0, [r5, r1] + bx lr @ return + +1: @ SUB LAYER, time using vsync (rate = bpm/2.5 / 59.7) + + lsl r0, #15 + mov r1, #149 + swi SWI_DIVIDE + mov r1, #MPL_TICKRATE + strh r0, [r5, r1] + bx lr + +#endif + +#ifdef SYS_NDS + +@ vsync = ~59.8261 HZ (says GBATEK) +@ divider = hz * 2.5 * 64 + + ldr r1,=mpp_clayer + ldrb r1, [r1] + cmp r1, #0 + bne 1f + ldr r1,=mm_mastertempo // multiply by master tempo + ldr r1, [r1] // + mul r0, r1 // +// lsr r1, #10 // + + lsl r0, #16+6-10 + b 2f +1: + lsl r0, #16+6 +2: + @ using 60hz vsync for timing +// lsl r0, #16+6 + ldr r1,=mpp_resolution + ldr r1, [r1] + swi SWI_DIVIDE + lsr r0, #1 + mov r1, #MPL_TICKRATE + strh r0, [r5, r1] + bx lr + +#endif + +.pool + +/****************************************************************************** + * mpp_setposition( position ) + * + * Set sequence position. + * Input r5 = layer + ******************************************************************************/ + .thumb_func +mpp_setposition: + + push {lr} + +mpp_setpositionA: + + strb r0, [r5, #MPL_POSITION] + + ldr r1, [r5, #MPL_SONGADR] + mov r3, r1 + add r1, #C_MAS_ORDER @ get sequence entry + ldrb r1, [r1, r0] @ + + cmp r1, #254 + bne .mpsp_skippatt + add r0, #1 + b mpp_setpositionA +.mpsp_skippatt: + + cmp r1, #255 + bne .mpsp_endsong + + @ END OF SONG!!! WOOPHEE!!!! + + + mov r0, #MPL_MODE @mpp_playmode + ldrb r0, [r5, r0] + + cmp r0, #MPP_PLAY_ONCE + bge 1f +@ @ its looping: + b 3f + +1: @ its playing once: + + bl mppStop + mov r0, #MPCB_SONGFINISHED + ldr r2,=mmCallback + ldr r2,[r2] + cmp r2, #0 + beq 3f + ldr r1,=mpp_clayer + ldrb r1, [r1] + bl mpp_call_r2 + +3: + + ldrb r0, [r5, #MPL_ISPLAYING] + cmp r0, #0 + bne 1f + + pop {pc} + +1: + ldr r0, [r5, #MPL_SONGADR] @ set position to 'restart' + ldrb r0, [r0, #C_MAS_REP] + b mpp_setpositionA +.mpsp_endsong: + + mov r0, r1 + + ldr r1, [r5, #MPL_PATTTABLE] + lsl r0, #2 + + @ r1 = pattern address( in table ) + + ldr r1, [r1, r0] + add r1, r3 @ add song address + + @ r1 = pattern address + + ldrb r2, [r1] @ set pattern size + strb r2, [r5, #MPL_NROWS] @ + + mov r2, #0 @ reset tick/row + strh r2, [r5, #MPL_TICK] + strb r2, [r5, #MPL_FPATTDELAY] + strb r2, [r5, #MPL_PATTDELAY] + + mov r0, #MPL_PATTREAD + add r1, #1 + str r1, [r5, r0] @ store pattern data address + + mov r0, #MPL_PLOOP_ADR @ reset pattern loop + str r1, [r5, r0] + mov r0, #0 + strb r0, [r5, #MPL_PLOOP_ROW] + strb r0, [r5, #MPL_PLOOP_TIMES] + + pop {pc} + +//----------------------------------------------------------------------------- +#ifdef SYS_NDS +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mppUpdateLayer( layer ) + * + * Update module layer + ******************************************************************************/ + .thumb_func +mppUpdateLayer: + + push {lr} + ldr r1,=mpp_layerp + str r0, [r1] + mov r1, #MPL_TICKRATE + ldrh r1, [r0, r1] + mov r2, #MPL_TICKFRAC + ldrh r3, [r0, r2] + lsl r1, #1 + add r3, r1 + strh r3, [r0, r2] + lsr r3, #16 + beq 1f +2: push {r3} + + bl mppProcessTick + pop {r3} + sub r3, #1 + bne 2b +1: pop {pc} + +/****************************************************************************** + * mmPulse() + * + * NDS Work Routine + ******************************************************************************/ + .global mmPulse + .thumb_func +mmPulse: + + push {lr} + + ldr r0,=mpp_channels // update main layer + ldr r1,=mm_pchannels // + ldr r1,[r1] // + str r1, [r0] // + ldr r0,=mpp_nchannels // + ldr r1,=mm_num_mch // + ldr r1,[r1] // + strb r1, [r0] // + ldr r0,=mpp_clayer // + mov r1, #0 // + strb r1, [r0] // + // + ldr r0,=mmLayerMain // + bl mppUpdateLayer // + + ldr r0,=mpp_channels // update sub layer + ldr r1,=mm_schannels // + str r1, [r0] // + ldr r0,=mpp_nchannels // + mov r1, #MP_SCHANNELS // + strb r1, [r0] // + ldr r0,=mpp_clayer // + mov r1, #1 // + strb r1, [r0] // + // + ldr r0,=mmLayerSub // + bl mppUpdateLayer // + + pop {pc} + +//----------------------------------------------------------------------------- +#endif +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +#ifdef SYS_GBA +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mppUpdateSub() + * + * Update sub-module/jingle, this is bad for some reason... + ******************************************************************************/ + .global mppUpdateSub + .thumb_func +mppUpdateSub: + + ldr r0,=mmLayerSub + ldrb r0, [r0, #MPL_ISPLAYING] + cmp r0, #0 + bne .mppus_update + bx lr +.mppus_update: + + ldr r0,=mpp_channels + ldr r1,=mm_schannels + str r1, [r0] + ldr r0,=mpp_nchannels + mov r1, #MP_SCHANNELS + strb r1, [r0] + ldr r0,=mpp_clayer + mov r1, #1 + strb r1, [r0] + + push {lr} + ldr r0,=mmLayerSub + ldr r1,=mpp_layerp + str r0, [r1] + + mov r1, #MPL_TICKRATE + ldrh r1, [r0, r1] + mov r2, #MPL_TICKFRAC + ldrh r3, [r0, r2] + lsl r1, #1 + add r3, r1 + strh r3, [r0, r2] + lsr r3, #16 + beq 1f +2: push {r3} + ldr r1,=mppProcessTick + bl mpp_call_r1 + pop {r3} + sub r3, #1 + bgt 2b +1: pop {pc} + +//----------------------------------------------------------------------------- +#endif +//----------------------------------------------------------------------------- + +.pool + +//----------------------------------------------------------------------------- +// IWRAM CODE +//----------------------------------------------------------------------------- +#ifdef USE_IWRAM + .SECTION ".iwram", "ax", %progbits + .ALIGN 2 +#endif +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mppProcessTick() + * + * Process module tick. + ******************************************************************************/ +.global mppProcessTick @@@@@@@@@@@@@@@@@@ +.thumb_func @@@@ @@@ @@ + @@@ @@ @@@@@@ @@ +mppProcessTick: @@ @@@ @ @@ + @@ @@@@@@@ @@@ + @@@@@@@@@@@@@@@@@ + + add r0,pc,#0 // switch to ARM to preserve regs + bx r0 // +.arm // + stmfd sp!, {lr} // + stmfd sp!, {r4-r10} // + + add r0,pc,#1 // switch back to THUMB + bx r0 +.thumb + + ldr r0,=mpp_layerp // test if module is playing + ldr r0, [r0] // + mov r8, r0 // + ldrb r1, [r0, #MPL_ISPLAYING] // + cmp r1, #0 // + bne 1f // + ldr r1,=.mppt_exit // + mov pc,r1 // +1: + +@--------------------------------------------------- +@ read pattern data +@--------------------------------------------------- + + ldrb r1, [r0, #MPL_PATTDELAY] + cmp r1, #0 + bne .mpp_pt_skippatternread + ldrb r0, [r0, #MPL_TICK] + cmp r0, #0 + bne .mpp_pt_skippatternread + + PROF_START + fjump2 mmReadPattern + //bl mpp_ReadPattern + PROF_END 4 + +@----------------------------------------- +.mpp_pt_skippatternread: + + mov r0, r8 + mov r4, #MPL_MCH_UPDATE + ldr r4, [r0, r4] + +@--------------------------------------------------- +@ loop through module channels +@--------------------------------------------------- + + ldr r7,=mpp_channels + ldr r7, [r7] + mov r0, #0 + mov r10, r0 @ use r10 as channel counter + mov r0, r8 + ldrb r0, [r0, #MPL_TICK] + cmp r0, #0 + bne pchannel_loop_other + +@--------------------------------------------------- +pchannel_loop_first: +@--------------------------------------------------- + lsr r4, #1 + bcc pchannel_empty + fjump2 mmUpdateChannel_T0 +pchannel_empty: + mov r0, #1 + add r10, r0 + add r7, #MCH_SIZE + cmp r4, #0 + bne pchannel_loop_first + b pchannel_loop_finished + +@--------------------------------------------------- +pchannel_loop_other: +@--------------------------------------------------- + lsr r4, #1 + bcc pchannel_empty2 + #ifdef FOO_UC + bl mpp_Update_Channel + #else + fjump2 mmUpdateChannel_TN + #endif + +pchannel_empty2: + mov r0, #1 + add r10, r0 + add r7, #MCH_SIZE + cmp r4, #0 + bne pchannel_loop_other + +pchannel_loop_finished: + +@--------------------------------------------------- +@ loop through active channels +@--------------------------------------------------- + PROF_START + ldr r6,=mm_achannels + ldr r6, [r6] + @ldr r6,=mpp_achannels + mov r4, #0 + +@--------------------------------------------------- +.mpp_pt_achn_loop: +@--------------------------------------------------- + + ldrb r0, [r6, #MCA_TYPE] + cmp r0, #ACHN_DISABLED + beq .mpp_pt_achn_disabled + ldr r0,=mpp_clayer + ldrb r0, [r0] + ldrb r1, [r6, #MCA_FLAGS] + lsr r1, #6 + cmp r1, r0 + bne .mpp_pt_achn_next + + ldr r1,=mpp_vars + ldrb r0, [r6, #MCA_VOLUME] + strb r0, [r1, #MPV_AFVOL] + mov r0, #0 + strh r0, [r1, #MPV_PANPLUS] + + ldr r5, [r6, #MCA_PERIOD] + + bl mpp_Update_ACHN + + b .mpp_pt_achn_next + +@--------------------------------------------------- +.mpp_pt_achn_disabled: +@ mov r0, r4 +@ bl mp_Mixer_StopChannel + +@--------------------------------------------------- +.mpp_pt_achn_next: +@--------------------------------------------------- + + ldrb r0, [r6, #MCA_FLAGS] + mov r1, #MCAF_UPDATED + bic r0, r1 + strb r0, [r6, #MCA_FLAGS] + add r6, #MCA_SIZE + add r4, #1 + ldr r0,=mm_num_ach + ldr r0,[r0] + + cmp r4, r0 +@ cmp r4, #MP_NCHANNELS + bne .mpp_pt_achn_loop +@--------------------------------------------------- + PROF_END 6 + + + + ldr r1,=mppProcessTick_incframe + mov pc,r1 + +.pool + +//----------------------------------------------------------------------------- +// TEXT Code +//----------------------------------------------------------------------------- + .TEXT + .THUMB + .ALIGN 2 +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mppProcessTick_incframe [[internal]] + ******************************************************************************/ + .thumb_func +mppProcessTick_incframe: + +@--------------------------------------------------- +@ update tick/row/position +@--------------------------------------------------- + + mov r5, r8 @ get tick# + ldrb r1, [r5, #MPL_TICK] @ .. + add r1, #1 @ increment + + ldrb r2, [r5, #MPL_SPEED] @ compare with speed + cmp r1, r2 @ .. + blt .mppt_continuerow @ if less than, continue this row + + ldrb r2, [r5, #MPL_FPATTDELAY] + cmp r2, #0 + beq .mppt_nofpd + sub r2, #1 + strb r2, [r5, #MPL_FPATTDELAY] + b .mppt_continuerow +.mppt_nofpd: + + mov r1, #0 @ .. otherwise clear tick count + b .mppt_nextrow @ and advance to next row + +.mppt_continuerow: @ continue current row: + strb r1, [r5, #MPL_TICK] @ save tick# + b .mppt_exit @ exit + +.mppt_nextrow: @ advance row + + ldrb r2, [r5, #MPL_PATTDELAY] + cmp r2, #0 + beq .mppt_nopd + sub r2, #1 + strb r2, [r5, #MPL_PATTDELAY] + beq .mppt_nopd + b .mppt_continuerow +.mppt_nopd: + + strb r1, [r5, #MPL_TICK] @ save tick# (0) + ldrb r1, [r5, #MPL_PATTJUMP] + cmp r1, #255 + beq .mppt_no_pj + + mov r2, #255 + strb r2, [r5, #MPL_PATTJUMP] + mov r0, r1 + bl mpp_setposition + + ldrb r1, [r5, #MPL_PATTJUMP_ROW] + cmp r1, #0 + beq .mppt_pj_no_offset + mov r2, #0 + strb r2, [r5, #MPL_PATTJUMP_ROW] + bl mpph_FastForward +.mppt_pj_no_offset: + + b .mppt_exit + +.mppt_no_pj: + + mov r3, #MPL_PLOOP_JUMP + ldrb r1, [r5, r3] + cmp r1, #0 + beq .mppt_no_ploop + mov r1, #0 + strb r1, [r5, r3] + ldrb r1, [r5, #MPL_PLOOP_ROW] + strb r1, [r5, #MPL_ROW] + mov r3, #MPL_PLOOP_ADR + ldr r1, [r5, r3] + + mov r3, #MPL_PATTREAD + str r1, [r5, r3] + b .mppt_exit +.mppt_no_ploop: + ldrb r1, [r5, #MPL_ROW] @ .. + add r1, #1 @ increment + ldrb r2, [r5, #MPL_NROWS] @ + add r2, #1 + cmp r1, r2 @ check with #rows for pattern + bne .mppt_continuepattern @ if !=, then continue playing this pattern + +.mppt_nextposition: @ advance position + + ldrb r0, [r5, #MPL_POSITION] @ increment position + add r0, #1 + + bl mpp_setposition + b .mppt_exit + +.mppt_continuepattern: + + strb r1, [r5, #MPL_ROW] @ save row count + +.thumb_func +.mppt_exit: + + @ switch to arm + ldr r0,=.mppt_exita + bx r0 +.arm +.align 2 +.mppt_exita: + + ldmfd sp!, {r4-r10} + ldmfd sp!, {r0} + bx r0 +.thumb + +.pool + +//----------------------------------------------------------------------------- +// IWRAM CODE +//----------------------------------------------------------------------------- +#ifdef USE_IWRAM + .SECTION ".iwram", "ax", %progbits + .ALIGN 2 +#endif +//----------------------------------------------------------------------------- + +/****************************************************************************** + * mpp_Channel_NewNote() + * + * Process new note. + * Input r7 = pchannel address + ******************************************************************************/ + .global mpp_Channel_NewNote + .thumb_func +mpp_Channel_NewNote: + + @ r7 = pchannel address + push {r4,lr} + + ldrb r0, [r7, #MCH_INST] @ get instrument# + sub r0, #1 + bcc .mppt_skipnna + + bl mpp_Channel_GetACHN + cmp r6, #0 + beq .mppt_alloc_channel + + ldrb r0, [r7, #MCH_INST] @ get instrument# + sub r0, #1 + + mpp_InstrumentPointer + + ldrb r1, [r7, #MCH_BFLAGS] @ fetch NNA + lsr r1, #6 + + beq .mppt_NNA_CUT @ skip if zero + + ldrb r1, [r0, #C_MASI_DCT] @ otherwise check duplicate check type + lsl r1, #32-2 + lsr r1, #32-2 + lsl r1, #1 @ jump to mppt_DCT_TABLE[dct] + add r1, pc + mov pc, r1 + +.mppt_DCT_TABLE: +b .mppt_DCNA +b .mppt_DCT_NOTE +b .mppt_DCT_SAMP +b .mppt_DCT_INST +.mppt_DCT_NOTE: @ DCT note --------------------- + ldrb r1, [r7, #MCH_PNOTE] @ get pattern note + lsl r1, #1 @ translate to real note + add r1, #C_MASI_MAP @ with note/sample map + ldrb r1, [r0, r1] @ r1 = real note + ldrb r2, [r7, #MCH_NOTE] @ compare with last note + cmp r1, r2 @ + beq .mppt_DCA @ equal? perform DCA + b .mppt_DCNA @ otherwise skip + +.mppt_DCT_SAMP: @ DCT sample ------------------- + + // **WARNING: code not functional with new instrument table + ldrb r1, [r7, #MCH_PNOTE] @ get pattern note + lsl r1, #1 @ translate to sample# + add r1, #C_MASI_MAP+1 @ with note/sample map + ldrb r1, [r0, r1] @ r1 = sample# + ldrb r2, [r6, #MCA_SAMPLE] @ compare with achn's sample + cmp r1, r2 @ + beq .mppt_DCA @ equal? perform DCA + b .mppt_DCNA @ otherwise skip + +.mppt_DCT_INST: @ DCT instrument --------------- + ldrb r1, [r7, #MCH_INST] @ load instrument + ldrb r2, [r6, #MCA_INST] @ compare with active inst + cmp r1, r2 @ + bne .mppt_DCNA @ not equal? skip DCA + +.mppt_DCA: @ DUPLICATE CHECK ACTION ------- + ldrb r1, [r0, #C_MASI_DCA] @ read type + cmp r1, #IT_DCA_CUT @ cut? + beq .mppt_NNA_CUT @ branch + cmp r1, #IT_DCA_OFF @ note-off? + beq .mppt_NNA_OFF @ branch + b .mppt_NNA_FADE @ note-fade otherwise + +.mppt_DCNA: + + ldrb r1, [r7, #MCH_BFLAGS] + lsr r1, #6 @ get NNA + lsl r1, #1 @ and jump to + add r1, pc @ NNA_TABLE[NNA] + mov pc, r1 +.mppt_NNA_TABLE: +b .mppt_NNA_CUT +b .mppt_NNA_CONTINUE +b .mppt_NNA_OFF +b .mppt_NNA_FADE + +@--------------------------------------------------------------------------------- +.mppt_NNA_CUT: +@--------------------------------------------------------------------------------- + + #ifdef SYS_NDS // nds supports volume ramping + + ldrb r1, [r6, #MCA_TYPE] + cmp r1, #0 + BEQ .mppt_samechannel + mov r1, #ACHN_BACKGROUND + strb r1, [r6, #MCA_TYPE] + mov r1, #0 + strb r1, [r6, #MCA_VOLUME] + b .mppt_NNA_FINISHED + + #else + b .mppt_samechannel + #endif + +@--------------------------------------------------------------------------------- +.mppt_NNA_CONTINUE: +@--------------------------------------------------------------------------------- + + mov r1, #ACHN_BACKGROUND @ use different channel + strb r1, [r6, #MCA_TYPE] @ set active channel to "background" + b .mppt_NNA_FINISHED @ finished + +@--------------------------------------------------------------------------------- +.mppt_NNA_OFF: +@--------------------------------------------------------------------------------- + + ldrb r1, [r6, #MCA_FLAGS] @ clear KEYON in flags byte + mov r2, #MCAF_KEYON + bic r1, r2 + + strb r1, [r6, #MCA_FLAGS] + mov r1, #ACHN_BACKGROUND @ set type to "background" + strb r1, [r6, #MCA_TYPE] + b .mppt_NNA_FINISHED @ finished + +@--------------------------------------------------------------------------------- +.mppt_NNA_FADE: +@--------------------------------------------------------------------------------- + + ldrb r1, [r6, #MCA_FLAGS] @ set NOTE FADE in flags byte + mov r2, #MCAF_FADE + orr r1, r2 + strb r1, [r6, #MCA_FLAGS] + mov r1, #ACHN_BACKGROUND @ set type to "background" + strb r1, [r6, #MCA_TYPE] @ + +.mppt_NNA_FINISHED: + +.mppt_alloc_channel: + + mov r4, r6 + + ldr r1,=mmAllocChannel + jump1 @ find new active channel + strb r0, [r7, #MCH_ALLOC] @ save number + + #ifdef SYS_NDS + + cmp r4, #0 + beq .mppt_samechannel + + mov r1, #MCA_SIZE @ copy data from previous channel + mul r0, r1 @ (for volume ramping wierdness) + ldr r1,=mm_achannels @ + ldr r1,[r1] @ + add r0, r1 @ + @ + mov r2, #MCA_SIZE/4 +1: ldmia r4!, {r1} + stmia r0!, {r1} + sub r2, #1 + bne 1b + +/* ldr r1, [r4, #MCA_FADE] @ + str r1, [r0, #MCA_FADE] @ + ldr r1, [r4, #MCA_ENVC_PAN] @ + str r1, [r0, #MCA_ENVC_PAN] @ + ldr r1, [r4, #MCA_AVIB_DEP] @ + str r1, [r0, #MCA_AVIB_DEP] @ + ldrb r1, [r4, #MCA_FLAGS] @ + strb r1, [r0, #MCA_FLAGS] @ + ldrb r1, [r4, #MCA_VOLUME] + strb r1, [r0, #MCA_VOLUME] + ldrb r1, [r4, #MCA_PANNING] + strb r1, [r0, #MCA_PANNING] + ldrb r1, [r4, #MCA_SAMPLE] + strb r1, [r0, #MCA_SAMPLE] + ldrb r1, [r4, #MCA_INST] + strb r1, [r0, #MCA_INST]*/ + + #endif + +.mppt_samechannel: + +.mppt_skipnna: + pop {r4} + pop {r3} + bx r3 + +.pool + +.align 2 +.thumb_func +@------------------------------------------------------------------------------------------------------ +mpp_Channel_GetACHN: +@------------------------------------------------------------------------------------------------------ + + @ gets the active channel pointer + @ and stores in r6 + @ gives 0 if N/A + + ldrb r0, [r7, #MCH_ALLOC] + cmp r0, #255 + bge 1f + ldr r6,=mm_achannels + ldr r6,[r6] + mov r1, #MCA_SIZE + mul r0, r1 + add r6, r0 + bx lr + +1: mov r6, #0 + bx lr +.pool + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------------------- +mpp_Update_ACHN: +@---------------------------------------------------------------------------------------------------- + +@ r5 = affected period +@ r6 = achannel address + + push {lr} @ enter subroutine + +@ check updated flag & exit if already updated + + ldrb r0, [r6, #MCA_FLAGS] + mov r1, #MCAF_UPDATED + tst r0, r1 + beq .mpp_achn_update + pop {pc} + +@-------------------------------------------- + + .global mpp_Update_ACHN_notest + .thumb_func +@---------------------------------------------------------------------------------------------------- +mpp_Update_ACHN_notest: +@---------------------------------------------------------------------------------------------------- + push {lr} + +.mpp_achn_update: + +@------------------------------------------------------------------------ +@ Envelope Processing +@------------------------------------------------------------------------ + + ldrb r0, [r6, #MCA_INST] + sub r0, #1 + bCS 1f + b .mppt_achn_noinst +1: mpp_InstrumentPointer + +@ get envelope flags + + mov r1, r0 + ldrb r2, [r1, #C_MASI_ENVFLAGS] + add r1, #C_MASI_ENVELOPES + + lsr r2, #1 @ shift out volume envelope bit + bcc .mppt_no_volenv + + ldrb r3, [r6, #MCA_FLAGS] + lsr r3, #6 + + bcs .mppt_achn_ve_enabled + ldrb r0, [r1] + add r1, r0 + b .mppt_no_volenv +.mppt_achn_ve_enabled: + + push {r1, r2} + + ldrh r0, [r6, #MCA_ENVC_VOL] + mov r2, r1 + ldrb r1, [r6, #MCA_ENVN_VOL] + bl mpph_ProcessEnvelope + strb r1, [r6, #MCA_ENVN_VOL] + strh r0, [r6, #MCA_ENVC_VOL] + mov r1, r3 + + cmp r2, #1 + bne .mpph_volenv_notend + ldrb r0, [r6, #MCA_FLAGS] + + mov r3, r8 @ stupid xm doesn't fade out at envelope end + ldrb r3, [r3, #MPL_FLAGS] + lsr r3, #C_FLAGS_XS + + mov r3, #MCAF_ENVEND + bcs 1f + mov r3, #MCAF_ENVEND+MCAF_FADE +1: + orr r0, r3 + strb r0, [r6, #MCA_FLAGS] +.mpph_volenv_notend: + + cmp r2, #1 + blt .mpph_volenv_normal + + @ check keyon and turn on fade... + ldrb r0, [r6, #MCA_FLAGS] + mov r2, #MCAF_KEYON + tst r0, r2 + bne .mpph_volenv_normal +.mpph_volenv_notefade: + mov r2, #MCAF_FADE + orr r0, r2 + strb r0, [r6, #MCA_FLAGS] + +.mpph_volenv_normal: + + ldr r0,=mpp_vars + ldrb r2, [r0, #MPV_AFVOL] + mul r2, r1 + lsr r2, #6+6 + strb r2, [r0, #MPV_AFVOL] + pop {r1, r2} + ldrb r0, [r1] + add r1, r0 + b .mppt_has_volenv +.mppt_no_volenv: + + ldrb r0, [r6, #MCA_FLAGS] + mov r3, #MCAF_ENVEND + orr r0, r3 + mov r3, #MCAF_KEYON + tst r0, r3 + bne .mppt_has_volenv + mov r3, #MCAF_FADE + orr r0, r3 + strb r0, [r6, #MCA_FLAGS] + + mov r0, r8 @ check XM MODE and cut note + ldrb r0, [r0, #MPL_FLAGS] + lsr r0, #C_FLAGS_XS + bcc .mppt_has_volenv + mov r0, #0 + strh r0, [r6, #MCA_FADE] +.mppt_has_volenv: + + lsr r2, #1 + bcc .mppt_no_panenv + push {r1, r2} + ldrh r0, [r6, #MCA_ENVC_PAN] + mov r2, r1 + ldrb r1, [r6, #MCA_ENVN_PAN] + bl mpph_ProcessEnvelope + strb r1, [r6, #MCA_ENVN_PAN] + strh r0, [r6, #MCA_ENVC_PAN] + mov r1, r3 + + ldr r0,=mpp_vars + mov r3, #MPV_PANPLUS + ldrsh r2, [r0,r3] + lsr r1, #4 + sub r1, #128 + add r2, r1 + strh r2, [r0,r3] + pop {r1, r2} +.mppt_no_panenv: + + lsr r2, #1 + bcc .mppt_no_pitchenv + ldrb r0, [r1, #C_MASIE_FILTER] + cmp r0, #0 + bne .mppt_no_pitchenv + push {r1, r2} + ldrh r0, [r6, #MCA_ENVC_PIC] + mov r2, r1 + ldrb r1, [r6, #MCA_ENVN_PIC] + bl mpph_ProcessEnvelope + strb r1, [r6, #MCA_ENVN_PIC] + strh r0, [r6, #MCA_ENVC_PIC] + mov r1, r3 + lsr r1, #3 + sub r1, #255 + mov r0, r5 + sub r1, #1 + bmi .mppt_pitchenv_minus +#ifdef USE_IWRAM + ldr r2,=mpph_LinearPitchSlide_Up + jump2 +#else + bl mpph_LinearPitchSlide_Up +#endif + b .mppt_pitchenv_plus +.mppt_pitchenv_minus: + neg r1, r1 +#ifdef USE_IWRAM + ldr r2,=mpph_LinearPitchSlide_Down + jump2 +#else + bl mpph_LinearPitchSlide_Down +#endif +.mppt_pitchenv_plus: + mov r5, r0 + pop {r1, r2} +.mppt_no_pitchenv: + + ldrb r0, [r6, #MCA_FLAGS] + mov r1, #MCAF_FADE + tst r0, r1 + beq .mppt_achn_nofade + ldrb r0, [r6, #MCA_INST] + sub r0, #1 + + mpp_InstrumentPointer + ldrb r0, [r0, #C_MASI_FADE] + + ldrh r1, [r6, #MCA_FADE] + + sub r1, r0 + bcs .mppt_achn_fadeout_clip + mov r1, #0 +.mppt_achn_fadeout_clip: + strh r1, [r6, #MCA_FADE] + +.mppt_achn_nofade: + +.mppt_achn_keyon: + + +@---------------------------------------------------------------------------------- +@ *** PROCESS AUTO VIBRATO +@---------------------------------------------------------------------------------- + + ldrb r0, [r6, #MCA_SAMPLE] + sub r0, #1 + bcc .mppt_achn_nostart @ no sample!! + + @bl mpp_SamplePointer + mpp_SamplePointer + ldrh r1, [r0, #C_MASS_VIR] @ get av-rate + cmp r1, #0 @ 0? + beq .mppt_av_disabled @ if 0 then its disabled + ldrh r2, [r6, #MCA_AVIB_DEP] @ get depth counter + add r2, r1 @ add rate + lsr r1, r2, #15 @ check for 15-bit overflow + beq .mppt_av_depclip @ .. + + ldr r2,=32768 @ and clamp to 32768 +.mppt_av_depclip: + strh r2, [r6, #MCA_AVIB_DEP] @ save depth counter + ldrb r1, [r0, #C_MASS_VID] @ get av-depth + mul r1, r2 @ multiply + + ldrb r3, [r6, #MCA_AVIB_POS] @ get table position + ldrb r2, [r0, #C_MASS_VIS] @ get av-speed + add r3, r2 @ add to position + lsl r3, #32-8 @ wrap position to 0->255 + lsr r3, #32-8 @ .. + strb r3, [r6, #MCA_AVIB_POS] @ save position + ldr r2,=mpp_TABLE_FineSineData @ get table pointer + ldrsb r2, [r2, r3] @ load table value at position + mul r2, r1 @ multiply with depth + asr r2, #23 @ shift value + bmi .mppt_av_minus @ and perform slide... +.mppt_av_plus: @ --slide up + mov r1, r2 @ r1 = slide value + mov r0, r5 @ r0 = frequency +#ifdef USE_IWRAM + fjump2 mpph_PitchSlide_Up +#else + bl mpph_PitchSlide_Up @ pitch slide +#endif + b .mppt_av_finished @ +.mppt_av_minus: @ --slide down + neg r1, r2 @ r1 = slide value + mov r0, r5 @ r0 = frequency +#ifdef USE_IWRAM + ldr r2,=mpph_PitchSlide_Down + jump2 +#else + bl mpph_PitchSlide_Down @ pitch slide +#endif + +.mppt_av_finished: + mov r5, r0 @ affect frequency +.mppt_av_disabled: + +@--------------------------------------------------------------------------------- + +.mppt_achn_noinst: + + push {r4} + mov r0, #MIXER_CHN_SIZE + mul r4, r0 + @ldr r0,=mp_channels +@ ldr r0,=mm_mixchannels +@ ldr r0,[r0] + GET_MIXCH r0 + add r4, r0 + + @ *** UPDATE MIXING INFORMATION + + ldrb r0, [r6, #MCA_FLAGS] @ read flags + mov r1, #MCAF_START @ test start bit + tst r0, r1 @ .. + beq .mppt_achn_nostart @ +.mppt_achn_start: @ START NOTE + bic r0, r1 @ clear bit + strb r0, [r6, #MCA_FLAGS] @ save flags + ldrb r0, [r6, #MCA_SAMPLE] @ get sample # + + sub r0, #1 @ .. + bcc .mppt_achn_nostart @ quit if invalid + @bl mpp_SamplePointer @ get sample address + mpp_SamplePointer + + ldrh r3, [r0, #C_MASS_MSLID] + + add r1,r3,#1 @ msl id == 0xFFFF? + lsr r1, #17 + + bcc .mppt_achn_msl_sample + +.mppt_achn_direct_sample: @ then sample follows + + add r0, #12 + +//------------------------------------------------ +#ifdef SYS_GBA +// ldr r1, [r0,#C_SAMPLE_LEN] @ setup mixer (GBA) +// lsl r1, #MP_SAMPFRAC +// str r1, [r4,#MIXER_CHN_LEN] +// ldr r1, [r0,#C_SAMPLE_LOOP] +// str r1, [r4,#MIXER_CHN_LOOP] + add r0, #C_SAMPLE_DATA + str r0, [r4,#MIXER_CHN_SRC] + +#else +//------------------------------------------- + + ldr r1,=0x2000000 + sub r0, r1 + str r0, [r4, #MIXER_CHN_SAMP] + ldrb r1, [r4, #MIXER_CHN_CNT] + mov r0, #MIXER_CF_START + orr r1, r0 + strb r1, [r4, #MIXER_CHN_CNT] + +#endif +//------------------- + + b .mppt_achn_gotsample +.mppt_achn_msl_sample: @ otherwise get from solution + + #ifdef SYS_GBA + + ldr r2,=mp_solution + ldr r2, [r2] + mov r1, r2 + add r1, #12 + lsl r3, #2 + ldr r1, [r1, r3] + add r1, #8 + add r0, r1, r2 + + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ NOTICE, USE LDM HERE + +// ldr r1, [r0,#C_SAMPLE_LEN] @ setup mixer (GBA) +// lsl r1, #MP_SAMPFRAC +// str r1, [r4,#MIXER_CHN_LEN] +// ldr r1, [r0,#C_SAMPLE_LOOP] +// str r1, [r4,#MIXER_CHN_LOOP] + add r0, #C_SAMPLE_DATA + str r0, [r4,#MIXER_CHN_SRC] + + #endif + + #ifdef SYS_NDS + + ldr r2,=mmSampleBank @ get samplebank pointer + ldr r2, [r2] + lsl r3, #2 @ add msl_id *4 + ldr r1, [r2, r3] + + lsl r1, #8 @ mask out counter value + lsr r1, #8 + add r1, #8 + + str r1, [r4,#MIXER_CHN_SAMP] + ldrb r1, [r4,#MIXER_CHN_CNT] // read control **CNT was cleared, no need to read it + mov r0, #MIXER_CF_START // set start bit + orr r1, r0 + strb r1, [r4,#MIXER_CHN_CNT] // save control + + #endif + +.mppt_achn_gotsample: + ldr r1,=mpp_vars + ldrb r1, [r1, #MPV_SAMPOFF] +#ifdef SYS_GBA + lsl r1, #MP_SAMPFRAC+8 + str r1, [r4, #MIXER_CHN_READ] +#else + str r1, [r4, #MIXER_CHN_READ] +#endif + +.mppt_achn_nostart: + @ set pitch + + ldrb r0, [r6, #MCA_SAMPLE] @ get sample# + sub r0, #1 @ .. + bcc .mppt_achn_setvolumeA + @bl mpp_SamplePointer @ quit if invalid + mpp_SamplePointer + push {r0} + + mov r1, r8 + ldrb r1, [r1, #MPL_FLAGS] + lsr r1, #C_FLAGS_SS + bcc .mppt_achn_amigafreqs +.mppt_achn_linearfreqs: + + ldrh r0, [r0, #C_MASS_FREQ] @ get C5SPEED + LSL R0, #2 + lsr r1, r5, #8 @ do some stuff... + mul r1, r0 @ ... period * freq? + + lsr r1, #8 + + ldr r0,=mpp_clayer + ldrb r0, [r0] + cmp r0, #0 + bne 1f + ldr r0,=mm_masterpitch + ldr r0, [r0] + mul r1, r0 + lsr r1, #10 +1: + + #ifdef SYS_GBA + + +// ldr r0,=mm_freqscalar +// ldr r0, [r0] + ldr r0,=(4096*65536)/15768 + mul r0, r1 + lsr r0, #16 + str r0, [r4, #MIXER_CHN_FREQ] + + #else + + ldr r0,=MIXER_SCALE + mul r0, r1 + lsr r0, #16+1 + strh r0, [r4, #MIXER_CHN_FREQ] + + //strh r1, [r4, #MIXER_CHN_FREQ] + #endif + + b .mppt_achn_setvolume + +.mppt_achn_amigafreqs: + ldr r0,=MOD_FREQ_DIVIDER_PAL + movs r1, r5 + + beq .mppt_achn_setvolume @ 0 is a bad period + swi SWI_DIVIDE + + ldr r1,=mpp_clayer + ldrb r1, [r1] + cmp r1, #0 + bne 1f + ldr r1,=mm_masterpitch + ldr r1, [r1] + mul r0, r1 + lsr r0, #10 +1: + + #ifdef SYS_GBA + +// ldr r1,=mm_freqscalar +// ldr r1,[r1] + ldr r1,=(4096*65536)/15768 + mul r0, r1 + lsr r0, #16 + + str r0, [r4, #MIXER_CHN_FREQ] + #else +// mov r1, r0 +// ldr r0,=16756991 @ calculate ds mixer timing +// swi SWI_DIVIDE +// neg r0,r0 + //lsr r0, #5 + ldr r1,=MIXER_SCALE + mul r0, r1 + lsr r0, #16+1 + strh r0, [r4, #MIXER_CHN_FREQ] + #endif + +@---------------------------------------------------------------------------------------------------- +.mppt_achn_setvolume: +@---------------------------------------------------------------------------------------------------- + + @ set volume + + pop {r0} + @ <-- stepped oct 28, 3:27pm + ldrb r3, [r0, #C_MASS_GV] @ SV, 6-bit + ldrb r0, [r6, #MCA_INST] + sub r0, #1 + bcs 1f + +.thumb_func +.mppt_achn_setvolumeA: + mov r1, #0 + b .mppt_achn_badinstrument +1: + mpp_InstrumentPointer + ldrb r0, [r0, #C_MASI_GVOL] @ IV, 7-bit + mul r3, r0 + + ldr r1,=mpp_vars + ldrb r0, [r1, #MPV_AFVOL] @ ((CV*VOL)/32*VEV/64) 7-bit + + mul r3, r0 + + mov r1, r8 @ get global vollume + ldrb r0, [r1, #MPL_FLAGS] + lsr r0, #4 + ldrb r0, [r1, #MPL_GV] @ .. 7-bit + + bcc 1f + lsl r0, #1 @ xm mode global volume is only 0->64, shift to 0->128 + +1: mul r3, r0 @ multiply + + lsr r3, #10 + + ldrh r0, [r6, #MCA_FADE] + + + mul r3, r0 + + lsr r3, r3, #10 + + mov r0, r8 + mov r1, #MPL_VOLUME + ldrh r0, [r0, r1] + mul r3, r0 + +//------------------------------------------------ +#ifdef SYS_NDS + lsr r1, r3, #19-3-5 ///#19-3 (new 16-bit levels!) + ldr r3,=65535 //2047 + cmp r1, r3 @ clip values over 255 + blt 1f + mov r1, r3 +1: +.mppt_achn_badinstrument: +// lsr r3, r1, #3 (new 16-bit levels!) + lsr r3, r1, #8 + strb r3, [r6, #MCA_FVOL] + +#else + + lsr r1, r3, #19 + cmp r1, #255 @ clip values over 255 + blt 1f + mov r1, #255 +1: +.mppt_achn_badinstrument: + strb r1, [r6, #MCA_FVOL] + +#endif + + cmp r1, #0 + bne .mppt_achn_audible + + #ifdef SYS_NDS // nds has volume ramping! + + ldrb r3, [r6, #MCA_TYPE] + cmp r3, #ACHN_BACKGROUND + bne 1f + ldrb r3, [r6, #MCA_VOLUME] + cmp r3, #0 + bne 1f + ldrh r3, [r4, #MIXER_CHN_CVOL] + cmp r3, #0 + beq .mppt_achn_not_audible + #endif + +1: ldrb r3, [r6, #MCA_FLAGS] + mov r2, #MCAF_ENVEND + tst r3, r2 + beq .mppt_achn_audible + mov r2, #MCAF_KEYON + tst r3, r2 + bne .mppt_achn_audible + +// #ifdef SYS_NDS +// ldrh r3, [r4, #MIXER_CHN_CVOL] // nds has volume ramping!! +// cmp r3, #0 +// bne .mppt_achn_audible +// #endif + +.mppt_achn_not_audible: + @ STOP CHANNEL + +#ifdef SYS_GBA + ldr r0,=1<<31 + str r0,[r4,#MIXER_CHN_SRC] @ stop mixer channel +#else + mov r0,#0 + str r0,[r4,#MIXER_CHN_SAMP] @ stop mixer channel +#endif + + ldrb r3, [r6, #MCA_TYPE] + cmp r3, #ACHN_FOREGROUND + bne .mpp_achn_noparent + ldrb r1, [r6, #MCA_PARENT] + mov r3, #MCH_SIZE + mul r1, r3 + ldr r0,=mpp_channels + ldr r0, [r0] + add r0, r1 + mov r1, #255 + strb r1, [r0, #MCH_ALLOC] +.mpp_achn_noparent: + + mov r1, #ACHN_DISABLED + strb r1, [r6, #MCA_TYPE] + b .mpp_achn_updated +.mppt_achn_audible: + +#ifdef SYS_NDS + + strh r1, [r4, #MIXER_CHN_VOL] + +#else + + strb r1, [r4, #MIXER_CHN_VOL] + +#endif + +#ifdef SYS_GBA // check if mixer channel has ended + + ldr r0, [r4, #MIXER_CHN_SRC] + asr r0, #31 + beq 1f + +#else + + ldr r0, [r4, #MIXER_CHN_SAMP] + lsl r0, #8 + bne 1f + +#endif + + ldrb r3, [r6, #MCA_TYPE] + cmp r3, #ACHN_FOREGROUND + bne 2f + + ldrb r1, [r6, #MCA_PARENT] // stop channel if channel ended + mov r3, #MCH_SIZE + mul r1, r3 + ldr r0,=mpp_channels + ldr r0, [r0] + add r0, r1 + mov r1, #255 + strb r1, [r0, #MCH_ALLOC] +2: + +#ifdef SYS_GBA + ldr r0,=1<<31 + str r0,[r4,#MIXER_CHN_SRC] @ stop mixer channel +#else + mov r0,#0 + str r0,[r4,#MIXER_CHN_SAMP] @ stop mixer channel +#endif + + mov r1, #ACHN_DISABLED + strb r1, [r6, #MCA_TYPE] + b .mpp_achn_updated + + @ set panning +1: ldr r1,=mpp_vars + mov r3, #MPV_PANPLUS + ldrsh r0, [r1,r3] + ldrb r1, [r6, #MCA_PANNING] + + add r1, r0 + + cmp r1, #0 + bge .mpp_achn_clippan1 + mov r1, #0 +.mpp_achn_clippan1: + cmp r1, #255 + ble .mpp_achn_clippan2 + mov r1, #255 +.mpp_achn_clippan2: + + #ifdef SYS_NDS + lsr r1, #1 + ldrb r0, [r4, #MIXER_CHN_CNT] + lsr r0, #7 + lsl r0, #7 + orr r0, r1 + strb r0, [r4, #MIXER_CHN_CNT] + #endif + + #ifdef SYS_GBA + strb r1, [r4, #MIXER_CHN_PAN] + #endif + + +.mpp_achn_updated: + pop {r4} + pop {r0} + bx r0 + //pop {pc} @ exit +.pool + +.align 2 +.thumb_func +@------------------------------------------------------------------------- +mpph_ProcessEnvelope: @ params={count,node,address} +@------------------------------------------------------------------------- + +@ processes the envelope at
+@ returns: +@ r0=count +@ r1=node +@ r2=exit_code +@ r3=value*64 + + push {r4,r5} + +@ get node and base + lsl r4, r1, #2 + add r4, #C_MASIE_NODES + add r4, r2 + + ldrh r3, [r4, #2] + lsl r3, #32-7 + lsr r3, #32-7-6 + +@ check for zero count + + cmp r0, #0 + bne .mpph_pe_between +.mpph_pe_new: + +@ process envelope loop + + ldrb r5, [r2, #C_MASIE_LEND] + cmp r1, r5 + bne 1f + ldrb r1, [r2, #C_MASIE_LSTART] + mov r2, #2 + b .mpph_pe_exit + +@ process envelope sustain loop + +1: ldrb r5, [r6, #MCA_FLAGS] + lsr r5, #1 @ locked + bcc 1f + ldrb r5, [r2, #C_MASIE_SEND] + cmp r1, r5 + bne 1f + ldrb r1, [r2, #C_MASIE_SSTART] + mov r2, #0 + b .mpph_pe_exit + +@ check for end + +1: ldrb r5, [r2, #C_MASIE_NODEC] + sub r5, #1 + cmp r1, r5 + bne .mpph_count + mov r2, #2 + b .mpph_pe_exit + +.mpph_pe_between: + +@ delta * count +@ formula : y = base*2^6 + ----------------- +@ 2^3 + mov r5, #0 + ldrsh r5, [r4,r5] + mul r5, r0 + asr r5, #3 + add r3, r5 + +.mpph_count: + +@ increment count and check if == read count + + add r0, #1 + ldrh r5, [r4, #2] + lsr r5, #7 + cmp r0, r5 + bne .mpph_pe_exit + +@ increment node and reset counter + + mov r0, #0 + add r1, #1 + +.mpph_pe_exit: + + pop {r4,r5} + bx lr +.pool + +/* +.align 2 +.thumb_func +@-------------------------------------------------------------------------------------------- +mpp_Alloc_Channel: +@-------------------------------------------------------------------------------------------- + + @ find a channel to use + @ returns invalid channel if none available + push {r4,r5} @ preserve reg(s) + ldr r5,=mm_ch_mask + ldr r5, [r5] + + @ldr r1,=mpp_achannels @ load pointer + ldr r1,=mm_achannels + ldr r1,[r1] + mov r0, #0 @ load counter + mov r2, #255 @ r2 = MAXVOL+1 (highest) + add r2, #1 + mov r3, #255 @ r3 = 255 (none found) + b .mppac_start + +.mppac_next: + add r1, #MCA_SIZE @ change pointer + add r0, #1 @ count +.mppac_start: + lsr r5, #1 + bcs .mppac_check + bne .mppac_next +.mppac_end: + mov r0, r3 @ if no disabled channels are found, use lowest volume channel +.mppac_found: + + pop {r4,r5} + bx lr + +.mppac_check: + ldrb r4, [r1, #MCA_TYPE] @ check active channel type + cmp r4, #ACHN_DISABLED @ disabled? + beq .mppac_found @ if so, use this channel + cmp r4, #ACHN_BACKGROUND @ check if its a background channel + bne .mppac_next + + ldrb r4, [r1, #MCA_FVOL] @ compare volumes + cmp r4, r2 @ + bge .mppac_next + mov r3, r0 @ save channel# + mov r2, r4 @ and volume + b .mppac_next +*/ + +.pool + +@........................................................................................ + +.thumb_func +mpp_PatternPointer: + mov r1, r8 + ldr r2,[r1,#MPL_SONGADR] + ldr r1,[r1,#MPL_PATTTABLE] + lsl r0, #2 + ldr r0,[r1,r0] + add r0, r2 + bx lr +.pool +#ifdef FOO_UC +.align 2 +.thumb_func +mpp_GetPeriod: + @ r0 = note + @ r2 = tuning + @ CLOBBERS R1,R3 + @ RETURN + @ r0 = IT/S3M PERIOD + + mov r1, r8 + ldrb r1, [r1, #MPL_FLAGS] + lsr r1, #C_FLAGS_SS + bcs .mpp_gp_linear +.mpp_gp_amiga: + + mov r3, r0 + ldr r0,=note_table_mod + ldrb r1, [r0, r3] + sub r0, #3*10 + lsr r3, #2 + ldrb r0, [r0, r3] + + @ r0 = octave + @ r1 = note + lsl r1, #1 + ldr r3,=ST3_FREQTABLE + ldrh r1, [r3, r1] + + ldr r3,=133808 + mul r1, r3 + lsr r1, r0 + + lsr r0, r1, #3 + mov r1, r2 + + swi SWI_DIVIDE + lsl r0, #3 + + bx lr + +.mpp_gp_linear: + ldr r1,=IT_PitchTable + lsl r0, #2 + ldr r0, [r1, r0] + + bx lr + +#endif + +@============================================================================= +@ EFFECT MEMORY +@============================================================================= + +.text + +mpp_effect_memmap_xm: +.byte 0,0,0,0,2,3,4,0,0,5,0,6,7,0,0,8,9,10,11,0,0,0,0,12,0,0,0,0,0,0,13 +@ /,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q, R, S,T,U,V,W, X,Y,Z,0,1,2,3 + +.equ MPP_XM_VFX_MEM_VS, 12 @ $ud +.equ MPP_XM_VFX_MEM_FVS, 13 @ $ud +.equ MPP_XM_VFX_MEM_GLIS, 14 @ $0x +.equ MPP_XM_VFX_MEM_PANSL, 7 @ $lr + +mpp_effect_memmap_it: +.byte 0,0,0,0,2,3,3,0,0,4,5,2,2,0,6,7,8,9,10,11,12,0,0,13,0,14,0 +@ /,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R, S, T, U,V,W, X,Y, Z +mpp_veffect_memmap_it: + +.equ MPP_IT_VFX_MEM, 14 +.equ MPP_GLIS_MEM, 0 +.equ MPP_IT_PORTAMEM, 2 + + +@ 0 means custom behavior, or disabled + +.align 2 +.thumb_func +@----------------------------------------------------------------------------- +mpp_Channel_ExchangeMemory: +@----------------------------------------------------------------------------- + + @ r0 = effect# + @ r1 = param + +@ check flags for XM mode + + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_XS + bcs 1f + +@ IT effects + + ldr r2,=mpp_effect_memmap_it + b 2f + +1: +@ XM effects + + ldr r2,=mpp_effect_memmap_xm +2: ldrb r2, [r2, r0] + sub r2, #1 + bcc 3f + +@ if param=0 then load memory value, otherwise save param to memory + + add r2, #MCH_MEMORY + cmp r1, #0 + bne 1f + ldrb r1, [r7, r2] + strb r1, [r7, #MCH_PARAM] +1: strb r1, [r7, r2] + +3: bx lr + +@---------------------------------------------------------- +mpp_Channel_ExchangeGxx: +@---------------------------------------------------------- + + @ r1 = param + + + +/****************************************************************************** + * + * Volume Commands + * + ******************************************************************************/ + + + +/****************************************************************************** + * mpp_Process_VolumeCommand() + * + * Process volume command + ******************************************************************************/ + .global mpp_Process_VolumeCommand + .thumb_func +mpp_Process_VolumeCommand: + + mov r0, r8 + ldrb r2, [r0, #MPL_TICK] + ldr r0, [r0, #MPL_SONGADR] + ldrb r0, [r0, #C_MAS_FLAGS] + lsr r0, #4 + ldrb r0, [r7, #MCH_VOLCMD] + bcc .mppuv_it + b .mppuv_xm +.mppuv_it: + +@ determine which command to use + + cmp r0, #64 + ble .mppuv_setvol + cmp r0, #84 + ble .mppuv_fvol + cmp r0, #104 + ble .mppuv_volslide + cmp r0, #124 + ble .mppuv_porta + cmp r0, #192 + ble .mppuv_panning + cmp r0, #202 + ble .mppuv_glissando + cmp r0, #212 + ble .mppuv_vibrato +.mppuv_exit1: + bx lr + +.align 2 +@----------------------------------------------------------------------------------- +.mppuv_setvol: @ SET VOLUME +@----------------------------------------------------------------------------------- + +@ sets volume on tick0 + + cmp r2, #0 + bne .mppuv_setvol_exit + strb r0, [r7, #MCH_VOLUME] +.mppuv_setvol_exit: + bx lr @ exit + +.align 2 +@----------------------------------------------------------------------------------- +.mppuv_fvol: @ FINE VOLUME SLIDE UP/DOWN +@----------------------------------------------------------------------------------- + + cmp r2, #0 @ only slide on tick0 + bne .mppuv_exit1 @ .. + ldrb r1, [r7, #MCH_VOLUME] @ load channel volume + mov r2, #MCH_MEMORY+MPP_IT_VFX_MEM + cmp r0, #75 @ check slide direction + bge .mppuv_fvoldown @ jump to slide down if value is 75+ (75-84 is slide down) +.mppuv_fvolup: @ ------ slide up ---------- + sub r0, #65 @ 65->74 , 0->9 +.mppuv_volup: @ ** entry for volume slide up + bne 1f @ is value 0? + ldrb r0, [r7, r2] @ then fetch value from memory +1: strb r0, [r7, r2] @ save value +.mppuv_volupA: + add r1, r0 @ add to volume + cmp r1, #64 @ clamp to 0->64 + blt .mppuv_fvol_exit @ .. + mov r1, #64 @ .. + b .mppuv_fvol_exit @ .. +.mppuv_fvoldown: @ ------ slide down -------- + sub r0, #75 @ 75->84 , 0->9 +.mppuv_voldown: @ ** entry for volume slide down + bne 1f @ is value 0? + ldrb r0, [r7, r2] @ then fetch value from memory +1: strb r0, [r7, r2] @ save value +.mppuv_voldownA: + sub r1, r0 @ subtract from volume + bcs .mppuv_fvol_exit @ check overflow and clamp + mov r1, #0 @ .. +.mppuv_fvol_exit: @ .. + strb r1, [r7, #MCH_VOLUME] @ store volume +.mppuv_exit2: + bx lr @ exit function + +.align 2 +@---------------------------------------------------------------------------------- +.mppuv_volslide: @ VOLUME SLIDE UP/DOWN +@---------------------------------------------------------------------------------- + + cmp r2, #0 @ only slide on other ticks + beq .mppuv_exit1 @ .. + ldrb r1, [r7, #MCH_VOLUME] @ get volume + cmp r0, #95 @ check slide direction + bge .mppuv_vs_down +.mppuv_vs_up: @ slide up... + mov r2, #MCH_MEMORY+MPP_IT_VFX_MEM + sub r0, #85 @ 85->94 , 0->9 + b .mppuv_volup @ branch to function (use fvol code) + +.mppuv_vs_down: @ slide down... + mov r2, #MCH_MEMORY+MPP_IT_VFX_MEM + sub r0, #95 @ 95->104 , 0->9 + b .mppuv_voldown @ branch to function (use fvol code) + +.align 2 +@--------------------------------------------------------------------------------------- +.mppuv_porta: @ PORTAMENTO UP/DOWN +@--------------------------------------------------------------------------------------- + + cmp r2, #0 @ only slide on other ticks + beq .mppuv_exit2 + + push {lr} @ save return address + mov r1, r0 @ get period value + mov r0, #MCH_PERIOD + ldr r0, [r7, r0] + + cmp r1, #115 @ check slide direction + bge .mppuv_porta_up +.mppuv_porta_down: + sub r1, #105 @ map value 0->9 + lsl r1, #2 @ volume command slides are + bne 1f + ldrb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] +1: strb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] + bl mpph_PitchSlide_Down @ equal to normal slides *4 + b .mppuv_porta_set + +.mppuv_porta_up: + sub r1, #115 @ slide up... + lsl r1, #2 + bne 1f + ldrb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] +1: strb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] + bl mpph_PitchSlide_Up + +.mppuv_porta_set: + mov r2, #MCH_PERIOD @ store new period + ldr r1, [r7, r2] + str r0, [r7, r2] + sub r0, r1 @ and edit temp period + add r5, r0 + + pop {r0} + bx r0 +// pop {pc} @ exit + +.align 2 +@--------------------------------------------------------------------------------------- +.mppuv_panning: @ SET PANNING +@--------------------------------------------------------------------------------------- + + cmp r2, #0 @ only set on tick 0 + bne .mppuv_exit1 @ .. + sub r0, #128 @ map to 0->64 + lsl r0, #2 + cmp r0, #255 + blt .mppuv_p_store + mov r0, #255 +.mppuv_p_store: + strb r0, [r7, #MCH_PANNING] @ save to active channel +.mppuv_p_exit: + bx lr @ exit + +.align 2 +@--------------------------------------------------------------------------------------- +.mppuv_glissando: @ GLISSANDO +@--------------------------------------------------------------------------------------- + + cmp r2, #0 + beq .mppuv_p_exit + + sub r0, #193 + ldr r1,=vcmd_glissando_table + ldrb r0, [r1, r0] + + mov r1, r8 + ldrb r1, [r1, #MPL_FLAGS] + lsr r1, #C_FLAGS_GS + bcs 2f +@ single gxx + + cmp r0, #0 + beq 1f + ldrb r0, [r7, #MCH_MEMORY+MPP_GLIS_MEM] +1: strb r0, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + b .mppe_glis_ot + +2: @ shared gxx + + cmp r0, #0 + beq 1f + ldrb r0, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] +1: strb r0, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] + strb r0, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + + b .mppe_glis_ot +.pool + +vcmd_glissando_table: +.byte 0,1,4,8,16,32,64,96,128,255 + +.align 2 +@--------------------------------------------------------------------------------------- +.mppuv_vibrato: @ VIBRATO (SPEED) +@--------------------------------------------------------------------------------------- + + @ vibrato... sets speed + cmp r2, #0 + beq .mppuv_vib_exit + sub r0, #203 + beq 1f + lsl r0, #2 + strb r0, [r7, #MCH_VIBSPD] +1: b mppe_DoVibrato +.mppuv_vib_exit: + bx lr + + + +/****************************************************************************** + * + * XM Volume Commands + * + ******************************************************************************/ + + + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------------- +.mppuv_xm: +@--------------------------------------------------------------------------------------- + +@ determine command type + + cmp r0, #0 @ 0 = none + beq .mppuv_exit4 + cmp r0, #0x50 + ble .mppuv_xm_setvol + cmp r0, #0x80 + blt .mppuv_xm_volslide + cmp r0, #0xA0 + blt .mppuv_xm_fvolslide + cmp r0, #0xC0 + blt .mppuv_xm_vibrato + cmp r0, #0xD0 + blt .mppuv_xm_panning + cmp r0, #0xF0 + blt .mppuv_xm_panslide + b .mppuv_xm_toneporta + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_setvol: @ Set Volume +@---------------------------------------------------------------------------------------- + + cmp R2, #0 + bne .mppuv_exit4 + sub r0, #0x10 + strb r0, [r7, #MCH_VOLUME] +.mppuv_exit4: + bx lr + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_volslide: @ Volume Slide +@---------------------------------------------------------------------------------------- + + cmp r2, #0 + beq .mppuv_exit2 + ldrb r1, [r7, #MCH_VOLUME] + mov r3, #MCH_MEMORY+MPP_XM_VFX_MEM_VS + ldrb r2, [r7, r3] + cmp r0, #0x70 + bge .mppuv_xm_volslide_up + sub r0, #0x60 +.mppuv_xm_volslide_dn_check: + bne 1f + mov r0, r2 + lsl r0, #32-4 + lsr r0, #32-4 + b 2f +1: lsr r2, #4 + lsl r2, #4 + orr r2, r0 + strb r2, [r7, r3] +2: b .mppuv_voldownA + +.mppuv_xm_volslide_up: + sub r0, #0x70 +.mppuv_xm_volslide_up_check: + bne 1f + mov r0, r2 + lsr r0, #4 + b 2f +1: lsl r2, #32-4 + lsr r2, #32-4 + lsl r0, #4 + orr r2, r0 + lsr r0, #4 + strb r2, [r7, r3] +2: b .mppuv_volupA + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_fvolslide: @ Fine Volume Slide +@---------------------------------------------------------------------------------------- + + cmp r2, #0 + bne .mppuv_exit4 + ldrb r1, [r7, #MCH_VOLUME] + mov r3, #MCH_MEMORY+MPP_XM_VFX_MEM_FVS + ldrb r2, [r7, r3] + cmp r0, #0x90 + bge .mppuv_xm_fvolslide_up + sub r0, #0x80 + b .mppuv_xm_volslide_dn_check +.mppuv_xm_fvolslide_up: + sub r0, #0x90 + b .mppuv_xm_volslide_up_check + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_vibrato: @ Vibrato +@---------------------------------------------------------------------------------------- + + @ xm vibrato + @ sets speed or depth + + cmp r2, #0 + beq .mppuv_xm_vibexit + cmp r0, #0xB0 + bge .mppuv_xm_vibdepth + +.mppuv_xm_vibspd: + sub r0, #0xA0 + lsl r0, #2 + beq 1f + strb r0, [r7, #MCH_VIBSPD] +1: b mppe_DoVibrato + +.mppuv_xm_vibdepth: + sub r0, #0xB0 + lsl r0, #3 + beq 1f + strb r0, [r7, #MCH_VIBDEP] +1: b mppe_DoVibrato + +.mppuv_xm_vibexit: + bx lr + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_panning: @ Panning +@---------------------------------------------------------------------------------------- + + cmp r2, #0 + bne .mppuv_exit3 + sub r0, #0xC0 + lsl r0, #4 + cmp r0, #240 + beq .mppuv_xm_panhack + strb r0, [r7, #MCH_PANNING] + bx lr +.mppuv_xm_panhack: + mov r0, #255 + strb r0, [r7, #MCH_PANNING] +.mppuv_exit3: + bx lr + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +.mppuv_xm_panslide: @ Panning Slide +@---------------------------------------------------------------------------------------- + + cmp r2, #0 + beq .mppuv_exit3 + ldrb r2, [r7, #MCH_PANNING] + ldrb r3, [r7, #MCH_MEMORY + MPP_XM_VFX_MEM_PANSL] + cmp r0, #0xE0 + bge .mppuv_xm_panslide_right + sub r0, #0xD0 + bne 1f + lsr r0, r3, #4 + b 2f +1: lsl r3, #32-4 + lsr r3, #32-4 + lsl r0, #4 + orr r3, r0 + lsr r0, #4 + strb r3, [r7, #MCH_MEMORY + MPP_XM_VFX_MEM_PANSL] + +2: lsl r0, #2 + sub r2, r0 + bcs .mppuv_xm_panslide_set + mov r2, #0 + b .mppuv_xm_panslide_set +.mppuv_xm_panslide_right: + sub r0, #0xE0 + bne 1f + lsl r0, r3, #32-4 + lsr r0, #32-4 + b 2f +1: lsr r3, #4 + lsl r3, #4 + orr r3, r0 + strb r3, [r7, #MCH_MEMORY + MPP_XM_VFX_MEM_PANSL] +2: lsl r0, #2 + add r2, r0 + cmp r2, #255 + blt .mppuv_xm_panslide_set + mov r2, #255 +.mppuv_xm_panslide_set: + strb r2, [r7, #MCH_PANNING] + bx lr + +.align 2 +.thumb_func +@------------------------------------------------------------------------------------- +.mppuv_xm_toneporta: @ Glissando +@------------------------------------------------------------------------------------- + + @ glissando... + @ on nonzero ticks, do a regular glissando slide at speed * 16 + cmp r2, #0 + beq 1f + + sub r0, #0xF0 + lsl r0, #4 + beq 2f + mov r1, #MCH_MEMORY+MPP_XM_VFX_MEM_GLIS + strb r0, [r7, r1] +2: ldrb r0, [r7, r1] + mov r1, r0 + + b .mppe_glis_backdoor + +1: bx lr + + + +/****************************************************************************** + * + * Module Effects + * + ******************************************************************************/ + + + +/****************************************************************************** + * mpp_ProcessEffect() + * + * Process pattern effect. + ******************************************************************************/ + .global mpp_Process_Effect + .thumb_func +mpp_Process_Effect: + + push {lr} + ldrb r0, [r7, #MCH_EFFECT] @ get effect# + ldrb r1, [r7, #MCH_PARAM] @ r1 = param + bl mpp_Channel_ExchangeMemory + + lsl r0, #1 + + pop {r2} + mov lr, r2 + + mov r2, r8 + ldrb r2, [r2, #MPL_TICK] @ r2 = tick# + + cmp r2, #0 @ Z flag = tick0 :) + add r0, pc + mov pc, r0 + + b mppe_todo + b mppe_SetSpeed + b mppe_PositionJump + b mppe_PatternBreak + b mppe_VolumeSlide + b mppe_Portamento + b mppe_Portamento + b mppe_Glissando + b mppe_Vibrato + b mppe_todo + b mppe_Arpeggio + b mppe_VibratoVolume + b mppe_PortaVolume + b mppe_ChannelVolume + b mppe_ChannelVolumeSlide + b mppe_SampleOffset + b mppe_todo + b mppe_Retrigger + b mppe_Tremolo @ tremolo + b mppe_Extended + b mppe_SetTempo + b mppe_FineVibrato + b mppe_SetGlobalVolume + b mppe_GlobalVolumeSlide + b mppe_SetPanning + b mppe_Panbrello + b mppe_ZXX + b mppe_SetVolume + b mppe_KeyOff + b mppe_EnvelopePos + b mppe_OldTremor +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_SetSpeed: @ EFFECT Axy: SET SPEED +@--------------------------------------------------------------------------------- + + bne .mppe_ss_exit @ dont set on nonzero ticks + cmp r1, #0 + beq .mppe_ss_exit + mov r0, r8 + + strb r1, [r0, #MPL_SPEED] +.mppe_ss_exit: +.thumb_func +mppe_todo: + bx lr @ exit + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_PositionJump: @ EFFECT Bxy: SET POSITION +@--------------------------------------------------------------------------------- + + bne .mppe_pj_exit @ skip nonzero ticks + mov r0, r8 + strb r1, [r0, #MPL_PATTJUMP] +.mppe_pj_exit: + bx lr @ exit +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_PatternBreak: @ EFFECT Cxy: PATTERN BREAK +@--------------------------------------------------------------------------------- + bne .mppe_pb_exit @ skip nonzero ticks + mov r0, r8 @ get variables + strb r1, [r0, #MPL_PATTJUMP_ROW] @ save param to row value + ldrb r1, [r0, #MPL_PATTJUMP] @ check if pattjump=empty + cmp r1, #255 @ 255=empty + bne .mppe_pb_exit @ ... + ldrb r1, [r0, #MPL_POSITION] @ if empty, set pattjump=position+1 + add r1, #1 + strb r1, [r0, #MPL_PATTJUMP] +.mppe_pb_exit: + bx lr @ finished +.pool + +.align 2 +.thumb_func +@------------------------------------------------------------------------------------------ +mppe_VolumeSlide: @ EFFECT Dxy: VOLUME SLIDE +@------------------------------------------------------------------------------------------ + + push {lr} + ldrb r0, [r7, #MCH_VOLUME] @ load volume + + bl mpph_VolumeSlide64 + + strb r0, [r7, #MCH_VOLUME] @ save volume +.mppe_vs_zt: + pop {r0} + bx r0 +// pop {pc} @ exit + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------- +mppe_Portamento: @ EFFECT Exy/Fxy: Portamento +@---------------------------------------------------------------------------------- + + push {lr} + +.mppe_pd_ot: + mov r3, #0 + mov r0, r1 + lsr r0, #4 @ test for Ex param (Extra fine slide) + cmp r0, #0xE @ .. +.mppe_pd_checkE: @ .. + bne .mppe_pd_checkF @ .. + cmp r2, #0 @ Extra fine slide: only slide on tick0 + bne .mppe_pd_exit @ .. + lsl r1, #32-4 @ mask out slide value + lsr r1, #32-4 @ .. + mov r3, #1 + b .mppe_pd_otherslide @ skip the *4 multiplication +.mppe_pd_checkF: @ ------------------------------------ + cmp r0, #0xF @ test for Fx param (Fine slide) + bne .mppe_pd_regslide @ .. + cmp r2, #0 @ Fine slide: only slide on tick0 + bne .mppe_pd_exit @ .. + lsl r1, #32-4 @ mask out slide value + lsr r1, #32-4 @ .. + b .mppe_pd_otherslide +.mppe_pd_regslide: + cmp r2, #0 + beq .mppe_pd_exit +.mppe_pd_otherslide: + + ldrb r0, [r7, #MCH_EFFECT] @ check slide direction + mov r2, #MCH_PERIOD + cmp r0, #5 @ .. (5 = portamento down) + ldr r0, [r7, r2] @ get period + + bne .mppe_pd_slideup @ branch to function +.mppe_pd_slidedown: @ -------SLIDE DOWN------- + + cmp r3, #0 + bne .mppe_pd_fineslidedown + bl mpph_PitchSlide_Down + + b .mppe_pd_store @ store & exit + +.mppe_pd_fineslidedown: + bl mpph_FinePitchSlide_Down + b .mppe_pd_store + +.mppe_pd_slideup: @ ---------SLIDE UP--------- + + cmp r3, #0 + bne .mppe_pd_fineslideup + bl mpph_PitchSlide_Up + b .mppe_pd_store +.mppe_pd_fineslideup: + bl mpph_FinePitchSlide_Up + +.mppe_pd_store: + mov r2, #MCH_PERIOD + ldr r1, [r7, #MCH_PERIOD] + str r0, [r7, #MCH_PERIOD] + sub r0, r1 + add r5, r0 +.mppe_pd_exit: + pop {r0} + bx r0 @ exit + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Glissando: @ EFFECT Gxy: Glissando +@--------------------------------------------------------------------------------- + + bne .mppe_glis_ot + + mov r0, r8 + ldrb r0, [r0, #MPL_FLAGS] + lsr r0, #C_FLAGS_GS + bcc 2f + @ gxx is shared, IT MODE ONLY!! + cmp r1, #0 + bne 3f + ldrb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] + strb r1, [r7, #MCH_PARAM] +3: strb r1, [r7, #MCH_MEMORY+MPP_IT_PORTAMEM] + strb r1, [r7, #MCH_MEMORY+MPP_GLIS_MEM] @ for simplification later + b .mppe_glis_ot + +2: @ gxx is separate + cmp r1, #0 + bne 3f + + ldrb r1, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + strb r1, [r7, #MCH_PARAM] +3: strb r1, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + + bx lr +// b .mppe_glis_exit +.mppe_glis_ot: + + push {lr} // save return address + + ldrb r1, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + +.mppe_glis_backdoor: + + push {r1} + + cmp r6, #0 // exit if no active channel + bne 1f // + pop {r1,r3} // + bx r3 // +1: // + + ldrb r0, [r6, #MCA_SAMPLE] // get target period + sub r0, #1 // + mpp_SamplePointer // + ldrh r1, [r0, #C_MASS_FREQ] // + LSL R1, #2 // + ldrb r2, [r7, #MCH_NOTE] // + ldr r3,=mmGetPeriod // + bl mpp_call_r3 // + + pop {r1} // r1 = parameter + push {r0} // + + mov r3, r0 // r3 = target period + mov r2, #MCH_PERIOD // r0 = current period + ldr r0, [r7, r2] // + mov r2, r8 // test S flag + ldrb r2, [r2, #MPL_FLAGS] // + lsr r2, #C_FLAGS_SS // + bCC .mppe_glis_amiga + cmp r0, r3 + blt .mppe_glis_slideup + bgt .mppe_glis_slidedown +.mppe_glis_noslide: + pop {r0} + pop {r3} + bx r3 + +.mppe_glis_slideup: + bl mpph_PitchSlide_Up + pop {r1} + + cmp r0, r1 + blt .mppe_glis_store + mov r0, r1 + b .mppe_glis_store +.mppe_glis_slidedown: + bl mpph_PitchSlide_Down + pop {r1} + cmp r0, r1 + bgt .mppe_glis_store + mov r0, r1 +.mppe_glis_store: + + mov r2, #MCH_PERIOD + ldr r1, [r7, r2] @#MCA_PERIOD] + str r0, [r7, r2] @#MCA_PERIOD] + sub r0, r1 + add r5, r0 + +.mppe_glis_exit: + pop {r3} + bx r3 + + + //bx lr + +.mppe_glis_amiga: + + cmp r0, r3 + blt .mppe_glis_amiga_up + bgt .mppe_glis_amiga_down + pop {r0} + pop {r3} + bx r3 + +.mppe_glis_amiga_down: + bl mpph_PitchSlide_Up + pop {r1} + cmp r0, r1 + bgt .mppe_glis_store + mov r0, r1 + b .mppe_glis_store +.mppe_glis_amiga_up: + bl mpph_PitchSlide_Down + pop {r1} + cmp r0, r1 + blt .mppe_glis_store + mov r0, r1 + b .mppe_glis_store + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Vibrato: @ EFFECT Hxy: Vibrato +@--------------------------------------------------------------------------------- + + bne .mppe_v_ot + lsr r0, r1, #4 @ if (x != 0) { + beq .mppe_v_nospd @ speed = 4*x; + lsl r0, #2 @ .. + strb r0, [r7, #MCH_VIBSPD] @ .. +.mppe_v_nospd: + + lsl r0, r1, #32-4 @ if (y != 0) { + beq .mppe_v_nodep @ .. + lsr r0, #32-6 @ depth = y * 4; + mov r1, r8 + ldrb r1, [r1, #MPL_OLDEFFECTS] @ if(OldEffects) + lsl r0, r1 @ depth <<= 1; + strb r0, [r7, #MCH_VIBDEP] @ + b mppe_DoVibrato +.mppe_v_nodep: + BX LR + +.align 2 +.thumb_func +@------------------------------------------------------- +mppe_DoVibrato: +@------------------------------------------------------- + +.mppe_v_ot: + mov r0, r8 + ldrb r1, [r0, #MPL_TICK] + ldrb r0, [r0, #MPL_OLDEFFECTS] + + cmp r0, #0 + beq .mppe_dv_update + cmp r1, #0 + bne .mppe_dv_update + + push {lr} + ldrb r1, [r7, #MCH_VIBPOS] + b .mppe_dv_notupdate +.mppe_dv_update: + push {lr} + ldrb r0, [r7, #MCH_VIBSPD] + ldrb r1, [r7, #MCH_VIBPOS] + add r1, r0 + lsl r1, #32-8 + lsr r1, #32-8 + strb r1, [r7, #MCH_VIBPOS] +.mppe_dv_notupdate: + ldr r2,=mpp_TABLE_FineSineData + ldrsb r1, [r2, r1] + ldrb r0, [r7, #MCH_VIBDEP] + mul r1, r0 + asr r1, #8 + mov r0, r5 + cmp r1, #0 + blt .mppe_dv_negative + bl mpph_PitchSlide_Up + b .mppe_dv_store +.mppe_dv_negative: + neg r1, r1 + bl mpph_PitchSlide_Down +.mppe_dv_store: + mov r5, r0 + pop {r0} + bx r0 +// pop {pc} @ return THUMB +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Tremor: @ EFFECT Ixy: Tremor +@--------------------------------------------------------------------------------- + bx lr + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Arpeggio: @ EFFECT Jxy: Arpeggio +@--------------------------------------------------------------------------------- + + bne .mppe_arp_ot + + mov r0, #0 + strb r0, [r7, #MCH_FXMEM] +.mppe_arp_ot: + cmp r6, #0 + beq 1f + ldrb r0, [r7, #MCH_FXMEM] +// ldrb r3, [r6, #MCA_SAMPLE] ? ??? + cmp r0, #1 + bgt .mppe_arp_2 + beq .mppe_arp_1 +.mppe_arp_0: + mov r0, #1 + strb r0, [r7, #MCH_FXMEM] + @ do nothing! :) +1: bx lr + +.mppe_arp_1: + + mov r0, #2 @ set next tick to '2' + strb r0, [r7, #MCH_FXMEM] @ save... + mov r0, r5 + lsr r1, #4 @ mask out high nibble of param +.mppe_arp_others: + mov r2, r5 + cmp r1, #12 @ see if its >= 12 + blt .mppea1_12 @ .. + add r2, r5 @ add period if so... (octave higher) +.mppea1_12: @ .. + lsl r1, #4 @ *16*hword + + mov r0, r5 + push {lr} + bl mpph_LinearPitchSlide_Up + + mov r5, r0 + pop {r0} + bx r0 +// pop {pc} + +.mppe_arp_2: + mov r0, #0 + strb r0, [r7, #MCH_FXMEM] + mov r0, r5 + lsl r1, #32-4 + lsr r1, #32-4 + b .mppe_arp_others + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_VibratoVolume: @ EFFECT Kxy: Vibrato+Volume Slide +@--------------------------------------------------------------------------------- + + push {lr} + push {r1,r2} + bl mppe_DoVibrato + pop {r1,r2} + cmp r2, #0 + bl mppe_VolumeSlide + pop {r0} + bx r0 +// pop {pc} + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_PortaVolume: @ EFFECT Lxy: Portamento+Volume Slide +@--------------------------------------------------------------------------------- + + push {lr} + push {r1,r2} + ldrb r1, [r7, #MCH_MEMORY+MPP_GLIS_MEM] + bl mppe_Glissando + pop {r1, r2} + cmp r2, #0 + bl mppe_VolumeSlide + pop {r0} + bx r0 +// pop {pc} + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_ChannelVolume: @ EFFECT Mxy: Set Channel Volume +@--------------------------------------------------------------------------------- + + bne .mppe_cv_exit @ quite simple... + cmp r1, #0x40 + bgt .mppe_cv_exit @ ignore command if parameter is > 0x40 + strb r1, [r7, #MCH_CVOLUME] +.mppe_cv_exit: + bx lr + +.align 2 +.thumb_func +@------------------------------------------------------------------------------------ +mppe_ChannelVolumeSlide: @ EFFECT Nxy: Channel Volume Slide +@------------------------------------------------------------------------------------ + + push {lr} + + ldrb r0, [r7, #MCH_CVOLUME] @ load volume + bl mpph_VolumeSlide64 + + strb r0, [r7, #MCH_CVOLUME] @ save volume + pop {r0} + bx r0 +// pop {pc} @ exit + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------- +mppe_SampleOffset: @ EFFECT Oxy Sample Offset +@---------------------------------------------------------------------------------- + + bne .mppe_so_exit @ skip on other ticks + + ldr r0,=mpp_vars + strb r1, [r0, #MPV_SAMPOFF] @ set offset +.mppe_so_exit: + bx lr +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_PanningSlide: @ EFFECT Pxy Panning Slide +@--------------------------------------------------------------------------------- + + push {lr} + + mov r0, #255 + push {r0} + ldrb r0, [r7, #MCH_PANNING] @ load panning + + bl mpph_VolumeSlide + + strb r0, [r7, #MCH_PANNING] @ save panning + pop {r0} + bx r0 +// pop {pc} @ exit + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Retrigger: @ EFFECT Qxy Retrigger Note +@--------------------------------------------------------------------------------- + + ldrb r0, [r7, #MCH_FXMEM] + cmp r0, #0 + bne .mppe_retrig_refillN +.mppe_retrig_refill: + lsl r0, r1, #32-4 + lsr r0, #32-4 + add r0, #1 +.mppe_retrig_exitcount: + strb r0, [r7, #MCH_FXMEM] + bx lr +.mppe_retrig_refillN: + sub r0, #1 + cmp r0, #1 + bne .mppe_retrig_exitcount +.mppe_retrig_fire: + + ldrb r2, [r7, #MCH_VOLUME] + lsr r0, r1, #4 + beq .mppe_retrig_v_change0 + cmp r0, #5 + ble .mppe_retrig_v_change_sub + cmp r0, #6 + beq .mppe_retrig_v_change_23 + cmp r0, #7 + beq .mppe_retrig_v_change_12 + cmp r0, #8 + beq .mppe_retrig_v_change0 + cmp r0, #0xD + ble .mppe_retrig_v_change_add + cmp r0, #0xE + beq .mppe_retrig_v_change_32 + cmp r0, #0xF + beq .mppe_retrig_v_change_21 +.mppe_retrig_v_change_21: + lsl r2, #1 + cmp r2, #64 + blt .mppe_retrig_finish + mov r2, #64 +.mppe_retrig_v_change0: + b .mppe_retrig_finish +.mppe_retrig_v_change_sub: + sub r0, #1 + mov r3, #1 + lsl r3, r0 + sub r2, r3 + bcs .mppe_retrig_finish + mov r2, #0 + b .mppe_retrig_finish +.mppe_retrig_v_change_23: + mov r0, #171 + mul r2, r0 + lsr r2, #8 + b .mppe_retrig_finish +.mppe_retrig_v_change_12: + lsr r2, #1 + b .mppe_retrig_finish +.mppe_retrig_v_change_add: + sub r0, #9 + mov r3, #1 + lsl r3, r0 + add r2, r3 + cmp r2, #64 + blt .mppe_retrig_finish + mov r2, #64 + b .mppe_retrig_finish +.mppe_retrig_v_change_32: + mov r0, #192 + mul r2, r0 + lsr r2, #7 +.mppe_retrig_finish: + strb r2, [r7, #MCH_VOLUME] + cmp r6, #0 + beq .mppe_retrig_refill + ldrb r0, [r6, #MCA_FLAGS] + mov r2, #MCAF_START + orr r0, r2 + strb r0, [r6, #MCA_FLAGS] + b .mppe_retrig_refill + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Tremolo: @ EFFECT Rxy: Tremolo +@--------------------------------------------------------------------------------- + +@ r1 = param +@ Z = tick0 + + beq .mppe_trem_zt @ skip this part on tick0 +.mppe_trem_ot: + @ X = speed, Y = depth + ldrb r0, [r7, #MCH_FXMEM] @ get sine position + lsr r3, r1, #4 @ mask out SPEED + lsl r3, #2 @ speed*4 to compensate for larger sine table + add r0, r3 @ add to position + strb r0, [r7, #MCH_FXMEM] @ save (value & 255) +.mppe_trem_zt: + ldrb r0, [r7, #MCH_FXMEM] @ get sine position + ldr r3,=mpp_TABLE_FineSineData @ load sine table value + ldrsb r0, [r3, r0] + lsl r1, #32-4 @ mask out DEPTH + lsr r1, #32-4 + mul r0, r1 @ SINE*DEPTH / 64 + asr r0, #6 + mov r1, r8 + ldrb r1, [r1, #MPL_FLAGS] + lsr r1, #C_FLAGS_XS + bcs 1f + asr r0, #1 +1: ldr r1,=mpp_vars @ set volume addition variable + strb r0, [r1, #MPV_VOLPLUS] + bx lr +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_Extended: @ EFFECT Sxy: Extended Effects +@--------------------------------------------------------------------------------- + + lsr r0, r1, #4 + lsl r0, #1 + cmp r2, #0 + add r0, pc + mov pc, r0 + + @ branch table... + b mppex_XM_FVolSlideUp @ S0x + b mppex_XM_FVolSlideDown @ S1x + b mppex_OldRetrig @ S2x + b mppex_VibForm @ S3x + b mppex_TremForm @ S4x + b mppex_PanbForm @ S5x + b mppex_FPattDelay @ S6x + b mppex_InstControl @ S7x + b mppex_SetPanning @ S8x + b mppex_SoundControl @ S9x + b mppex_HighOffset @ SAx + b mppex_PatternLoop @ SBx + b mppex_NoteCut @ SCx + b mppex_NoteDelay @ SDx + b mppex_PatternDelay @ SEy + b mppex_SongMessage @ SFx + +.mppe_ex_quit: + +@------------------------------------------- +.thumb_func +mppex_Unused: + bx lr + +@------------------------------------------- + +.thumb_func +mppex_XM_FVolSlideUp: + bne 2f + ldrb r0, [r7, #MCH_VOLUME] + lsl r1, #32-4 + lsr r1, #32-4 + add r0, r1 + cmp r0, #64 + blt 1f + mov r0, #64 +1: strb r0, [r7, #MCH_VOLUME] +2: bx lr + +.thumb_func +mppex_XM_FVolSlideDown: + bne 2f + ldrb r0, [r7, #MCH_VOLUME] + lsl r1, #32-4 + lsr r1, #32-4 + sub r0, r1 + bcs 1f + mov r0, #0 +1: strb r0, [r7, #MCH_VOLUME] +2: bx lr + +@------------------------------------------- +.thumb_func +mppex_OldRetrig: + bne 1f + lsl r1, #32-4 + lsr r1, #32-4 + strb r1, [r7, #MCH_FXMEM] + bx lr + +1: ldrb r0, [r7, #MCH_FXMEM] + sub r0, #1 + + bne 1f + + lsl r0, r1, #32-4 + lsr r0, #32-4 + strb r0, [r7, #MCH_FXMEM] + + cmp r6, #0 + beq 1f + ldrb r1, [r6, #MCA_FLAGS] + mov r2, #MCAF_START + + orr r1, r2 + strb r1, [r6, #MCA_FLAGS] + +1: strb r0, [r7, #MCH_FXMEM] + bx lr + +@------------------------------------------- +.thumb_func +mppex_VibForm: + bx lr + +@------------------------------------------- +.thumb_func +mppex_TremForm: + bx lr + +@------------------------------------------- +.thumb_func +mppex_PanbForm: + bx lr + +@------------------------------------------- +.thumb_func +mppex_FPattDelay: + bne .mppex_fpd_exit + lsl r1, #32-4 + lsr r1, #32-4 + mov r0, r8 + strb r1, [r0, #MPL_FPATTDELAY] +.mppex_fpd_exit: + bx lr + +@------------------------------------------- +.thumb_func +mppex_InstControl: + bne .mppex_ic_exit + lsl r1, #32-4 + lsr r1, #32-4 + cmp r1, #2 + ble .mppex_ic_pastnotes + cmp r1, #6 + ble .mppex_ic_nna + cmp r1, #8 + ble .mppex_ic_envelope + bx lr +.mppex_ic_pastnotes: + @ todo... + bx lr +.mppex_ic_nna: + @ overwrite NNA + sub r1, #3 + ldrb r2, [r7, #MCH_BFLAGS] + lsl r2, #32-6 + lsr r2, #32-6 + lsl r1, #6 + orr r2, r1 + strb r2, [r7, #MCH_BFLAGS] + bx lr +.mppex_ic_envelope: + cmp r6, #0 + beq .mppex_ic_exit + ldrb r2, [r6, #MCA_FLAGS] + mov r0, #32 + bic r2, r0 + sub r1, #7 + lsl r1, #5 + orr r2, r1 + strb r2, [r6, #MCA_FLAGS] + +.mppex_ic_exit: + bx lr + +@------------------------------------------- +.thumb_func +mppex_SetPanning: + lsl r1, #4 + strb r1, [r7, #MCH_PANNING] + bx lr + +@------------------------------------------- +.thumb_func +mppex_SoundControl: + cmp r1, #0x91 + beq .mppex_sc_surround + bx lr +.mppex_sc_surround: + @ set surround + bx lr + +@------------------------------------------- +.thumb_func +mppex_HighOffset: + @ todo... + bx lr + +@------------------------------------------- +.thumb_func +mppex_PatternLoop: + bne .mppex_pl_exit @ dont update on nonzero ticks + mov r2, r8 + + lsl r1, #32-4 @ mask low nibble of parameter + lsr r1, #32-4 @ ... + bne .mppex_pl_not0 @ is zero? + + ldrb r1, [r2, #MPL_ROW] @ ... + strb r1, [r2, #MPL_PLOOP_ROW] @ ... + ldr r1,=mpp_vars @ .... + ldr r1, [r1, #MPV_PATTREAD_P] @ .. ... + mov r3, #MPL_PLOOP_ADR + str r1, [r2, r3] @ ... ... + bx lr @ ... ... +.mppex_pl_not0: @ otherwise... + ldrb r0, [r2, #MPL_PLOOP_TIMES] @ get pattern loop counter + cmp r0, #0 @ zero? + bne .mppex_pl_active @ if not then its already active + strb r1, [r2, #MPL_PLOOP_TIMES] @ zero: save parameter to counter + b .mppex_pl_exit_enable @ exit & enable jump +.mppex_pl_active: @ nonzero: + sub r0, #1 @ decrement counter + strb r0, [r2, #MPL_PLOOP_TIMES] @ save + beq .mppex_pl_exit @ enable jump if not 0 +.mppex_pl_exit_enable: + mov r0, #1 @ enable jump + mov r3, #MPL_PLOOP_JUMP + strb r0, [r2, r3] @ .. +.mppex_pl_exit: @ exit + bx lr @ .... +.pool + +@------------------------------------------- +.thumb_func +mppex_NoteCut: + lsl r1, #32-4 @ mask parameter + lsr r1, #32-4 @ .. + cmp r1, r2 @ compare with tick# + bne .mppex_nc_exit @ if equal: + mov r0, #0 @ cut volume + strb r0, [r7, #MCH_VOLUME] @ .. +.mppex_nc_exit: @ exit + bx lr @ .. + +@------------------------------------------- +.thumb_func +mppex_NoteDelay: + + mov r0, r8 + ldrb r2, [r0, #MPL_TICK] + lsl r1, #32-4 + lsr r1, #32-4 + cmp r2, r1 + bge 1f + ldr r0,=mpp_vars + strb r1, [r0, #MPV_NOTEDELAY] +1: bx lr + +@------------------------------------------- +.thumb_func +mppex_PatternDelay: + bne .mppex_pd_quit @ update on tick0 + lsl r1, #32-4 @ mask parameter + lsr r1, #32-4 @ .. + mov r0, r8 + ldrb r2, [r0, #MPL_PATTDELAY] @ get patterndelay + cmp r2, #0 @ only update if it's 0 + bne .mppex_pd_quit @ .. + add r1, #1 @ set to param+1 + strb r1, [r0, #MPL_PATTDELAY] @ .. +.mppex_pd_quit: @ exit + bx lr @ .. + +@------------------------------------------- +.thumb_func +mppex_SongMessage: + + bne .mppex_pd_quit @ update on tick0 + push {lr} @ save return address + lsl r1, #32-4 @ mask parameter + lsr r1, #32-4 @ .. + ldr r2,=mmCallback + ldr r2, [r2] + cmp r2, #0 + beq 1f + mov r0, #MPCB_SONGMESSAGE + + bl mpp_call_r2 + @jump2 +1: //pop {pc} + pop {r0} + bx r0 +.pool + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +mppe_SetTempo: @ EFFECT Txy: Set Tempo / Tempo Slide +@---------------------------------------------------------------------------------------- + + @ 0x = slide down + @ 1x = slide up + @ 2x+ = set + + // BUGGED??? + // not using setbpm for slides??? + + cmp r1, #0x20 + bge .mppe_st_set + cmp r2, #0 + beq .mppe_st_exit + + mov r0, r8 + ldrb r2, [r0, #MPL_BPM] + + cmp r1, #0x10 + bge .mppe_st_slideup +.mppe_st_slidedown: + sub r2, r1 + cmp r2, #32 + bge .mppe_st_save + mov r2, #32 +.mppe_st_save: + mov r0, r2 + b .mppe_st_set2 +.mppe_st_slideup: + + lsl r1, #32-4 + lsr r1, #32-4 + + add r2, r1 + cmp r2, #255 + blt .mppe_st_save + mov r2, #255 + b .mppe_st_save +.mppe_st_set: + cmp r2, #0 + bne .mppe_st_exit + mov r0, r1 +.mppe_st_set2: + push {r5,lr} + mov r5, r8 + ldr r1,=mpp_setbpm + bl mpp_call_r1 + @jump1 + pop {r5} + pop {r3} + bx r3 +.mppe_st_exit: + bx lr +.pool + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------------- +mppe_FineVibrato: @ EFFECT Uxy: Fine Vibrato +@---------------------------------------------------------------------------------------- + + bne .mppe_fv_ot + lsr r0, r1, #4 + beq .mppe_fv_nospd + lsl r0, #2 + strb r0, [r7, #MCH_VIBSPD] +.mppe_fv_nospd: + + lsl r0, r1, #32-4 + beq .mppe_fv_nodep +// lsr r0, #32 heh... + lsr r0, #32-4 + mov r1, r8 + ldrb r1, [r1, #MPL_OLDEFFECTS] + lsl r0, r1 + strb r0, [r7, #MCH_VIBDEP] +.mppe_fv_nodep: + +.mppe_fv_ot: + b mppe_DoVibrato +.pool + +.align 2 +.thumb_func +@------------------------------------------------------------------------------------ +mppe_SetGlobalVolume: @ EFFECT Vxy: Set Global Volume +@------------------------------------------------------------------------------------ + + bne .mppe_sgv_exit @ on tick0: + mov r0, r8 + ldrb r2, [r0, #MPL_FLAGS] + mov r3, #(1<<(C_FLAGS_XS-1))+(1<<(C_FLAGS_LS-1)) + tst r2, r3 + beq 1f + mov r2, #0x40 + b 2f +1: mov r2, #0x80 +2: + cmp r1, r2 + blt 1f + mov r1, r2 +1: strb r1, [r0, #MPL_GV] @ save param to global volume +.mppe_sgv_exit: + bx lr +.pool + + +.align 2 +.thumb_func +@---------------------------------------------------------------------------------- +mppe_GlobalVolumeSlide: @ EFFECT Wxy: Global Volume Slide +@---------------------------------------------------------------------------------- + + push {lr} + +.mppe_gvs_ot: + mov r0, r8 + ldrb r0, [r0, #MPL_FLAGS] + lsr r0, #C_FLAGS_XS + bcs 1f + + mov r0, #128 + b 2f + +1: mov r0, #64 + +2: push {r0} + mov r0, r8 + ldrb r0, [r0, #MPL_GV] @ load global volume + + bl mpph_VolumeSlide @ slide.. + + mov r1, r8 + strb r0, [r1, #MPL_GV] @ save global volume + pop {r0} + bx r0 +// pop {pc} @ exit +.pool + + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------------- +mppe_SetPanning: @ EFFECT Xxy: Set Panning +@--------------------------------------------------------------------------------------- + + bne .mppe_sp_exit @ on tick0: + strb r1, [r7, #MCH_PANNING] @ set panning=param +.mppe_sp_exit: + bx lr +.pool + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------------- +mppe_Panbrello: @ EFFECT Yxy: Panbrello +@--------------------------------------------------------------------------------------- + + @ todo + bx lr + +.align 2 +.thumb_func +@--------------------------------------------------------------------------------- +mppe_ZXX: @ EFFECT Zxy: Set Filter +@--------------------------------------------------------------------------------- + +@ ZXX IS NOT SUPPORTED + bx lr @ exit +.pool + +@======================================================================================= +@ OLD EFFECTS +@======================================================================================= + +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mppe_SetVolume: @ EFFECT 0xx: Set Volume +@----------------------------------------------------------------------------------- + + bne .mppe_sv_exit @ on tick0: + strb r1, [r7, #MCH_VOLUME] @ set volume=param +.mppe_sv_exit: + bx lr + +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mppe_KeyOff: @ EFFECT 1xx: Key Off +@----------------------------------------------------------------------------------- + cmp r1, r2 @ if tick=param: + bne .mppe_ko_exit @ + cmp r6, #0 + beq .mppe_ko_exit + ldrb r0, [r6, #MCA_FLAGS] @ clear keyon from flags + mov r1, #MCAF_KEYON @ + bic r0, r1 @ + strb r0, [r6, #MCA_FLAGS] @ +.mppe_ko_exit: + bx lr @ finished +.pool + +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mppe_EnvelopePos: @ EFFECT 1xx: Envelope Position +@----------------------------------------------------------------------------------- + bne .mppe_ep_ot @ on tick0: + cmp r6, #0 + beq .mppe_ep_ot + + @ - NOT SUPPORTED ANYMORE - + +@ strh r1, [r6, #MCA_ENVP_VOL] @ set volume envelope position +@ strh r1, [r6, #MCA_ENVP_PAN] @ set panning envelope positin + @ pitch envelope wasn't invented yet +.mppe_ep_ot: + bx lr @ finished + +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mppe_OldTremor: @ EFFECT 3xy: Old Tremor +@----------------------------------------------------------------------------------- + + bne .mppe_ot_ot + bx lr +.mppe_ot_ot: + ldrb r0, [r7, #MCH_FXMEM] + cmp r0, #0 + bne .mppe_ot_old +.mppe_ot_new: + ldrb r0, [r7, #MCH_BFLAGS+1] + mov r3, #0b110 + eor r0, r3 + strb r0, [r7, #MCH_BFLAGS+1] + lsr r0, #3 + bcc .mppe_ot_low + lsr r1, #4 + add r1, #1 + strb r1, [r7, #MCH_FXMEM] + b .mppe_ot_apply +.mppe_ot_low: + lsl r1, #32-4 + lsr r1, #32-4 + add r1, #1 + strb r1, [r7, #MCH_FXMEM] + b .mppe_ot_apply + +.mppe_ot_old: + sub r0, #1 + strb r0, [r7, #MCH_FXMEM] + +.mppe_ot_apply: + ldrb r2, [r7, #MCH_BFLAGS+1] + + lsr r2, #3 + bcs .mppe_ot_cut + mov r1, #-64&255 + ldr r2,=mpp_vars + strb r1, [r2, #MPV_VOLPLUS] +.mppe_ot_cut: + bx lr + +@=============================================================================== +@ FUNCTIONS!! +@=============================================================================== + +.align 2 +.thumb_func +@-------------------------------------------------------------------------- +mpph_PitchSlide_Down: @ Linear/Amiga slide down +@-------------------------------------------------------------------------- + + @ r0 = period + @ r1 = slide value (/4) + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_psd_amiga + b .mpph_psd + +.thumb_func +@-------------------------------------------------------------------------- +mpph_LinearPitchSlide_Down: @ Linear slide down +@-------------------------------------------------------------------------- + + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_psu +.mpph_psd: + ldr r2,=mpp_TABLE_LinearSlideDownTable +.mpph_psd_fine: + lsl r1, #1 + ldrh r1, [r2, r1] + lsr r0, #5 + mul r0, r1 + lsr r0, #16 -5 +.mpph_psd_clip: + cmp r0, #0 + bge .mpph_psd_clipdone + mov r0, #0 +.mpph_psd_clipdone: + bx lr +.mpph_psd_amiga: + lsl r1, #4 +.mpph_psd_amiga_fine: + add r0, r1 + lsr r1, r0, #16+5 + beq .mpph_psd_clipdone + mov r0, #1 + lsl r0, #16+5 + b .mpph_psd_clip + +.align 2 +.thumb_func +@-------------------------------------------------------------------------- +mpph_PitchSlide_Up: @ Linear/Amiga slide up +@-------------------------------------------------------------------------- + + @ r0 = period + @ r1 = slide value (/4) + + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_psu_amiga + b .mpph_psu +.thumb_func +mpph_LinearPitchSlide_Up: @ Linear slide up + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_psd +.mpph_psu: + ldr r2,=mpp_TABLE_LinearSlideUpTable + mov r3, r0 + cmp r1, #192 + blt .mpph_psu_notdouble + add r3, r3 +.mpph_psu_notdouble: +.mpph_psu_fine: + lsl r1, #1 + ldrh r1, [r2, r1] + lsr r0, #5 + mul r0, r1 + lsr r0, #16-5 + add r0, r3 +.mpph_psu_clip: + mov r1, r0 + lsr r1, #16+5 + beq .mpph_psu_clipped + mov r0, #1 + lsl r0, #16+5 +.mpph_psu_clipped: + bx lr +.mpph_psu_amiga: + lsl r1, #4 +.mpph_psu_amiga_fine: + sub r0, r1 + bcs .mpph_psu_clipped + mov r0, #0 + bx lr + +.align 2 +.thumb_func +@--------------------------------------------------------------------------- +mpph_FinePitchSlide_Up: +@--------------------------------------------------------------------------- + + @ r0 = period + @ r1 = slide value (0-15) + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_fpsu_amiga + ldr r2,=mpp_TABLE_FineLinearSlideUpTable + mov r3, r0 + b .mpph_psu_fine +.mpph_fpsu_amiga: + lsl r1, #2 + b .mpph_psu_amiga_fine + +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mpph_FinePitchSlide_Down: +@----------------------------------------------------------------------------------- + + @ r0 = period + @ r1 = slide value (0-15) + + mov r2, r8 + ldrb r2, [r2, #MPL_FLAGS] + lsr r2, #C_FLAGS_SS + bcc .mpph_fpsd_amiga + ldr r2,=mpp_TABLE_FineLinearSlideDownTable + b .mpph_psd_fine +.mpph_fpsd_amiga: + lsl r1, #2 + b .mpph_psd_amiga_fine +.pool + +@----------------------------------------------------------------------------------- + +.text +.align 2 +.thumb_func +@----------------------------------------------------------------------------------- +mpph_FastForward: +@----------------------------------------------------------------------------------- + + @ r1 = #rows to skip + cmp r1, #0 + bne .mpph_ff +.mpph_ff_exitf: + bx lr +.mpph_ff: + + mov r0, r8 + ldrb r2, [r0, #MPL_NROWS] + add r2, #1 + cmp r1, r2 + bge .mpph_ff_exitf + strb r1, [r0, #MPL_ROW] + push {r7,lr} + ldr r7,=mmReadPattern //mpp_ReadPattern +.mpph_ff_loop: + push {r1,r7} + bl mpp_call_r7 + pop {r1,r7} + sub r1, #1 + bne .mpph_ff_loop + + pop {r7} + pop {r0} + bx r0 +// pop {pc} +.pool + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ IWRAM CODE @ +@ @ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +.align 2 +.thumb_func +@----------------------------------------------------------------------------- +mpph_VolumeSlide64: +@----------------------------------------------------------------------------- + + mov r3, #64 + push {r3} + +.thumb_func +@----------------------------------------------------------------------------- +mpph_VolumeSlide: +@----------------------------------------------------------------------------- + + @ r0 = volume + @ r1 = paramter + @ r2 = tick# + @ stack:1 = max volume + + mov r3, r8 + ldrb r3, [r3, #MPL_FLAGS] + lsr r3, #C_FLAGS_XS + bcs .mpph_vs_XM + + cmp r1, #0x0F @ is value 15? + bne .mpph_vs_hack1 @ then only slide on tick0 + b .mpph_vs_fsub +.mpph_vs_hack1: + cmp r1, #0xF0 @ is value 15? + bne .mpph_vs_hack2 @ then only slide on tick0 + cmp r2, #0 @ .. + bne .mpph_vs_exit @ .. + b .mpph_vs_fadd +.mpph_vs_hack2: + + mov r3, r1 @ test for Dx0 + lsl r3, #32-4 @ .. + bne .mpph_vs_next1 @ .. +.mpph_vs_add: @ Dx0: (used for DxF too) + cmp r2, #0 + beq .mpph_vs_exit +.mpph_vs_fadd: + lsr r1, #4 @ fix value + add r0, r1 @ add to volume + pop {r1} + cmp r0, r1 @ clip values past 64 + blt .mpph_vs_exit2 @ .. + mov r0, r1 @ .. + b .mpph_vs_exit2 @ .. +.mpph_vs_next1: @--------------------- + mov r3, r1 @ test for D0x + lsr r3, #4 @ .. + bne .mpph_vs_next2 @ .. +.mpph_vs_sub: @ D0x: + cmp r2, #0 + beq .mpph_vs_exit +.mpph_vs_fsub: + lsl r1, #32-4 @ mask value + lsr r1, #32-4 @ .. + + sub r0, r1 @ subtract from volume + bcs .mpph_vs_exit @ clip values under 0 + mov r0, #0 @ .. + b .mpph_vs_exit @ .. +.mpph_vs_next2: @--------------------- + cmp r2, #0 @ fine slides now... only slide on tick0 + bne .mpph_vs_exit @ .. + + mov r3, r1 @ test for DxF + lsl r3, #32-4 @ .. + lsr r3, #32-4 + cmp r3, #0x0F @ .. + beq .mpph_vs_fadd @ branch + + mov r3, r1 @ test for DFx + lsr r3, #4 @ .. + cmp r3, #0x0F @ .. + beq .mpph_vs_fsub @ branch +.mpph_vs_exit: + + pop {r1} + +.mpph_vs_exit2: + bx lr @ exit if all fail + +.mpph_vs_XM: + cmp r2, #0 + beq .mpph_vs_exit + + lsr r3, r1, #4 + lsl r1, #32-4 + lsr r1, #32-4 + sub r3, r1 + add r0, r3 + pop {r1} + cmp r0, r1 + blt .mpph_vsxm_testlow + mov r0, r1 +.mpph_vsxm_testlow: + cmp r0, #0 + bgt .mpph_vs_exit2 + mov r0, #0 + bx lr +.pool + +@========================================================================================== +@ TABLES +@========================================================================================== + +.TEXT + +.align 2 +/****************************************************************************** + * ST3_FREQTABLE + * + * LUT for amiga periods. + ******************************************************************************/ + .global ST3_FREQTABLE +ST3_FREQTABLE: + +.hword 1712*8, 1616*8, 1524*8, 1440*8, 1356*8, 1280*8, 1208*8, 1140*8, 1076*8, 1016*8, 960*8, 907*8 @ MORE ACCURACY SCALARS + +@middle octave is 4. +@ +@ 133808 * ( period(NOTE) >> octave ) +@ note_st3period = -------------------------------------------- +@ middle_c_finetunevalue(INSTRUMENT) +@ + +.align 2 +@------------------------------------------------------------------------------------------- +mpp_TABLE_LinearSlideUpTable: @ value = 2^(val/192), 16.16 fixed +@------------------------------------------------------------------------------------------- + +.hword 0, 237, 475, 714, 953 @ 0->4 @ ADD 1.0 +.hword 1194, 1435, 1677, 1920, 2164 @ 5->9 +.hword 2409, 2655, 2902, 3149, 3397 @ 10->14 +.hword 3647, 3897, 4148, 4400, 4653 @ 15->19 +.hword 4907, 5157, 5417, 5674, 5932 @ 20->24 +.hword 6190, 6449, 6710, 6971, 7233 @ 25->29 +.hword 7496, 7761, 8026, 8292, 8559 @ 30->34 +.hword 8027, 9096, 9366, 9636, 9908 @ 35->39 +.hword 10181, 10455, 10730, 11006, 11283 @ 40->44 +.hword 11560, 11839, 12119, 12400, 12682 @ 45->49 +.hword 12965, 13249, 13533, 13819, 14106 @ 50->54 +.hword 14394, 14684, 14974, 15265, 15557 @ 55->59 +.hword 15850, 16145, 16440, 16737, 17034 @ 60->64 +.hword 17333, 17633, 17933, 18235, 18538 @ 65->69 +.hword 18842, 19147, 19454, 19761, 20070 @ 70->74 +.hword 20379, 20690, 21002, 21315, 21629 @ 75->79 +.hword 21944, 22260, 22578, 22897, 23216 @ 80->84 +.hword 23537, 23860, 24183, 24507, 24833 @ 85->89 +.hword 25160, 25488, 25817, 26148, 26479 @ 90->94 +.hword 26812, 27146, 27481, 27818, 28155 @ 95->99 +.hword 28494, 28834, 29175, 29518, 29862 @ 100->104 +.hword 30207, 30553, 30900, 31248, 31599 @ 105->109 +.hword 31951, 32303, 32657, 33012, 33369 @ 110->114 +.hword 33726, 34085, 34446, 34807, 35170 @ 115->119 +.hword 35534, 35900, 36267, 36635, 37004 @ 120->124 +.hword 37375, 37747, 38121, 38496, 38872 @ 125->129 +.hword 39250, 39629, 40009, 40391, 40774 @ 130->134 +.hword 41158, 41544, 41932, 42320, 42710 @ 135->139 +.hword 43102, 43495, 43889, 44285, 44682 @ 140->144 +.hword 45081, 45481, 45882, 46285, 46690 @ 145->149 +.hword 47095, 47503, 47917, 48322, 48734 @ 150->154 +.hword 49147, 49562, 49978, 50396, 50815 @ 155->159 +.hword 51236, 51658, 52082, 52507, 52934 @ 160->164 +.hword 53363, 53793, 54224, 54658, 55092 @ 165->169 +.hword 55529, 55966, 56406, 56847, 57289 @ 170->174 +.hword 57734, 58179, 58627, 59076, 59527 @ 175->179 +.hword 59979, 60433, 60889, 61346, 61805 @ 180->184 +.hword 62265, 62727, 63191, 63657, 64124 @ 185->189 +.hword 64593, 65064, 0, 474, 950 @ 190->194 @ ADD 2.0 w/ 192+ +.hword 1427, 1906, 2387, 2870, 3355 @ 195->199 +.hword 3841, 4327, 4818, 5310, 5803 @ 200->204 +.hword 6298, 6795, 7294, 7794, 8296 @ 205->209 +.hword 8800, 9306, 9814, 10323, 10835 @ 210->214 +.hword 11348, 11863, 12380, 12899, 13419 @ 215->219 +.hword 13942, 14467, 14993, 15521, 16051 @ 220->224 +.hword 16583, 17117, 17653, 18191, 18731 @ 225->229 +.hword 19273, 19817, 20362, 20910, 21460 @ 230->234 +.hword 22011, 22565, 23121, 23678, 24238 @ 235->239 +.hword 24800, 25363, 25929, 25497, 27067 @ 240->244 +.hword 27639, 28213, 28789, 29367, 29947 @ 245->249 +.hword 30530, 31114, 31701, 32289, 32880 @ 250->254 +.hword 33473, 34068 @ 255->256 + +.align 2 +@------------------------------------------------------------------------------------- +mpp_TABLE_LinearSlideDownTable: @ value = 2^(-val/192), 16.16 fixed +@------------------------------------------------------------------------------------- + +.hword 65535, 65300, 65065, 64830, 64596, 64364, 64132, 63901 @ 0->7 +.hword 63670, 63441, 63212, 62984, 62757, 62531, 62306, 62081 @ 8->15 +.hword 61858, 61635, 61413, 61191, 60971, 60751, 60532, 60314 @ 16->23 +.hword 60097, 59880, 59664, 59449, 59235, 59022, 58809, 58597 @ 24->31 +.hword 58386, 58176, 57966, 57757, 57549, 57341, 57135, 56929 @ 32->39 +.hword 56724, 56519, 56316, 56113, 55911, 55709, 55508, 55308 @ 40->47 +.hword 55109, 54910, 54713, 54515, 54319, 54123, 53928, 53734 @ 48->55 +.hword 53540, 53347, 53155, 52963, 52773, 52582, 52393, 52204 @ 56->63 +.hword 52016, 51829, 51642, 51456, 51270, 51085, 50901, 50718 @ 64->71 +.hword 50535, 50353, 50172, 49991, 49811, 49631, 49452, 49274 @ 72->79 +.hword 49097, 48920, 48743, 48568, 48393, 48128, 48044, 47871 @ 80->87 +.hword 47699, 47527, 47356, 47185, 47015, 46846, 46677, 46509 @ 88->95 +.hword 46341, 46174, 46008, 45842, 45677, 45512, 45348, 45185 @ 96->103 +.hword 45022, 44859, 44698, 44537, 44376, 44216, 44057, 43898 @104->111 +.hword 43740, 43582, 43425, 43269, 43113, 42958, 42803, 42649 @112->119 +.hword 42495, 42342, 42189, 42037, 41886, 41735, 41584, 41434 @120->127 +.hword 41285, 41136, 40988, 40840, 40639, 40566, 40400, 40253 @128->135 +.hword 40110, 39965, 39821, 39678, 39535, 39392, 39250, 39109 @136->143 +.hword 38968, 38828, 38688, 38548, 38409, 38271, 38133, 37996 @144->151 +.hword 37859, 37722, 37586, 37451, 37316, 37181, 37047, 36914 @152->159 +.hword 36781, 36648, 36516, 36385, 36254, 36123, 35993, 35863 @160->167 +.hword 35734, 35605, 35477, 35349, 35221, 35095, 34968, 34842 @168->175 +.hword 34716, 34591, 34467, 34343, 34219, 34095, 33973, 33850 @176->183 +.hword 33728, 33607, 33486, 33365, 33245, 33125, 33005, 32887 @184->191 +.hword 32768, 32650, 32532, 32415, 32298, 32182, 32066, 31950 @192->199 +.hword 31835, 31720, 31606, 31492, 31379, 31266, 31153, 31041 @200->207 +.hword 30929, 30817, 30706, 30596, 30485, 30376, 30226, 30157 @208->215 +.hword 30048, 29940, 29832, 29725, 29618, 29511, 29405, 29299 @216->223 +.hword 29193, 29088, 28983, 28879, 28774, 28671, 28567, 28464 @224->231 +.hword 28362, 28260, 28158, 28056, 27955, 27855, 27754, 27654 @232->239 +.hword 27554, 27455, 27356, 27258, 27159, 27062, 26964, 26867 @240->247 +.hword 26770, 26674, 26577, 26482, 26386, 26291, 26196, 26102 @248->255 +.hword 26008 @ 256 + +/****************************************************************************** + * IT_PitchTable + * + * LUT for linear periods. + ******************************************************************************/ + .global IT_PitchTable + .align 2 +IT_PitchTable: + +.hword 2048, 0, 2170, 0, 2299, 0, 2435, 0, 2580, 0, 2734, 0 @ C-0 +.hword 2896, 0, 3069, 0, 3251, 0, 3444, 0, 3649, 0, 3866, 0 @>B-0 + +.hword 4096, 0, 4340, 0, 4598, 0, 4871, 0, 5161, 0, 5468, 0 @ C-1 +.hword 5793, 0, 6137, 0, 6502, 0, 6889, 0, 7298, 0, 7732, 0 @>B-1 + +.hword 8192, 0, 8679, 0, 9195, 0, 9742, 0, 10321, 0, 10935, 0 @ octave 2 +.hword 11585, 0, 12274, 0, 13004, 0, 13777, 0, 14596, 0, 15464, 0 + +.hword 16384, 0, 17358, 0, 18390, 0, 19484, 0, 20643, 0, 21870, 0 @ octave 3 +.hword 23170, 0, 24548, 0, 26008, 0, 27554, 0, 29193, 0, 30929, 0 + +.hword 32768, 0, 34716, 0, 36781, 0, 38968, 0, 41285, 0, 43740, 0 @ octave 4 +.hword 46341, 0, 49097, 0, 52016, 0, 55109, 0, 58386, 0, 61858, 0 + +.hword 0, 1, 3897, 1, 8026, 1, 12400, 1, 17034, 1, 21944, 1 @ octave 5 +.hword 27146, 1, 32657, 1, 38496, 1, 44682, 1, 51236, 1, 58179, 1 + +.hword 0, 2, 7794, 2, 16051, 2, 24800, 2, 34068, 2, 43888, 2 @ octave 6 +.hword 54292, 2, 65314, 2, 11456, 3, 23828, 3, 36936, 3, 50823, 3 + +.hword 0, 4, 15588, 4, 32103, 4, 49600, 4, 2601, 5, 22240, 5 @ octave 7 +.hword 43048, 5, 65092, 5, 22912, 6, 47656, 6, 8336, 7, 36110, 7 + +.hword 0, 8, 31176, 8, 64205, 8, 33663, 9, 5201, 10, 44481, 10 @ octave 8 +.hword 20559, 11, 64648, 11, 45823, 12, 29776, 13, 16671, 14, 6684, 15 + +.hword 0, 16, 62352, 16, 62875, 17, 1790, 19, 10403, 20, 23425, 21 @ octave 9 +.hword 41118, 22, 63761, 23, 26111, 25, 59552, 26, 33342, 28, 13368, 30 + +.align 2 +@------------------------------------------------------------------------------------- +mpp_TABLE_FineLinearSlideUpTable: +@------------------------------------------------------------------------------------- + +.hword 0, 59, 118, 178, 237 @ 0->4 ADD 1x +.hword 296, 356, 415, 475, 535 @ 5->9 +.hword 594, 654, 714, 773, 833 @ 10->14 +.hword 893 @ 15 + +.align 2 +@------------------------------------------------------------------------------------- +mpp_TABLE_FineLinearSlideDownTable: +@------------------------------------------------------------------------------------- + +.hword 65535, 65477, 65418, 65359, 65300, 65241, 65182, 65359 @ 0->7 +.hword 65065, 65006, 64947, 64888, 64830, 64772, 64713, 64645 @ 8->15 + +@------------------------------------------------------------------------------------- +mpp_TABLE_FineSineData: +@------------------------------------------------------------------------------------- + +.byte 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23 +.byte 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44 +.byte 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59 +.byte 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64 +.byte 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60 +.byte 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46 +.byte 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26 +.byte 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2 +.byte 0, -2, -3, -5, -6, -8, -9,-11,-12,-14,-16,-17,-19,-20,-22,-23 +.byte -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44 +.byte -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59 +.byte -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64 +.byte -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60 +.byte -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46 +.byte -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26 +.byte -24,-23,-22,-20,-19,-17,-16,-14,-12,-11, -9, -8, -6, -5, -3, -2 + +.end diff --git a/libs/maxmod/mm_mas_arm.S b/libs/maxmod/mm_mas_arm.S new file mode 100644 index 0000000..13df41e --- /dev/null +++ b/libs/maxmod/mm_mas_arm.S @@ -0,0 +1,612 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> background then its important, dont use this channel + bgt .mppac_found // 1/3 if < background then its disabled, use this channel + + cmp r2, r4, lsl#23 // 1 compare volume with our record + bls .mppac_next_test // 1/3 goto next if not less + mov r3, r0 // 1 otherwise save this channel + movs r2, r4, lsl#23 // 1 and volume level +// beq .mppac_finished // 1/3 exit immediately if volume is zero + b .mppac_next_test // 3 loop + // 17 +.mppac_finished: + mov r0, r3 +// cmp r0, #255 //trap +// 5: bge 5b +.mppac_found: + pop {r4,r5,r6} + bx lr + +.global mmReadPattern +@**************************************************** +mmReadPattern: +@**************************************************** + push {r10-r12} + ldr r11, [r8, #MPL_SONGADR] + ldrb r12, [r11, #C_MAS_INSTN] // read instr count + ldrb r11, [r8, #MPL_FLAGS] // read flags + mov r10, #1 // for various things + + ldr r0,=mpp_channels + ldr r9, [r0] + ldr r7, [r8, #MPL_PATTREAD] + ldr r0,=mpp_vars + str r7, [r0, #MPV_PATTREAD_P] + + mov r1, #0 + +@---------------------------------------------------------------- +readpattern: +@---------------------------------------------------------------- + + mov r5, #0 // clear flags + ldrb r3, [r7], #1 // read pattern byte + movs r3, r3, lsl#32-7 // mask channel# + beq end_of_row // 0 = end of row + rsb r3, r10, r3, lsr#32-7 // get channel number + orr r1, r10, lsl r3 + mov r0, #MCH_SIZE + mla r6, r3, r0, r9 // get channel pointer + ldrcsb r2, [r7], #1 // read new maskvariable if bit was set + strcsb r2, [r6, #MCH_CFLAGS] // and save it + ldrccb r2, [r6, #MCH_CFLAGS] // otherwise read previous flags + + tst r2, #1 // test note bit + beq no_note + ldrb r0, [r7], #1 // read note value + cmp r0, #254 // test if < 254 + strltb r0, [r6, #MCH_PNOTE] // [most common result] + blt no_note + orreq r5, #MF_NOTECUT // 254 is note-cut + orrgt r5, #MF_NOTEOFF // 255 is note-off +no_note: + + tst r2, #2 // shift out instrument bit + beq no_instrument + ldrb r0, [r7], #1 // read instrument value + tst r5, #MF_NOTEOFF|MF_NOTECUT + bne no_instrument // skip if note-off or cut is set + cmp r0, r12 // check if value > max instruments + movgt r0, #0 // zero if so + ldrb r3, [r6, #MCH_INST] // test if instrument is the same + cmp r0, r3 + beq same_instrument + movs r3, r11, lsr#C_FLAGS_LS // shift out 'mod/s3m' flag + orrcs r5, #MF_START // set start flag if old + orr r5, #MF_NEWINSTR // set new instrument flag +same_instrument: + strb r0, [r6, #MCH_INST] +no_instrument: + + tst r10, r2, lsr#3 // test volume & effect bits + ldrcsb r0, [r7], #1 // copy vcmd + strcsb r0, [r6, #MCH_VOLCMD] +no_vcmd: + beq no_effect + ldrb r0, [r7], #1 // copy effect + ldrb r3, [r7], #1 // copy param + orr r0, r3, lsl#8 + strh r0, [r6, #MCH_EFFECT] // write effect+param +no_effect: + orr r5, r2, lsr#4 // orr in the new flags + strb r5, [r6, #MCH_FLAGS] // save flags + b readpattern // loop +end_of_row: + str r7, [r8, #MPL_PATTREAD] // save read position + str r1, [r8, #MPL_MCH_UPDATE] // save update bits + pop {r10-r12} + bx lr // return + +.macro get_channel branch + ldrb r0, [r7, #MCH_ALLOC] // get channel + cmp r0, #255 // + bge \branch // no channel! + ldr r6,=mm_achannels // + ldr r6, [r6] // + mov r1, #MCA_SIZE // + mla r6, r0, r1, r6 // +.endm + +.global mmUpdateChannel_T0, mmUpdateChannel_TN +@*************************************************************************** +mmUpdateChannel_T0: // for tick 0 +@*************************************************************************** + push {lr} + + ldrb r5, [r7, #MCH_FLAGS] // read channel flags + tst r5, #MF_START // test start flag + beq dont_start_channel // skip section if cleared + + tst r5, #MF_HASFX // test effect flag + beq no_channel_effect + ldrh r0, [r7, #MCH_EFFECT] // read effect + and r1, r0, #0xFF +// cmp r1, #19 // test for 'SDx' (note delay) +// lsreq r2, r0, #12 +// cmpeq r2, #0xD +// beq dont_start_channel // dont start channel if delayed + + // test for glissando + tst r5, #MF_NEWINSTR + bne start_channel // always start channel if it's a new instrument + cmp r1, #0x7 // test if effect is Gxx + beq glissando_affected + +no_channel_effect: + tst r5, #MF_NEWINSTR // copeee + bne start_channel // always start channel if it's a new instrument + + tst r5, #MF_HASVCMD // test for volume commmand + beq start_channel // none = start channel + ldrb r0, [r8, #MPL_FLAGS] // read mod flags + movs r0, r0, lsr#C_FLAGS_XS // test for XM mode + ldrb r0, [r7, #MCH_VOLCMD] // read volume command + bcs xm_vcmd // branch +it_vcmd: // using IT effects: + cmp r0, #193 // glissando is 193..202 + blt start_channel + cmp r0, #202 + bgt start_channel + b glissando_affected +xm_vcmd: // using XM effects: + cmp r0, #0xF0 // glissando is Fx + bge glissando_affected + b start_channel +no_channel_vcmd: + +glissando_affected: + + get_channel start_channel +/* ldrb r0, [r7, #MCH_ALLOC] // if channel is invalid + cmp r0, #255 // then skip this + bge start_channel + + ldr r6,=mm_achannels // get channel + ldr r6, [r6] // + mov r1, #MCA_SIZE // + mla r6, r0, r1, r6 // +*/ + bl mmChannelStartACHN // start achn + bic r5, #MF_START // clear start flag + strb r5, [r7, #MCH_FLAGS] + b dont_start_channel + +start_channel: // ok start channel... + + ldr r2,=mpp_Channel_NewNote + mov lr, pc + bx r2 + get_channel mmUpdateChannel_TN_ + +// cmp r6, #0 +// beq mmUpdateChannel_TN_ + + bl mmChannelStartACHN // start achn +//---------------------------------------------- + // r2 = note, calculate period + ldrb r0, [r6, #MCA_SAMPLE] + subs r0, #1 + bcc no_sample_to_make_period + + ldrb r1, [r8, #MPL_FLAGS] + lsrs r1, #C_FLAGS_SS + bcs linear_periods + + ldr r3, [r8, #MPL_SONGADR] // read song addr + ldr r1, [r8, #MPL_SAMPTABLE]// get sample table + ldr r0, [r1, r0, lsl#2] // get sample address + add r0, r3 // add module base + + ldrh r1, [r0, #C_MASS_FREQ] // read tuning freq + lsl r1, #2 // shift ... +// mov r0, r2 // move this. + bl get_amiga_period + b got_period +linear_periods: + LDR R1,=IT_PitchTable + LDR R0, [R1, R2, LSL#2] + //bl get_linear_period +got_period: +//-------------------------------- + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + str r0, [r7, #MCH_PERIOD] // save period + ldrb r0, [r6, #MCA_FLAGS] // set start flag + orr r0, #MCAF_START + strb r0, [r6, #MCA_FLAGS] +no_sample_to_make_period: +//---------------------------------------------------- + + b channel_started + +dont_start_channel: + + get_channel mmUpdateChannel_TN___ + +channel_started: + tst r5, #MF_DVOL + beq dvol_skip + ldrb r0, [r7, #MCH_INST] + subs r0, #1 + bcc dvol_no_instrument + + ldr r2, [r8, #MPL_SONGADR] // get instrument pointer + ldr r1, [r8, #MPL_INSTTABLE] + ldr r0, [r1, r0, lsl#2] + add r0, r2 + + ldr r1, [r0, #C_MASI_NNA] // read nna,envflags,pan + ldrb r2, [r7, #MCH_BFLAGS] // read bflags + bic r2, #0b11000000 // clear old nna + orr r2, r1, lsl#6 // set new nna + strb r2, [r7, #MCH_BFLAGS] + + ldrb r2, [r6, #MCA_FLAGS] // read achn flags + bic r2, #MCAF_VOLENV + tst r1, #ENVFLAG_A<<8 + orrne r2, #MCAF_VOLENV + strb r2, [r6, #MCA_FLAGS] + + movs r1, r1, lsl#8+1 // shift out panning MSB + movcs r1, r1, lsr#24 // if set, use new panning value + strcsb r1, [r7, #MCH_PANNING] +dvol_no_instrument: + + ldrb r0, [r6, #MCA_SAMPLE] // read sample# + subs r0, #1 + bcc dvol_no_sample // exit if invalid + + ldr r2, [r8, #MPL_SONGADR] // get sample address + ldr r1, [r8, #MPL_SAMPTABLE] + ldr r0, [r1, r0, lsl#2] + //add r0, r2 + + ldrh r1, [r0, r2] + //ldrh r1, [r0, #C_MASS_DV] // read dvol & pan + strb r1, [r7, #MCH_VOLUME] // copy volume + movs r1, r1, lsl#24-7 + mov r1, r1, lsr#24 + strcsb r1, [r7, #MCH_PANNING] +dvol_skip: +dvol_no_sample: + + tst r5, #MF_START|MF_DVOL + beq dont_reset_volume + + ldrb r0, [r8, #MPL_FLAGS] + tst r0, #C_FLAGS_X + beq 1f + tst r5, #MF_DVOL + beq dont_reset_volume // xm stuff +1: +reset_volume: + mov r0, #(1<<10) // [1] + mov r1, #0 // [1] + mov r2, #0 // [1] + add r12, r6, #MCA_FADE // [1] + stmia r12, {r0-r2} // [19] + // [23] + strh r1, [r6, #MCA_ENVN_VOL] + strb r1, [r6, #MCA_ENVN_PIC] + + // the last bit of code sets fade to (1<<10) + // and clears ENVC_VOL,ENVC_PAN,ENVC_PIC, + // AVIB_DEP, and AVIB_POS + // second bit clears ENVN vars + + strb r1, [r7, #MCH_FXMEM] // clear fx memory + + ldrb r1, [r6, #MCA_FLAGS] // set keyon + orr r1, #MCAF_KEYON // and clear envend+fade + bic r1, #MCAF_ENVEND | MCAF_FADE + strb r1, [r6, #MCA_FLAGS] + +dont_reset_volume: + + tst r5, #MF_NOTEOFF // test noteoff bit + beq skip_noteoff + + ldrb r1, [r6, #MCA_FLAGS] // read flags + bic r1, #MCAF_KEYON // clear key-on + ldrb r0, [r8, #MPL_FLAGS] // read mod flags + tst r0, #C_FLAGS_X // test xm mode + orrne r1, #MCAF_FADE // XM starts fade immediately on note-off + strb r1, [r6, #MCA_FLAGS] +skip_noteoff: + + tst r5, #MF_NOTECUT // test notecut bit + movne r0, #0 // clear volume + strneb r0, [r7, #MCH_VOLUME] // on note-cut + + bic r5, #MF_START // clear start flag + strb r5, [r7, #MCH_FLAGS] // save flags + b mmUpdateChannel_TN_ +@************************************************************ +mmUpdateChannel_TN: // for other ticks +@************************************************************ + push {lr} + +mmUpdateChannel_TN_: + ldrb r0, [r7, #MCH_ALLOC] // get channel + cmp r0, #255 // + bge mmUpdateChannel_TN___ // no channel! + ldr r6,=mm_achannels // + ldr r6, [r6] // + mov r1, #MCA_SIZE // + mla r6, r0, r1, r6 // + +mmUpdateChannel_TN___: + + movge r6, #0 + + ldr r5, [r7, #MCH_PERIOD] // r5 will be used to hold the period + ldr r1,=mpp_vars + mov r0, #0 + strb r0, [r1, #MPV_SAMPOFF] // clear variables + strb r0, [r1, #MPV_VOLPLUS] + strb r0, [r1, #MPV_PANPLUS] + strb r0, [r1, #MPV_NOTEDELAY] + +//--------------------------------------------- +// Update Volume Commands +//--------------------------------------------- + + ldrb r0, [r7, #MCH_FLAGS] + tst r0, #MF_HASVCMD + ldrne r1,=mpp_Process_VolumeCommand + movne lr, pc + bxne r1 + //blne mpp_Process_VolumeCommand + +//--------------------------------------------- +// Update Effects +//--------------------------------------------- + + ldrb r0, [r7, #MCH_FLAGS] + tst r0, #MF_HASFX + ldrne r1,=mpp_Process_Effect + movne lr, pc + bxne r1 + //blne mpp_Process_Effect + +//--------------------------------------------- + + cmp r6, #0 + beq no_achn + ldrh r0, [r7, #MCH_VOLUME] // read volume & cvolume + and r1, r0, #255 // mask volume + mov r0, r0, lsr#8 // mask cvolume + mul r0, r1, r0 // multiply together + mov r0, r0, lsr#5 // shift + strb r0, [r6, #MCA_VOLUME] // save in achn volume + + ldr r1,=mpp_vars // + ldrsb r2, [r1, #MPV_VOLPLUS] // read volume addition + adds r0, r2, lsl#3 // add to volume + movmi r0, #0 + cmp r0, #129 + movcs r0, #128 + strb r0, [r1, #MPV_AFVOL] // store in immediate vol + + ldrb r0, [r1, #MPV_NOTEDELAY]// read note delay + cmp r0, #0 // dont update if nonzero + beq channel_update_achn + + ldrb r0, [r6, #MCA_FLAGS] + orr r0, #MCAF_UPDATED + strb r0, [r6, #MCA_FLAGS] + b no_achn + +channel_update_achn: + + ldrb r0, [r7, #MCH_PANNING] // copy panning + strb r0, [r6, #MCA_PANNING] + ldr r0, [r7, #MCH_PERIOD] // copy period + str r0, [r6, #MCA_PERIOD] + mov r0, #0 + strh r0, [r1, #MPV_PANPLUS] // WHAT IS THIS??? "@ <---- RESERVED FOR LATER USE, CLEAR TO ZERO TEMPORARILY" + + ldrb r0, [r6, #MCA_FLAGS] + orr r0, #MCAF_UPDATED + strb r0, [r6, #MCA_FLAGS] + + push {r4} + ldrb r4, [r7, #MCH_ALLOC] + ldr r1,=mpp_Update_ACHN_notest + mov lr, pc + bx r1 + + pop {r4} +no_achn: + pop {lr} + bx lr + +@*********************************************************** +mmChannelStartACHN: // returns r2=note +@*********************************************************** + ldrb r2, [r7, #MCH_BFLAGS+1] // clear tremor/cutvol + bic r2, #0b110 + strb r2, [r7, #MCH_BFLAGS+1] + + cmp r6, #0 // achn==0? + beq 1f // then skip this part + + mov r0, #ACHN_FOREGROUND // set foreground type + strb r0, [r6, #MCA_TYPE] + + ldrb r0, [r6, #MCA_FLAGS] // read flags + bic r0, #0b11000000 // clear SUB, EFFECT + ldr r1,=mpp_clayer // get layer + ldrb r1, [r1] + orr r0, r1, lsl#6 // orr into flags + orr r0, r10, r0, lsl#8 // orr PARENT + strh r0, [r6, #MCA_PARENT] // store parent/flags + ldrb r0, [r7, #MCH_INST] // copy instrument + strb r0, [r6, #MCA_INST] +1: ldreqb r0, [r7, #MCH_INST] + subs r0, #1 + bcc invalid_instrument + + ldr r2, [r8, #MPL_SONGADR] // get instrument pointer + ldr r1, [r8, #MPL_INSTTABLE] + ldr r0, [r1, r0, lsl#2] + add r0, r2 + + ldrb r2, [r7, #MCH_PNOTE] // get pattern note + + ldrh r1, [r0, #C_MASI_MAP] // read notemap offset + tst r1, #0x8000 // test MSB + beq full_notemap // if set: notemap doesnt exist! + // use single entry + cmp r6, #0 // if channel is valid + strneb r1, [r6, #MCA_SAMPLE] // write sample value + strb r2, [r7, #MCH_NOTE] // write note value (without notemap, all entries == PNOTE) + bx lr // return + +full_notemap: + + add r0, r2, lsl#1 // add note offset + ldrh r2, [r0, r1] // read notemap entry [instr+note*2+notemap_offset] + strb r2, [r7, #MCH_NOTE] // write note value + cmp r6, #0 // if channel is valid + mov r0, r2, lsr#8 // write sample value + strneb r0, [r6, #MCA_SAMPLE] // .. + and r2, #255 +invalid_instrument: + bx lr // return + +/********** + + cmp r6, #0 // read notemap [sample] + ldrneb r2, [r0, #C_MASI_MAP+1] + strneb r2, [r6, #MCA_SAMPLE] + +//invalid_instrument: // BUG??? + ldrb r2, [r0, #C_MASI_MAP] // read notemap [note] + strb r2, [r7, #MCH_NOTE] +invalid_instrument: + + bx lr +**************/ + +.global mmGetPeriod +@*********************************************************** +mmGetPeriod: +@*********************************************************** + + ldrb r0, [r8, #MPL_FLAGS] + lsrs r0, #C_FLAGS_SS + bcs get_linear_period // tuning not used here with linear periods + +get_amiga_period: + adr r3, note_table_mod // get octave/mod from note + ldrb r0, [r3, r2] + sub r3, #3*10 + ldrb r2, [r3, r2, lsr#2] + + // r0 = (note mod 12) << 1 + // r1 = tuning + // r2 = (note / 12) + + ldr r3,=ST3_FREQTABLE // read st3 table entry + ldrh r0, [r3, r0] + + mov r3, #0x00AB0 // r3 = 133808 + orr r3, #0x20000 + mul r0, r3, r0 // multiply by magic number... + mov r0, r0, lsr r2 // shift by octave + cmp r1, #0 + beq 1f + swi SWI_DIVIDE<<16 // divide value / tuning +1: bx lr + +.global note_table_oct // remove this, make this static +.global note_table_mod // remove this, make this staic +note_table_oct: +.byte 0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5, 6,6,6 ,7,7,7,8,8,8,9,9,9 +note_table_mod: +.byte 0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0,2,4,6,8,10,12,14,16,18,20,22,0 +.align 2 + +get_linear_period: + ldr r1,=IT_PitchTable + ldr r0, [r1, r2, lsl#2] + bx lr + +.pool diff --git a/libs/maxmod/mm_mixer_gba.S b/libs/maxmod/mm_mixer_gba.S new file mode 100644 index 0000000..16bdeb7 --- /dev/null +++ b/libs/maxmod/mm_mixer_gba.S @@ -0,0 +1,1367 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> + +@ read frequency value + + ldr rfreq, [rchan, #CHN_FREQ] + cmp rfreq, #0 + beq .mpm_next @ EXIT if zero ----------------=-> + + ldr r0,=mm_ratescale + ldr r0, [r0] + mul rfreq, r0 + lsr rfreq, #14 + +@ load mixing buffers + + ldr rmixb,=mm_mixbuffer + ldr rmixb,[rmixb] + +@ get read position + + ldr rread, [rchan, #CHN_READ] + +@ calculate volume + + ldrb rvolR,[rchan, #CHN_VOL] @ volume = 0-255 + ldrb r0, [rchan, #CHN_PAN] @ pan = 0-255 + + rsb r0, r0, #256 + mul rvolL, r0, rvolR @ (vol*pan) = right volume + mov rvolL, rvolL, lsr#8 + add rvolA, rvolA, rvolL @ add to volume counter + rsb r0, r0, #256 + mul rvolR, r0, rvolR @ calc left volume (256-pan)*vol + mov rvolR, rvolR, lsr#8 + add rvolA, rvolA, rvolR, lsl#16 + + ldr rmixc, [sp] @ get mix count + +@**************************************************************** +.mpm_remix_test: +@**************************************************************** + + mov r2, #0 + mul r1, rmixc, rfreq // get number of samples that will be read + + cmp rfreq, #FETCH_THRESHOLD + bge 1f + + cmp r1, #FETCH_SIZE<<12 // check if its > fetch size + movhi r1, #FETCH_SIZE<<12 // if so: clamp to fetch size and set flag + movhi r2, #1 + +1: +// ldr r0, [rchan, #CHN_LEN] // now subtract length - read to get # samples remaining + ldr r0, [rsrc, #-C_SAMPLE_DATA+C_SAMPLE_LEN] + rsb r0, rread, r0, lsl#SAMPFRAC +// sub r0, r0, rread // in the source + cmp r1, r0 // clamp mix count + movhi r1, r0 + bhi .calc_mix + cmp r2, #0 + beq .mpm_mix_full + +.calc_mix: + + + push {r1} // preserve sample count + + +//-------------------------------- +.macro DIV_ITER shift +//-------------------------------- + cmp r0, rfreq, lsl#\shift + subcs r0, rfreq, lsl#\shift + addcs r2, #1<<\shift +.endm +//-------------------------------- +.macro DIVIDER shift +//-------------------------------- + DIV_ITER \shift +.if \shift != 0 + DIVIDER (\shift-1) +.endif +.endm +//-------------------------------- + + mov r0, r1 // divide samples / frequency (24bit/16bit) + mov r2, #0 + +1: subs r0, rfreq, lsl#16 // divide top part + addcs r2, #1<<16 + bcs 1b + add r0, rfreq, lsl#16 + + DIVIDER 15 // divide the rest... + + cmp r0, #1 // round up result + adc r0, r2, #0 + +// mov r0,r1 +// mov r1,rfreq +// swi 0x060000 +// cmp r1, #0 +// addne r0, #1 + + pop {r1} // restore sample count + sub rmixc, r0 // subtract from mixcount + mov rmixcc, r0 + b .mpm_mix_short + +@------------------------------------------------------------------------ +@ SECTOR 2, MIXING +@------------------------------------------------------------------------ + +@----------------------------------------- +.mpm_mix_full: +@----------------------------------------- + +@ mix all samples + + mov rmixcc, rmixc @ <-- move mixing count + mov rmixc, #0 @ clear mixing count +.mpm_mix_short: + +@------------------------------------------------------ +.mpm_remix: +@------------------------------------------------------ + +@ mix samples... +@ preserve registers + stmfd sp!, {rmixc,rvolA,rchan} + +@ zero mixing count?? + cmp rmixcc, #0 + beq .mpm_mix_complete @ exit --------> + + cmp rfreq, #FETCH_THRESHOLD + bge .dont_use_fetch + + /* + ldr r0,=mm_fetch // transfer samples from ROM to RAM + add r1, #2<<14 // add threshold for safety + ldr r2,=REG_DMA3SAD + str r0, [r2, #4] + add r0, r10, rread, lsr#12 + bic r0, #0b11 + str r0, [r2, #0] + mov r0, #(1<<31)+(1<<26) + add r0, r1, lsr#14 + str r0, [r2, #8] + b fooo + */ + + // [cycle timings assume 3,1 ROM waitstates] + + push {r3-r12} + // r10 is SRC! + ldr r0,=mm_fetch // destination + add r10, r10, rread, lsr#12 // add read offset to source + bic r10, #0b11 // align to 32 bits + add r1, #4<<12 // add safety threshold + subs r1, #40<<12 // subtract 36 + + bcc .exit_fetch // skip large fetch if negative +.fetch: ldmia r10!, {r2-r9,r11,r14} // read 40 samples [44 cycles] + stmia r0!, {r2-r9,r11,r14} // write 40 samples [11 cycles] + subs r1, #40<<12 // count [1 cycle ] + bcc .exit_fetch // exit if done [1 cycle ] + ldmia r10!, {r2-r9,r11,r14} // read 40 samples [44 cycles] + stmia r0!, {r2-r9,r11,r14} // write 40 samples [11 cycles] + subs r1, #40<<12 // count [1 cycle ] + bcc .exit_fetch // exit if done [1 cycle ] + ldmia r10!, {r2-r9,r11,r14} // read 40 samples [44 cycles] + stmia r0!, {r2-r9,r11,r14} // write 40 samples [11 cycles] + subs r1, #40<<12 // count [1 cycle ] + bcs .fetch // loop if remaining [3 cycles] + // [173 cycles/120 samples] +.exit_fetch: + + adds r1, #(40<<12)-(24<<12) + bmi .end_medfetch +.medfetch: + ldmia r10!, {r2-r7} // read 24 samples [26] + stmia r0!, {r2-r7} // write 24 samples [7 ] + subs r1, #24<<12 // count [1 ] + bcc .end_medfetch // exit if done [1 ] + ldmia r10!, {r2-r7} // read 24 samples [26] + stmia r0!, {r2-r7} // write 24 samples [7 ] + subs r1, #24<<12 // count [1 ] + bcc .end_medfetch // exit if done [1 ] + ldmia r10!, {r2-r7} // read 24 samples [26] + stmia r0!, {r2-r7} // write 24 samples [7 ] + subs r1, #24<<12 // count [1 ] + bcs .medfetch // loop [3 ] +.end_medfetch: // [107] + + adds r1, #24<<12 // add 24 back + bmi .end_fetch // exit if <= 0 +.fetchsmall: + ldr r2, [r10], #4 // read 4 samples [8] + str r2, [r0], #4 // write 4 samples [2] + subs r1, #4<<12 // count [1] + ble .end_fetch // exit maybe [1] + ldr r2, [r10], #4 // read 4 samples [8] + str r2, [r0], #4 // write 4 samples [2] + subs r1, #4<<12 // count [1] + bgt .fetchsmall // exit maybe [3] +.end_fetch: + + pop {r3-r12} // restore regs + +fooo: + + mov r0, rread, lsr#12 // get read integer + push {r0, rsrc} // preserve regs + bic rread, r0, lsl#12 // clear integer + and r0, #0b11 // mask low bits + ldr rsrc,=mm_fetch // + add rsrc, rsrc, r0 // offset source (fetch is word aligned!) + +.dont_use_fetch: + + tst rmixb, #0b11 // test alignment of work output + beq .mpm_aligned + +#define rsamp1 r1 +#define rsampa r0 +#define rsampb r2 + @ routine to WORD align mixing sector + ldrb rsampa, [rsrc, rread, lsr#SAMPFRAC] @ load sample + add rread, rread, rfreq @ add frequency + mul rsampb, rsampa, rvolL @ multiply by left volume + ldrh rsamp1, [rmixb] @ add to mixing buffer (left) + add rsamp1, rsamp1, rsampb, lsr#5 + strh rsamp1, [rmixb], #4 + mul rsampb, rsampa, rvolR @ multiply by right volume + ldrh rsamp1, [rmixb] @ add to mixing buffer (right) + add rsamp1, rsamp1, rsampb, lsr#5 + strh rsamp1, [rmixb], #2 + sub rmixcc, rmixcc, #1 @ decrement mix count + +#undef rsamp1 +#undef rsampa +#undef rsampb + +.mpm_aligned: + // determine mixing mode + cmp rvolL, rvolR // if volume_left == volume_right then assume 'center' mixing + beq .mpm_mix_ac + cmp rvolL, #0 // if left volume is zero, do 'right' mixing + beq .mpm_mix_ar + cmp rvolR, #0 // if right volume is zero, do 'left' mixing + beq .mpm_mix_al + b mmMix_ArbPanning // otherwise do arb mixing +.mpm_mix_al: + b mmMix_HardLeft +.mpm_mix_ar: + b mmMix_HardRight + +@ center mixing------------ +.mpm_mix_ac: + cmp rvolL, #0 // check if volume is zero + bne mmMix_CenteredPanning // mix samples if not zero + b mmMix_Skip // skip samples if zero +.mpm_mix_complete: + + cmp rfreq, #FETCH_THRESHOLD + poplt {r0, rsrc} // restore regs + addlt rread, rread, r0, lsl#12 // add old integer to read + ldmfd sp!, {rmixc,rvolA,rchan} // restore more regs + + ldr r1, [rsrc, #-C_SAMPLE_DATA+C_SAMPLE_LEN] + lsl r1, #SAMPFRAC + //ldr r1, [rchan, #CHN_LEN] // check length against position + cmp r1, rread + bgt .mpm_channelfinished + +// ldr r1, [rchan, #CHN_LOOP] // read channel loop + + ldr r1, [rsrc, #-C_SAMPLE_DATA+C_SAMPLE_LOOP] + cmp r1, #0 +// movs r1, r1, lsl#8 // mask out high byte (that is VOLUME) + bmi .mpm_channel_stop // MSB = no loop, stop channel -> + + + sub rread,rread,r1,lsl#(SAMPFRAC) // subtract loop length (< + b .mpm_remix_test // yes: loop + +@---------------------------------------------------------------- +.mpm_channel_stop: +@---------------------------------------------------------------- + +@ *** END OF SAMPLE + mov r1, #1<<31 // disable channel + str r1, [rchan, #CHN_SRC] + +@ mix zero into the rest of the buffer + ldr rsrc,=mpm_nullsample // mix zero into the rest of the buffer + mov rfreq, #0 // zero freq + mov rread, #0 // zero freq + movs rmixcc, rmixc // mix remaining amount + ble .mpm_channelfinished // (exit if zero) + mov rmixc, #0 + mov r1, #0 + b .mpm_remix // mix 'zero' into the rest of the data + +@--------------------------------------------------------------- +.mpm_channelfinished: +@--------------------------------------------------------------- + + cmp rmixc, #0 // mix more samples? + bne .mpm_remix_test // yes: loop + +@ *** END OF MIXING *** + + str rread, [rchan, #CHN_READ] // save read position + +@----------------------- +.mpm_next: +@----------------------- + + add rchan, rchan, #CHN_SIZE // seek to next channel + ldr r0,=mm_mixch_end // compare with ending + ldr r0,[r0] + cmp rchan, r0 + bne .mpm_cloop // loop if != + +@---------------------------------------------------------------------------------- +@ SECTOR 3, POST-PROCESSING +@---------------------------------------------------------------------------------- + +#define prmixl r0 +#define prwritel r2 +#define prwriter r3 +#define prcount r4 +#define prvolR r12 +#define prvolL r11 +#define prsamp1 r6 +#define prsamp2 r5 +#define prsamp3 r7 + + ldr prmixl,=mm_mixbuffer + ldr prmixl,[prmixl] + + ldr prwritel,=mp_writepos + ldr prwritel, [prwritel] + ldr prwriter,=mm_mixlen + ldr prwriter, [prwriter] + add prwriter, prwritel, prwriter, lsl#1 @#MP_MIXLEN*2 + ldmfd sp!, {prcount} + +@ get volume accumulators + + mov prvolR, rvolA, lsr#16+1 + mov prvolR, prvolR, lsl#3 + + mov prvolL, rvolA, lsl#16 + mov prvolL, prvolL, lsr#16+1 + mov prvolL, prvolL, lsl#3 + + subs prcount, prcount, #1 + ble .mpm_copy2_end + +@-------------------------------------------------- +.mpm_copy2: +@-------------------------------------------------- + +@ ***************** LEFT OUTPUT ****************** + + ldr prsamp1, [prmixl], #4 @ get 2 mixed samples + sub prsamp2, prsamp1, prvolL @ convert to signed + + mov prsamp2, prsamp2, lsl#16 @ mask low hword with sign extension + movs prsamp2, prsamp2, asr#16+3 @ and convert 11-bit to 8-bit + + cmp prsamp2, #-128 @ clamp + movlt prsamp2, #-128 @ + cmp prsamp2, #127 @ + movgt prsamp2, #127 @ + + @ next sample... + rsbs prsamp3, prvolL, prsamp1,lsr#16 @ convert to signed + movs prsamp3, prsamp3, asr#3 @ convert 11-bit to 8-bit + + cmp prsamp3, #-128 @ clamp + movlt prsamp3, #-128 @ + cmp prsamp3, #127 @ + movgt prsamp3, #127 @ + + and prsamp2, prsamp2, #255 @ write to output + orr prsamp2, prsamp3, lsl#8 @ + strh prsamp2, [prwritel], #2 @ + +@ **************** RIGHT OUTPUT ****************** + + ldr prsamp1, [prmixl], #4 @ get 2 mixed samples + sub prsamp2, prsamp1, prvolR @ convert to signed + + mov prsamp2, prsamp2, lsl#16 @ mask low hword and convert 11-bit to 8-bit + movs prsamp2, prsamp2, asr#16+3 @ + + cmp prsamp2, #-128 @ clamp value + movlt prsamp2, #-128 @ + cmp prsamp2, #127 @ + movgt prsamp2, #127 @ + + @ next sample... + rsbs prsamp3, prvolR, prsamp1,lsr#16 @ convert to signed + movs prsamp3, prsamp3, asr#3 @ convert 11-bit to 8-bit + + cmp prsamp3, #-128 @ clamp value + movlt prsamp3, #-128 @ + cmp prsamp3, #127 @ + movgt prsamp3, #127 @ + + and prsamp2, prsamp2, #255 @ write to output + orr prsamp2, prsamp3, lsl#8 @ + strh prsamp2, [prwriter], #2 @ + + subs prcount, prcount, #2 @ loop + bgt .mpm_copy2 @ + +@------------------------------------------------------------------ + +.mpm_copy2_end: + ldr r0,=mp_writepos @ store new write position + str prwritel, [r0] + +@------------------------------------------------------------------ + + ldmfd sp!, {r4-r11,lr} // restore registers + bx lr // phew! + +.pool + +@================================================================================ +@ MIXING ROUTINES +@================================================================================ + +.macro READ_AND_INCREMENT reg + ldrb \reg, [rsrc, rread, lsr#SAMPFRAC] + add rread, rread, rfreq +.endm + +.macro READ_D reg, tmp + READ_AND_INCREMENT \reg + READ_AND_INCREMENT \tmp + orr \reg, \tmp, lsl#16 +.endm + +.macro MIX_D vol, tmp1, tmp2 + READ_D \tmp1, \tmp2 // load&combine 2 samples + mul \tmp2, \tmp1, \vol // multiply by volume + bic \tmp2, \tmp2, #0x1F0000 // prepare for shift +.endm + +.macro MIX_DA vol, target, tmp1, tmp2 + MIX_D \vol, \tmp1, \tmp2 + add \target, \target, \tmp2, lsr#5 // add 11-bit values +.endm + +.macro MIX_DC vol, target_a, target_b, tmp1, tmp2 + MIX_D \vol, \tmp1, \tmp2 + add \target_a, \target_a, \tmp2, lsr#5 // add 11-bit values + add \target_b, \target_b, \tmp2, lsr#5 +.endm + +.macro MIX_DB vol_l, vol_r, target_a, target_b, tmp1, tmp2 + READ_D \tmp1, \tmp2 + +.if \target_a != 0 + mul \tmp2, \tmp1, \vol_l // multiply by volume + bic \tmp2, \tmp2, #0x1F0000 // prepare for shift + add \target_a, \target_a, \tmp2, lsr#5 // add 11-bit values +.endif +.if \target_b != 0 + mul \tmp2, \tmp1, \vol_r // multiply by volume + bic \tmp2, \tmp2, #0x1F0000 // prepare for shift + add \target_b, \target_b, \tmp2, lsr#5 // add 11-bit values +.endif +.endm + +@----------------------------------------------------------------------------------- +mmMix_Skip: +@----------------------------------------------------------------------------------- + +@ mix nothing + mul r0, rmixcc, rfreq @ read += samples * frequency + add rread, rread, r0 + b .mpm_mix_complete + +@----------------------------------------------------------------------------------- +mmMix_HardLeft: +@----------------------------------------------------------------------------------- +@ mix hard panned left + + bl mmMix_SingleChannel // mix left channel + bgt mmMix_Remainder // mix remaining amount + b .mpm_mix_complete // return + +@----------------------------------------------------------------------------------- +mmMix_HardRight: +@----------------------------------------------------------------------------------- +@ hard panned right + + mov rvolL, rvolR // move volume + add rmixb, rmixb, #4 // offset to 'right' data + bl mmMix_SingleChannel // mix routine + mov rvolL, #0 // clear left volume again + sub rmixb, rmixb, #4 // remove offet + bgt mmMix_Remainder // mix remaining count + b .mpm_mix_complete // return + +@---------------------------------------- +mmMix_SingleChannel: +@---------------------------------------- + +#define rsamp1 r1 +#define rsamp2 r2 +#define rsamp3 r11 +#define rsamp4 r12 +#define rsampa r0 +#define rsampb r4 + +@ hard panned mixing (single channel mono) +@ interleaving really cuts this method's effectiveness :( + +@ mix 8 samples/loop + + subs rmixcc, rmixcc, #8 + bmi .mpmah_8e +.mpmah_8: + ldmia rmixb, {rsamp1, rsamp2, rsamp3} // load data [2nd word not used] + MIX_DA rvolL, rsamp1, rsampa, rsampb // mix data + str rsamp1, [rmixb], #8 // store mixed word + MIX_DA rvolL, rsamp3, rsampa, rsampb // mix data + str rsamp3, [rmixb], #8 // store mixed word + ldmia rmixb, {rsamp1, rsamp2, rsamp3} // load data [2nd word not used] + MIX_DA rvolL, rsamp1, rsampa, rsampb // mix data + str rsamp1, [rmixb], #8 // store mixed word + MIX_DA rvolL, rsamp3, rsampa, rsampb // mix data + str rsamp3, [rmixb], #8 // store mixed word + subs rmixcc, rmixcc, #8 // decrement 8 samples + bpl .mpmah_8 // loop if >= 0 +.mpmah_8e: + +@ mix remainder samples + + adds rmixcc, rmixcc, #8 // fix mixing count + bx lr // return + +#undef rsamp1 +#undef rsamp2 +#undef rsamp3 +#undef rsamp4 +#undef rsampa +#undef rsampb + +@---------------------------------------------------------- +mmMix_CenteredPanning: +@---------------------------------------------------------- + +#define rsamp1 r1 +#define rsamp2 r2 +#define rsamp3 r4 +#define rsamp4 r6 +#define rsamp5 r11 +#define rsamp6 r12 +#define rsampa r0 +#define rsampb lr + +@ mix center panning (double channel mono) + + subs rmixcc, rmixcc, #6 + bmi .mpmac_6e +.mpmac_6: + + ldmia rmixb, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5,rsamp6} // read words + MIX_DC rvolL, rsamp1, rsamp2, rsampa, rsampb // mix data + MIX_DC rvolL, rsamp3, rsamp4, rsampa, rsampb + MIX_DC rvolL, rsamp5, rsamp6, rsampa, rsampb + stmia rmixb!, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5,rsamp6} // write words + subs rmixcc, rmixcc, #6 // count + bpl .mpmac_6 // loop +.mpmac_6e: + + mov rvolR, rvolL // restore right volume (same as left) + adds rmixcc, rmixcc, #6 // fix mix count + bgt mmMix_Remainder // mix remaining amount + b .mpm_mix_complete // finished mixing segment + +#undef rsamp1 +#undef rsamp2 +#undef rsamp3 +#undef rsamp4 +#undef rsamp5 +#undef rsamp6 +#undef rsampa +#undef rsampb + +@--------------------------------------------------- +mmMix_ArbPanning: // SLOWEST! +@--------------------------------------------------- + +#define rsamp1 r1 +#define rsamp2 r2 +#define rsamp3 r4 +#define rsamp4 r11 +#define rsampa r0 +#define rsampb r12 +#define rsamp5 r14 + + subs r3, r3, #10 + bmi .mpmaa_10e +.mpmaa_10: + + ldmia rmixb, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5} // load bufferdata + MIX_DB rvolL, rvolR, rsamp1, rsamp2, rsampa, rsampb // mix + MIX_DB rvolL, rvolR, rsamp3, rsamp4, rsampa, rsampb // mix + MIX_DB rvolL, rvolR, rsamp5, 0, rsampa, rsampb // mix half + stmia rmixb!, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5} // store bufferdata + ldmia rmixb, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5} // load bufferdata + mul rsampb, rsampa, rvolR // mix other half + bic rsampb, rsampb, #0x1F0000 // .. + add rsamp1, rsamp1, rsampb, lsr#5 // .. + MIX_DB rvolL, rvolR, rsamp2, rsamp3, rsampa, rsampb // mix + MIX_DB rvolL, rvolR, rsamp4, rsamp5, rsampa, rsampb // mix + stmia rmixb!, {rsamp1,rsamp2,rsamp3,rsamp4,rsamp5} // store bufferdata + subs rmixcc, rmixcc, #10 // count + bpl .mpmaa_10 // loop +.mpmaa_10e: + + adds rmixcc, rmixcc, #10 + bgt mmMix_Remainder + b .mpm_mix_complete + +.pool + +#undef rsamp1 +#undef rsamp2 +#undef rsamp3 +#undef rsamp4 +#undef rsampa +#undef rsampb + +//--------------------------------------------------------------------------- +mmMix_Remainder: +//--------------------------------------------------------------------------- +// (slow function to mix remaining amount of samples) +// assumes mix count isn't zero! + +#define rsamp1 r1 +#define rsamp2 r2 +#define rvol r11 +#define rsampa r0 +#define rsampb r4 + + orr rvol, rvolL, rvolR, lsl#16 + +.mix_remaining: +/* ldrb rsampa, [rsrc, rread, lsr#SAMPFRAC] @ 3 load sample + add rread, rread, rfreq @ 1 add frequency + mul rsampb, rsampa, rvolL @ 2 multiply by volume + ldrh rsamp1, [rmixb] @ 3 load mix buffer entry + add rsamp1, rsamp1, rsampb, lsr#5 @ 1 add + strh rsamp1, [rmixb], #2 @ 2 store + ldrh rsamp1, [rmixb, #2] @ 3 + mul rsampb, rsampa, rvolR @ 2 + add rsamp1, rsamp1, rsampb, lsr#5 @ 1 + strh rsamp1, [rmixb, #2] @ 2 +*/ + + ldrb rsampa, [rsrc, rread, lsr#SAMPFRAC] @ 3 load sample + add rread, rread, rfreq @ 1 add frequency + mul rsampb, rvol, rsampa @ 2 multiply by volume + ldrh rsamp1, [rmixb] @ 3 load mix buffer entry (left) + bic rsamp2, rsampb, #0xFF0000 @ 1 prep for shift + add rsamp1, rsamp1, rsamp2, lsr#5 @ 1 add + strh rsamp1, [rmixb], #2 @ 2 store (left) + ldrh rsamp1, [rmixb, #2] @ 3 load (right) + add rsamp1, rsamp1, rsampb, lsr#16+5 @ 1 add values + strh rsamp1, [rmixb, #2] @ 2 store (right) + + subs rmixcc, rmixcc, #2 @ 2 + blt .end_mix_remaining @ 1/exit + +/* ldrb rsampa, [rsrc, rread, lsr#SAMPFRAC] @ load sample + add rread, rread, rfreq @ add frequency + mul rsampb, rsampa, rvolL @ multiply by volume + ldrh rsamp1, [rmixb] @ load mix buffer entry + add rsamp1, rsamp1, rsampb, lsr#5 @ add + strh rsamp1, [rmixb], #4 @ store + ldrh rsamp1, [rmixb] + mul rsampb, rsampa, rvolR + add rsamp1, rsamp1, rsampb, lsr#5 + strh rsamp1, [rmixb], #2 +*/ + + ldrb rsampa, [rsrc, rread, lsr#SAMPFRAC] @ 3 load sample + add rread, rread, rfreq @ 1 add frequency + mul rsampb, rvol, rsampa @ 2 multiply by volume + ldrh rsamp1, [rmixb] @ 3 load mix buffer entry (left) + bic rsamp2, rsampb, #0xFF0000 @ 1 prep for shift + add rsamp1, rsamp1, rsamp2, lsr#5 @ 1 add + strh rsamp1, [rmixb], #4 @ 2 store (left) + ldrh rsamp1, [rmixb] @ 3 load (right) + add rsamp1, rsamp1, rsampb, lsr#16+5 @ 1 add values + strh rsamp1, [rmixb], #2 @ 2 store (right) + + bgt .mix_remaining +.end_mix_remaining: + + b .mpm_mix_complete + +#undef rsamp1 +#undef rsamp2 +#undef rvol +#undef rsampa +#undef rsampb + +@============================================================================ +@ END OF MIXER +@============================================================================ + + .TEXT + .THUMB + .ALIGN 2 + +/**************************************************************************** + * mmMixerSetSource( channel, p_sample ) + * + * Set channel source + ****************************************************************************/ + .thumb_func +mmMixerSetSource: + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2 // + ldr r2,=mm_mixchannels // + ldr r2, [r2] // + add r0, r2 // + + add r1, #C_SAMPLE_DATA // set sample data address + str r1, [r0, #CHN_SRC] // + + mov r1, #0 // reset read position + str r1, [r0, #CHN_READ] // + + bx lr + +/**************************************************************************** + * mmMixerSetRead( channel, value ) + * + * Set channel read position + ****************************************************************************/ + .thumb_func +mmMixerSetRead: + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2 // + ldr r2,=mm_mixchannels // + ldr r2,[r2] // + add r0, r2 // + + str r1, [r0, #CHN_READ] // store new offset + bx lr // + +/**************************************************************************** + * mmMixerSetFreq + * + * Set channel mixing rate + ****************************************************************************/ + .thumb_func +mmMixerSetFreq: + +// push {r3, r4} // FIXME: why would you preserve r3? + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2, r0 // + ldr r2,=mm_mixchannels // + ldr r2,[r2] // + add r0, r0, r2 // + + lsl r1, #2 // ... + + strh r1, [r0, #CHN_FREQ] + bx lr + +/* + ldr r4,=mm_freqscalar // r4=scale + ldr r4,[r4] // + + add r2, pc, #0 // switch to arm for a nice long multiply + bx r2 + + .ARM + + //------------------------------------ + // fix frequency to match mixing rate + // a = specified frequency + // hz = a*2y13 / pr + //------------------------------------ + + umull r3, r2, r1, r4 // long multiply + add r3, r3, #32768 // shift, etc.. + mov r3, r3, lsr#16 // + orr r3, r3, r2, lsl#16 // + + str r3, [r0, #CHN_FREQ] // set chan frequency + + ldmfd sp!, {r3,r4} // pop registers + bx lr // return + */ + .THUMB + +/**************************************************************************** + * mmMixerMulFreq( channel, value ) + * + * Scale mixing frequency + ****************************************************************************/ + .thumb_func +mmMixerMulFreq: + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2 // + ldr r2,=mm_mixchannels // + ldr r2, [r2] // + add r0, r2 // + + ldr r3, [r0, #CHN_FREQ] // scale + mul r3, r1 // + lsr r3, #10 // + str r3, [r0, #CHN_FREQ] // + bx lr + +/**************************************************************************** + * mmMixerStopChannel( channel ) + * + * Stop mixing channel + ****************************************************************************/ + .thumb_func +mmMixerStopChannel: + + mov r1, #CHN_SIZE // get channel pointer from index + mul r0, r1 // + ldr r1,=mm_mixchannels // + ldr r1,[r1] // + add r0, r1 // + + mov r1, #1 // set MSB (disable) of source + lsl r1, #31 // + str r1, [r0] // + bx lr + +/**************************************************************************** + * mmMixerChannelActive( channel ) + * + * Test if mixing channel is active + ****************************************************************************/ + .thumb_func +mmMixerChannelActive: + + mov r1, #CHN_SIZE // get channel pointer from index + mul r0, r1 // + ldr r1,=mm_mixchannels // + ldr r1,[r1] // + add r0, r1 // + +mp_Mixer_ChannelEnabledA: + ldr r0, [r0, #CHN_SRC] // nonzero (-1) = enabled + asr r0, #31 // zero = disabled + mvn r0, r0 // + bx lr + +/**************************************************************************** + * mmMixerSetVolume( channel, volume ) + * + * Set channel volume + ****************************************************************************/ + .thumb_func +mmMixerSetVolume: + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2 // + ldr r2,=mm_mixchannels // + ldr r2,[r2] // + add r0, r2 // + + strb r1, [r0, #CHN_VOL] // set volume + + bx lr + +/**************************************************************************** + * mmMixerSetPan( channel, panning ) + * + * Set channel panning + ****************************************************************************/ + .thumb_func +mmMixerSetPan: + + mov r2, #CHN_SIZE // get channel pointer from index + mul r0, r2 // + ldr r2,=mm_mixchannels // + ldr r2,[r2] // + add r0, r2 // + + strb r1, [r0, #CHN_PAN] // set panning + bx lr + +/**************************************************************************** + * mmMixerInit( system ) + * + * Initialize mixer + ****************************************************************************/ + .thumb_func +mmMixerInit: + + ldr r2,=mm_mixbuffer + ldr r1, [r0,#MM_GBA_SYSTEM_ACH_COUNT] + str r1, [r2,#16] + + mov r3, #CHN_SIZE + mul r1, r3 + ldr r3, [r0,#MM_GBA_SYSTEM_MIXCH] + str r3, [r2,#4] + add r3, r1 + str r3, [r2,#20] + ldr r1, [r0,#MM_GBA_SYSTEM_MIXMEM] + str r1, [r2,#0] + ldr r1, [r0,#MM_GBA_SYSTEM_WAVEMEM] + str r1, [r2,#8] + ldr r1, [r0,#MM_GBA_SYSTEM_MODE] + lsl r1, #1 + adr r3, mp_mixing_lengths + ldrh r3, [r3,r1] + str r3, [r2,#12] + adr r3, mp_rate_scales + ldrh r3, [r3, r1] + str r3, [r2, #24] + adr r3, mp_timing_sheet + ldrh r3, [r3, r1] + str r3, [r2, #28] + adr r3, mp_bpm_divisors + lsl r1, #1 + ldr r3, [r3,r1] + + ldr r2,=mm_bpmdv + str r3, [r2,#0] + + + ldr r0,=mm_wavebuffer @ clear wave buffer + ldr r0,[r0] + ldr r1,=mm_mixlen + ldr r1, [r1] + mov r2, #0 @ .. +.mpi_loop1: @ .. + stmia r0!, {r2} @ .. + sub r1, r1, #1 @ .. + bne .mpi_loop1 @ .. + + ldr r0,=mp_mix_seg @ reset mixing segment + strb r2, [r0] @ .. + + ldr r0,=mm_mixchannels @ disable mixing channels + ldr r1,[r0,#12]@ nchannels + ldr r0,[r0] + ldr r3,=1<<31 +.mpi_loop2: + str r3, [r0, #CHN_SRC] + add r0, #CHN_SIZE + sub r1, #1 + bne .mpi_loop2 + + ldr r0,=mmVBlank @ enable vblank routine + ldr r1,=0xE1A00000 @ .. + str r1, [r0] @ .. + + ldr r0,=REG_SGFIFOA @ clear fifo data + str r2, [r0] @ .. + str r2, [r0, #4] @ .. + ldr r0,=REG_SOUNDCNT_H @ reset direct sound + strh r2, [r0] @ .. + ldr r1,=0x9A0C @ setup sound [DIRECT SOUND A/B reset,timer0,A=left,B=right,volume=100%] + strh r1, [r0] @ .. + ldr r0,=REG_DMA1SAD @ setup DMA source addresses (playback buffers) + ldr r1,=mm_wavebuffer + ldr r2, [r1, #4]@mixlen + ldr r1, [r1] + + @ldr r1,=mp_playbuffer_l @ .. + str r1, [r0] @ .. + + add r1,r2 + add r1,r2 + +@ ldr r1,=mp_playbuffer_r @ .. + str r1, [r0, #12] @ .. + + ldr r1,=REG_SGFIFOA @ setup DMA destination (sound fifo) + str r1, [r0, #4] @ .. + add r1, #4 @ .. + str r1, [r0, #16] @ .. + + ldr r1,=0xB6000000 @ enable DMA (enable,fifo request,32-bit,repeat) + str r1, [r0, #8] @ .. + str r1, [r0, #20] @ .. + + ldr r0,=REG_SOUNDCNT_X @ master sound enable + mov r1, #0x80 @ .. + strh r1, [r0] @ .. + + ldr r0,=REG_VCOUNT @ wait for new frame +.mpi_vsync: @ .. + ldrh r1, [r0] @ skip current vblank period + cmp r1, #160 @ .. + bge .mpi_vsync @ .. +.mpi_vsync2: + ldrh r1, [r0] @ wait for new one + cmp r1, #160 @ .. + blt .mpi_vsync2 @ .. + +.mpi_vsync_2: @ pass#2 + ldrh r1, [r0] @ skip current vblank period + cmp r1, #160 @ .. + bge .mpi_vsync_2 @ .. +.mpi_vsync2_2: + ldrh r1, [r0] @ wait for new one + cmp r1, #160 @ .. + blt .mpi_vsync2_2 @ .. + + ldr r0,=REG_TM0CNT @ enable sampling timer + ldr r1,=mm_timerfreq + ldr r1,[r1] + mov r2, #0x80 + lsl r2, #16 + orr r1, r2 + @ldr r1,=(-MP_TIMERFREQ&0xFFFF) | (0x80<<16) @ .. + str r1, [r0] @ .. + bx lr @ finished + + +// round(rate / 59.737) +.align 2 +mp_mixing_lengths: + .hword 136, 176, 224, 264, 304, 352, 448, 528 + @ 8khz,10khz,13khz,16khz,18khz,21khz,27khz,32khz + +.align 2 +//mp_freq_scales: @ (16khz -> real) +// .hword 33056, 25536, 20064, 17024, 14784, 12768 + +// 15768*16384 / rate +mp_rate_scales: + .hword 31812, 24576, 19310, 16384, 14228, 12288, 9655, 8192 + @ 8khz, 10khz, 13khz, 16khz, 18khz, 21khz, 27khz, 32khz + @ 8121, 10512, 13379, 15768, 18157, 21024, 26758, 31536, + +.align 2 +// gbaclock / rate +mp_timing_sheet: + .hword -2066,-1596,-1254,-1064, -924, -798, -627, -532 + @ 8khz,10khz,13khz,16khz,18khz,21khz,27khz,32khz + +.align 2 +// rate * 2.5 +mp_bpm_divisors: + .word 20302,26280,33447,39420,45393,52560,66895,78840 + + +.end diff --git a/libs/maxmod/mm_types.h b/libs/maxmod/mm_types.h new file mode 100644 index 0000000..222ff5e --- /dev/null +++ b/libs/maxmod/mm_types.h @@ -0,0 +1,327 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> 32768 (HZ) + mm_word sampling_rate; + +// number of samples to buffer + mm_word buffer_length; + +// pointer to filling routine + mm_stream_func callback; + +// stream format (mm_stream_formats) + mm_word format; + +// hardware timer selection (mm_stream_timers) + mm_word timer; + +// if set, user must call mmStreamUpdate manually + mm_bool manual; + +//----------------------------------------------------------------------------- +} mm_stream; +//----------------------------------------------------------------------------- + +typedef struct t_mmlayer +{ + +// current tick count + mm_byte tick; + +// current row being played + mm_byte row; + +// module sequence position + mm_byte position; + +// number of rows in current pattern + mm_byte nrows; + +// global volume multiplier + mm_byte global_volume; + +// speed of module (ticks/row) + mm_byte speed; + +// module is active + mm_byte active; + +// tempo of module + mm_byte bpm; + +//----------------------------------------------------------------------------- +} mm_modlayer; +//----------------------------------------------------------------------------- + +typedef struct tmm_voice +{ + +// data source information + mm_addr source; // address to sample data + mm_word length; // length of sample data OR loop length (expressed in WORDS) + mm_hword loop_start; // loop start position (expressed in WORDS) + +// frequency divider + mm_hword timer; + +// update flags + mm_byte flags; + +// source format + mm_byte format; // 0: 8-bit + // 1: 16-bit + // 2: adpcm +// repeat mode + mm_byte repeat; // 0: manual + // 1: forward loop + // 2: one shot + +// volume + divider setting + mm_byte volume; // 0->127 + mm_byte divider; // 0->3 = /1, /2, /4, /16 + +// panning setting + mm_byte panning; // 0->127 + +// index of voice + mm_byte index; // 0->15 + +// pad to 20 bytes + mm_byte reserved[1]; + +//----------------------------------------------------------------------------- +} mm_voice; +//----------------------------------------------------------------------------- + +enum { + MMVF_FREQ =2, // update frequency when this flag is set + MMVF_VOLUME =4, // update volume + MMVF_PANNING =8, // update panning + MMVF_SOURCE =16, // update source and start note + MMVF_STOP =32 // stop voice (cut sound) +}; + +//----------------------------------------------------------------------------- + +#endif diff --git a/libs/maxmod/mp_defs.inc b/libs/maxmod/mp_defs.inc new file mode 100644 index 0000000..7716ef9 --- /dev/null +++ b/libs/maxmod/mp_defs.inc @@ -0,0 +1,117 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> -#include "data/aas_data.h" +#include "data/snd.h" #define CONV_RGB24_RGB15(r, g, b) \ (((r) >> 3) | (((uint16_t)(g) & 0xf8) << 2) | (((uint16_t)(b) & 0xf8) << 7)) @@ -12,4 +12,6 @@ extern unsigned char tuncross_cmap[]; extern uint32_t tunmap[]; +extern unsigned char sound_data[]; + #endif /* DATA_H_ */ diff --git a/src/data.s b/src/data.s index 7a74252..94949e7 100644 --- a/src/data.s +++ b/src/data.s @@ -3,6 +3,7 @@ .globl tuncross_pixels .globl tuncross_cmap .globl tunmap + .globl sound_data .align 1 tuncross_pixels: @@ -13,3 +14,6 @@ tuncross_cmap: .align 2 tunmap: .incbin "data/tun.map" + + .align 2 +sound_data: .incbin "data/snd.bin" diff --git a/src/debug.c b/src/debug.c index 9fd40d3..e983ff6 100644 --- a/src/debug.c +++ b/src/debug.c @@ -12,29 +12,11 @@ uint16_t vblperf_color[] = { 0x3e0, 0xf863, 0xffc0, 0x3ff, 0x1ff, 0x001f, 0xf81f, 0x1e0, 0xf81f, 0xf81f, 0xf81f }; -static void vblperf_intr(void) -{ - vblperf_count++; -} - -void vblperf_start(int palidx) +void vblperf_setcolor(int palidx) { vblperf_palptr = (uint16_t*)CRAM_BG_ADDR + palidx; - intr_disable(); - REG_DISPSTAT |= DISPSTAT_IEN_VBLANK; - interrupt(INTR_VBLANK, vblperf_intr); - unmask(INTR_VBLANK); - intr_enable(); } -void vblperf_stop(void) -{ - intr_disable(); - REG_DISPSTAT &= ~DISPSTAT_IEN_VBLANK; - interrupt(INTR_VBLANK, 0); - mask(INTR_VBLANK); - intr_enable(); -} uint32_t panic_regs[16]; void get_panic_regs(void); @@ -71,6 +53,12 @@ void panic(void *pc, const char *fmt, ...) y = dbg_drawstr(0, y, " r8 %08x r9 %08x\nr10 %08x r11 %08x\n ip %08x sp %08x\n lr %08x pc %08x\n", reg[8], reg[9], reg[10], reg[11], reg[12], reg[13], reg[14], reg[15]); + /* stop any sound/music playback */ + REG_SOUNDCNT_H = SCNT_DSA_CLRFIFO | SCNT_DSB_CLRFIFO; + REG_TMCNT_H(1) &= ~TMCNT_EN; + REG_DMA1CNT_H = 0; + REG_DMA2CNT_H = 0; + for(;;); } diff --git a/src/debug.h b/src/debug.h index 5715da8..45cc067 100644 --- a/src/debug.h +++ b/src/debug.h @@ -10,8 +10,7 @@ extern uint16_t vblperf_color[]; uint16_t *vblperf_palptr; volatile int vblperf_count; -void vblperf_start(int palidx); -void vblperf_stop(void); +void vblperf_setcolor(int palidx); #define vblperf_begin() \ do { \ diff --git a/src/gamescr.c b/src/gamescr.c index 8ce610e..1b11c25 100644 --- a/src/gamescr.c +++ b/src/gamescr.c @@ -18,7 +18,7 @@ void gamescr(void) REG_DISPCNT = 4 | DISPCNT_BG2 | DISPCNT_FB1; - vblperf_start(0xff); + vblperf_setcolor(0xff); cdst = (uint16_t*)CRAM_BG_ADDR; csrc = tuncross_cmap; diff --git a/src/main.c b/src/main.c index f629a13..9b3b0e8 100644 --- a/src/main.c +++ b/src/main.c @@ -3,14 +3,10 @@ #include "intr.h" #include "debug.h" #include "game.h" - -#include "AAS.h" #include "data.h" +#include "maxmod.h" -#define RGB15(r, g, b) \ - (((uint16_t)(r) & 0x1f) | \ - (((uint16_t)(g) & 0x1f) << 5) | \ - (((uint16_t)(b) & 0x1f) << 10)) +static void vblank(void); int main(void) { @@ -19,18 +15,28 @@ int main(void) REG_WAITCNT = WAITCNT_PREFETCH | WAITCNT_ROM_2_1; #ifndef NOSOUND - 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(); - - AAS_MOD_Play(AAS_DATA_MOD_popcorn); -#else - intr_enable(); + mmInitDefault(sound_data, 8); + mmStart(MOD_POPCORN, MM_PLAY_LOOP); #endif + intr_disable(); + interrupt(INTR_VBLANK, vblank); + REG_DISPSTAT |= DISPSTAT_IEN_VBLANK; + unmask(INTR_VBLANK); + + intr_enable(); gamescr(); for(;;); return 0; } + +static void vblank(void) +{ + vblperf_count++; + +#ifndef NOSOUND + mmVBlank(); + mmFrame(); +#endif +} diff --git a/tools/conv2aas/Makefile b/tools/conv2aas/Makefile deleted file mode 100644 index af55b98..0000000 --- a/tools/conv2aas/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -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 deleted file mode 100644 index 679f15d..0000000 --- a/tools/conv2aas/conv2aas.c +++ /dev/null @@ -1,1247 +0,0 @@ -/* 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 -#include -#include -#include -#include - -#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 = ¬es_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*)(¬es_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; -} diff --git a/tools/mmutil/COPYING b/tools/mmutil/COPYING new file mode 100644 index 0000000..fd6f82c --- /dev/null +++ b/tools/mmutil/COPYING @@ -0,0 +1,24 @@ +Maxmod Utility + +Copyright (c) 2008, Mukunda Johnson + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the owners nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/tools/mmutil/Makefile b/tools/mmutil/Makefile new file mode 100644 index 0000000..73eefd4 --- /dev/null +++ b/tools/mmutil/Makefile @@ -0,0 +1,14 @@ +src = $(wildcard *.c) +obj = $(src:.c=.o) +bin = mmutil + +CC = gcc +CFLAGS = -Wno-multichar +LDFLAGS = -lm + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +.PHONY: clean +clean: + rm -f $(obj) $(bin) diff --git a/tools/mmutil/adpcm.c b/tools/mmutil/adpcm.c new file mode 100644 index 0000000..4f6a053 --- /dev/null +++ b/tools/mmutil/adpcm.c @@ -0,0 +1,221 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include "defs.h" +#include "deftypes.h" +#include "mas.h" + +const s8 IndexTable[8] = { + -1, -1, -1, -1, 2, 4, 6, 8 +}; + +const u16 AdpcmTable[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; + +static int read_sample( Sample* sample, int position ) +{ + int s; + if( sample->format & SAMPF_16BIT ) + { + s = ((s16*)sample->data)[position]; + } + else + { + // expand 8-bit value + int a = ((s8*)sample->data)[position]; + s = (a<<8); + } + if( s < -32767 ) s = -32767; // is this necessary?... + return s; +} + +static int minmax( int value, int low, int high ) +{ + if( value < low ) value = low; + if( value > high ) value = high; + return value; +} + +static int calc_delta( int diff, int step ) +{ + int delta = (step >> 3); // t/8 + + if( diff >= step ) { // t/1 + diff -= step; + delta += step; + } + if( diff >= (step>>1) ) { // t/2 + diff -= step>>1; + delta += step>>1; + } + if( diff >= (step>>2) ) { // t/4 + diff -= step>>2; + delta += step>>2; + } + return delta; +} + +//---------------------------------------------------------------------- +// Compresses a sample with IMA-ADPCM +// Make sure the data has proper alignment/length! +//---------------------------------------------------------------------- +void adpcm_compress_sample( Sample* sample ) +//---------------------------------------------------------------------- +{ + u32 x; + u8* output; + + int prev_value; + int curr_value; + + int diff; + int data; + int delta; + + int index; + int step; + + // allocate space for sample (compressed size) + output = (u8*)malloc( sample->sample_length/2+4 ); + + prev_value = read_sample( sample, 0 ); + index = 0; + + { // determine best (or close to best) initial table value + + int i; + int smallest_error; + int tmp_error; + smallest_error = 9999999; + + + diff = read_sample( sample, 1 ) - read_sample( sample, 0 ); + + for( i = 0; i < 88; i++ ) + { + tmp_error = calc_delta( diff, i ) - diff; + if( tmp_error < smallest_error ) + { + smallest_error = tmp_error; + index = i; + } + } + } + + // set data header + (*((u32*)output)) = prev_value // initial PCM16 value + | (index << 16); // initial table index value + + step = AdpcmTable[index]; + + for( x = 0; x < sample->sample_length; x++ ) + { + curr_value = read_sample( sample, x ); + + diff = curr_value - prev_value; + if( diff < 0 ) + { + // negate difference & set negative bit + diff = -diff; + data = 8; + } + else + { + // clear negative flag + data = 0; + } + + /* + difference calculation: + Diff = AdpcmTable[Index]/8 + IF (data4bit AND 1) THEN Diff = Diff + AdpcmTable[Index]/4 + IF (data4bit AND 2) THEN Diff = Diff + AdpcmTable[Index]/2 + IF (data4bit AND 4) THEN Diff = Diff + AdpcmTable[Index]/1 + */ + + delta = (step >> 3); // t/8 (always) + + if( diff >= step ) { // t/1 + data |= 4; + diff -= step; + delta += step; + } + if( diff >= (step>>1) ) { // t/2 + data |= 2; + diff -= step>>1; + delta += step>>1; + } + if( diff >= (step>>2) ) { // t/4 + data |= 1; + diff -= step>>2; + delta += step>>2; + } + + // add/subtract delta + prev_value += (data&8) ? -delta : delta; + + // claamp output + prev_value = minmax( prev_value, -0x7FFF, 0x7FFF ); + + // add index table value (and clamp) + index = minmax( index + IndexTable[data & 7], 0, 88 ); + + // read new step value + step = AdpcmTable[index]; + + // write output + if( (x & 1) ) + output[(x>>1)+4] |= (data) << 4; + else + output[(x>>1)+4] = (data); + } + + // delete old sample + free( sample->data ); + + // assign new sample + sample->data = output; + + // new format + sample->format = SAMP_FORMAT_ADPCM; + + // new length/loop + sample->sample_length = (sample->sample_length/2) +4; + sample->loop_start /= 2; + sample->loop_end /= 2; + + // step loop past adpcm header + sample->loop_start += 4; + sample->loop_end += 4; +} diff --git a/tools/mmutil/adpcm.h b/tools/mmutil/adpcm.h new file mode 100644 index 0000000..2ecce4c --- /dev/null +++ b/tools/mmutil/adpcm.h @@ -0,0 +1,28 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> (b) ? (b) : (x))) + +#endif // _defs_h_ diff --git a/tools/mmutil/deftypes.h b/tools/mmutil/deftypes.h new file mode 100644 index 0000000..f6afdcf --- /dev/null +++ b/tools/mmutil/deftypes.h @@ -0,0 +1,50 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> > 8) ); + file_byte_count += 2; +} + +void write24( u32 p_v ) +{ + write8( (u8)(p_v & 0xFF) ); + write8( (u8)((p_v >> 8) & 0xFF) ); + write8( (u8)((p_v >> 16) & 0xFF) ); + file_byte_count += 3; +} + +void write32( u32 p_v ) +{ + write16( (u16)(p_v & 0xFFFF) ); + write16( (u16)(p_v >> 16) ); + file_byte_count += 4; +} + +void align16( void ) +{ + if( ftell( fout ) & 1 ) + write8( BYTESMASHER ); +} + +void align32( void ) +{ + if( ftell( fout ) & 3 ) + write8( BYTESMASHER ); + if( ftell( fout ) & 3 ) + write8( BYTESMASHER ); + if( ftell( fout ) & 3 ) + write8( BYTESMASHER ); +} + +void align32f( FILE* p_file ) +{ + if( ftell( p_file ) & 3 ) + write8( BYTESMASHER ); + if( ftell( p_file ) & 3 ) + write8( BYTESMASHER ); + if( ftell( p_file ) & 3 ) + write8( BYTESMASHER ); +} + +void skip8( u32 count ) +{ + fseek( fin, count, SEEK_CUR ); +// while( count ) +// { +// //read8(); +// count--; +// } +} + +void skip8f( u32 count, FILE* p_file ) +{ + fseek( p_file, count, SEEK_CUR ); +// while( count ) // this was a major slowdown! +// { +// //read8f( p_file ); +// +// count--; +// } +} + +void file_delete( char* filename ) +{ + if( file_exists( filename ) ) + remove( filename ); +} + +int file_get_byte_count( ) +{ + int a = file_byte_count; + file_byte_count = 0; + return a; +} diff --git a/tools/mmutil/files.h b/tools/mmutil/files.h new file mode 100644 index 0000000..08256c1 --- /dev/null +++ b/tools/mmutil/files.h @@ -0,0 +1,67 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> + +int file_size( char* filename ); +int file_open_read( char* filename ); +int file_open_write( char* filename ); +int file_open_write_end( char* filename ); +void file_close_read( void ); +void file_close_write( void ); +u8 read8( void ); +u16 read16( void ); +u32 read24( void ); +u32 read32( void ); +void write8( u8 p_v ); +void write16( u16 p_v ); +void write24( u32 p_v ); +void write32( u32 p_v ); +void align16( void ); +void align32( void ); +void skip8( u32 count ); +int file_seek_read( int offset, int mode ); +int file_seek_write( int offset, int mode ); +int file_tell_read( void ); +int file_tell_write( void ); + +u8 read8f( FILE* p_fin ); +u16 read16f( FILE* p_fin ); +u32 read32f( FILE* p_fin ); +void align32f( FILE* p_file ); +void skip8f( u32 count, FILE* p_file ); + +void file_delete( char* filename ); + +bool file_exists( char* filename ); + +int file_get_byte_count(); + +int file_tell_size( void ); + +#define FILE_OPEN_OKAY 0 +#define FILE_OPEN_ERROR -1 + +#endif diff --git a/tools/mmutil/gba.c b/tools/mmutil/gba.c new file mode 100644 index 0000000..34e294f --- /dev/null +++ b/tools/mmutil/gba.c @@ -0,0 +1,409 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include "defs.h" +#include "files.h" +#include "mas.h" + +const u8 GBA_ROM[] = { +0x30, 0x0, 0x0, 0xEA, 0x24, 0xFF, 0xAE, 0x51, 0x69, 0x9A, 0xA2, 0x21, 0x3D, 0x84, 0x82, 0xA, 0x84, 0xE4, 0x9, 0xAD, 0x11, 0x24, 0x8B, 0x98, 0xC0, 0x81, 0x7F, 0x21, 0xA3, 0x52, 0xBE, 0x19, 0x93, 0x9, 0xCE, +0x20, 0x10, 0x46, 0x4A, 0x4A, 0xF8, 0x27, 0x31, 0xEC, 0x58, 0xC7, 0xE8, 0x33, 0x82, 0xE3, 0xCE, 0xBF, 0x85, 0xF4, 0xDF, 0x94, 0xCE, 0x4B, 0x9, 0xC1, 0x94, 0x56, 0x8A, 0xC0, 0x13, 0x72, 0xA7, 0xFC, 0x9F, +0x84, 0x4D, 0x73, 0xA3, 0xCA, 0x9A, 0x61, 0x58, 0x97, 0xA3, 0x27, 0xFC, 0x3, 0x98, 0x76, 0x23, 0x1D, 0xC7, 0x61, 0x3, 0x4, 0xAE, 0x56, 0xBF, 0x38, 0x84, 0x0, 0x40, 0xA7, 0xE, 0xFD, 0xFF, 0x52, 0xFE, 0x3, +0x6F, 0x95, 0x30, 0xF1, 0x97, 0xFB, 0xC0, 0x85, 0x60, 0xD6, 0x80, 0x25, 0xA9, 0x63, 0xBE, 0x3, 0x1, 0x4E, 0x38, 0xE2, 0xF9, 0xA2, 0x34, 0xFF, 0xBB, 0x3E, 0x3, 0x44, 0x78, 0x0, 0x90, 0xCB, 0x88, 0x11, +0x3A, 0x94, 0x65, 0xC0, 0x7C, 0x63, 0x87, 0xF0, 0x3C, 0xAF, 0xD6, 0x25, 0xE4, 0x8B, 0x38, 0xA, 0xAC, 0x72, 0x21, 0xD4, 0xF8, 0x7, 0x4D, 0x41, 0x58, 0x4D, 0x4F, 0x44, 0x20, 0x44, 0x45, 0x4D, 0x4F, 0x0, +0x0, 0x0, 0x0, 0x0, 0x30, 0x31, 0x96, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x64, 0x0, 0x0, 0x6, 0x0, 0x0, 0xEA, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0xA0, 0xE3, 0x2, 0x14, 0xA0, 0xE3, 0xF8, 0x7, +0xB0, 0xE8, 0xF8, 0x7, 0xA1, 0xE8, 0xA1, 0x29, 0xB0, 0xE1, 0xFB, 0xFF, 0xFF, 0x3A, 0xFE, 0x0, 0xA0, 0xE3, 0x0, 0x0, 0x1, 0xEF, 0x8, 0x0, 0x9F, 0xE5, 0x8, 0x10, 0x9F, 0xE5, 0x0, 0x0, 0x12, 0xEF, 0x4, 0xF0, +0x9F, 0xE5, 0x4, 0x1, 0x0, 0x2, 0x0, 0x0, 0x0, 0x3, 0x44, 0x18, 0x0, 0x3, 0x10, 0xF2, 0x3A, 0x0, 0x0, 0xC0, 0x7E, 0xC0, 0x7A, 0xA0, 0x76, 0x80, 0x72, 0x0, 0x60, 0x6E, 0x60, 0x6A, 0x40, 0x66, 0x20, 0x62, +0x0, 0x20, 0x5E, 0x0, 0x5A, 0x0, 0x35, 0x3, 0x0, 0x0, 0x50, 0x13, 0x11, 0x11, 0x15, 0x13, 0x31, 0x55, 0x0, 0x15, 0x13, 0x51, 0x0, 0x15, 0x13, 0x52, 0x0, 0x0, 0x35, 0x34, 0x53, 0x0, 0x50, 0x55, 0x5, 0x0, +0x40, 0x0, 0x0, 0x1, 0x1F, 0x0, 0xFF, 0x7F, 0x9C, 0x73, 0x0, 0x39, 0x67, 0xB5, 0x56, 0x52, 0x4A, 0xFF, 0x7F, 0xE0, 0x20, 0x12, 0xF0, 0x1, 0x0, 0x29, 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x2, 0x0, 0x18, 0x0, +0x36, 0x24, 0x24, 0x20, 0x37, 0x36, 0x20, 0x36, 0x7F, 0x0, 0x1, 0x36, 0x0, 0x8, 0x3E, 0xB, 0x0, 0x3E, 0x68, 0x3F, 0x8, 0x0, 0x0, 0x66, 0x35, 0x0, 0x1B, 0x6C, 0x56, 0x33, 0x0, 0x1C, 0x32, 0x1C, 0x0, 0x1E, +0x73, 0x33, 0x5E, 0x0, 0xC, 0x8, 0x4, 0x80, 0x30, 0x37, 0xC, 0x6, 0x6, 0x6, 0xC, 0x18, 0x0, 0xB0, 0x0, 0x3, 0x18, 0x0, 0xB, 0x0, 0x27, 0x3C, 0xFF, 0x3C, 0x66, 0x83, 0x0, 0x7A, 0xC, 0xC, 0x3F, 0xC, 0xC, +0x40, 0x67, 0x30, 0x2C, 0x41, 0x3F, 0x70, 0x75, 0xC, 0x0, 0x40, 0x60, 0x30, 0x0, 0x3A, 0x0, 0x3, 0x0, 0x3E, 0x73, 0x7B, 0x6F, 0x67, 0x67, 0x4, 0x3E, 0x0, 0x18, 0x1C, 0x1E, 0x0, 0x40, 0x7E, 0x0, 0x1, 0x3E, +0x63, 0x60, 0x38, 0xE, 0x63, 0x7F, 0x10, 0x7, 0x0, 0x3C, 0x60, 0x63, 0x3E, 0x0, 0x38, 0x3C, 0x36, 0x0, 0x33, 0x7F, 0x30, 0x78, 0x0, 0x7F, 0x3, 0x3F, 0x41, 0x60, 0x10, 0xF, 0x3E, 0x63, 0x3, 0x3F, 0x63, +0x0, 0x17, 0x37, 0x7F, 0x63, 0x0, 0x3F, 0x0, 0x60, 0x3E, 0x0, 0xC, 0x10, 0xF, 0x0, 0x7, 0x72, 0x7E, 0x10, 0x2F, 0x0, 0x5A, 0x80, 0x3, 0x8, 0x4, 0x10, 0x65, 0xC, 0x2E, 0x18, 0x30, 0x1, 0xB, 0x7E, 0x20, +0x2, 0x10, 0xC, 0x10, 0xA7, 0x1E, 0x60, 0x33, 0x0, 0x7F, 0x0, 0x87, 0x3E, 0x41, 0x79, 0x65, 0x79, 0x40, 0x1, 0x20, 0x3F, 0x7F, 0x63, 0x63, 0x63, 0x0, 0x3F, 0x2, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x10, +0x67, 0x3, 0x70, 0x3, 0x0, 0x7F, 0x0, 0xF, 0x0, 0x1, 0x3F, 0x0, 0x7F, 0x46, 0x4, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x30, 0x7, 0x6, 0xF, 0x83, 0x10, 0x77, 0x3, 0x73, 0x63, 0x7E, 0x0, 0x0, 0x33, 0x20, 0x37, +0xC0, 0x1, 0x3D, 0x1, 0x0, 0x3C, 0x0, 0x78, 0x30, 0x30, 0x30, 0x0, 0x33, 0x33, 0x1E, 0x0, 0x67, 0x66, 0x36, 0x1E, 0x4, 0x36, 0x66, 0x67, 0x0, 0xF, 0x1, 0x1E, 0x46, 0x66, 0x1, 0x7F, 0x0, 0x41, 0x63, 0x77, +0x7F, 0x6B, 0x0, 0x5F, 0x7, 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x0, 0x67, 0x0, 0xB7, 0x0, 0x6E, 0x90, 0x20, 0x5F, 0x3E, 0x6, 0x30, 0x4F, 0x63, 0x6B, 0x7B, 0x3E, 0x54, 0x60, 0x30, 0x7F, 0x67, 0x10, 0xE7, 0x3E, +0x10, 0xFF, 0x7E, 0x5A, 0x78, 0x5A, 0x20, 0x57, 0x20, 0x2E, 0x1, 0xF, 0x10, 0x36, 0x36, 0x1C, 0x8, 0x81, 0x0, 0x77, 0x6B, 0x7F, 0x77, 0x63, 0x41, 0x0, 0x0, 0xC, 0x6, 0x1C, 0x1C, 0x36, 0x63, 0x0, 0x0, +0xA6, 0x1, 0xC0, 0x3C, 0x8A, 0x1, 0x17, 0x31, 0x18, 0x4C, 0x0, 0x6F, 0x1E, 0x1, 0x96, 0x6, 0x8, 0x6, 0x1E, 0x0, 0x3, 0x10, 0xFD, 0x60, 0x40, 0x0, 0x83, 0x11, 0x5D, 0x18, 0x18, 0x1E, 0x0, 0x8, 0x10, 0x2C, +0x71, 0xFE, 0x18, 0xFF, 0xC, 0x4, 0x1, 0xDB, 0x22, 0x29, 0x1E, 0x30, 0x3E, 0x3, 0x33, 0x6E, 0x0, 0x7, 0x6, 0x6, 0x0, 0xFF, 0x1, 0x47, 0xDC, 0x11, 0x69, 0x11, 0x7F, 0x30, 0x0, 0x16, 0x0, 0x17, 0x10, 0xF, +0x7F, 0x3, 0x81, 0x1, 0x8F, 0x6C, 0xC, 0x1E, 0xC, 0xC, 0x1E, 0x2, 0x5B, 0x0, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1E, 0x7, 0x6, 0x22, 0x36, 0x6E, 0x10, 0xAF, 0x18, 0x0, 0x1C, 0x20, 0xFF, 0x0, 0x5B, 0x30, 0x10, +0x32, 0x33, 0x0, 0x17, 0x11, 0x0, 0x67, 0x20, 0x15, 0x20, 0x17, 0x2, 0x0, 0x33, 0x7F, 0x6B, 0x6B, 0x6B, 0x2, 0x93, 0x3B, 0xF5, 0x11, 0x51, 0x20, 0x5F, 0x11, 0xC7, 0x20, 0xF, 0x3E, 0x1, 0x50, 0x0, 0x0, +0x66, 0x47, 0x3E, 0x1, 0xE8, 0x0, 0x7B, 0x6E, 0x11, 0xF, 0x0, 0x7F, 0x1, 0x0, 0x12, 0x3E, 0x0, 0x8, 0x12, 0x46, 0x2C, 0x18, 0x10, 0x3F, 0x33, 0xE1, 0x30, 0x87, 0x30, 0xFF, 0x0, 0x7, 0x6B, 0x6B, 0x7F, +0x36, 0x10, 0xF, 0x62, 0x36, 0x30, 0xD2, 0x0, 0x1F, 0x3E, 0x30, 0x1F, 0x2, 0x66, 0x19, 0x4, 0xC, 0x26, 0x3F, 0x0, 0x70, 0x2, 0x8D, 0x18, 0x18, 0x31, 0x70, 0x0, 0x2, 0x95, 0x20, 0x3, 0x7, 0xC, 0xC, 0x2, +0x2F, 0xF, 0x7, 0x0, 0x6E, 0x3B, 0x42, 0xFB, 0x11, 0x8, 0x2, 0x67, 0xF3, 0xA, 0xBF, 0x60, 0x8, 0x33, 0x40, 0x3, 0xF0, 0x1, 0x40, 0x8D, 0x10, 0x91, 0x80, 0x27, 0xF0, 0x3, 0x9C, 0x0, 0xF4, 0x22, 0x22, 0xF0, +0x1, 0x90, 0x5, 0x90, 0x59, 0x10, 0x11, 0x3F, 0x11, 0x1, 0xF0, 0x3, 0xF0, 0x3, 0x90, 0x7, 0x50, 0x38, 0xF0, 0x3, 0x0, 0xF, 0x9F, 0x40, 0xB6, 0x11, 0x11, 0xF0, 0x1, 0x10, 0xD, 0x50, 0x73, 0x0, 0x19, 0xF0, +0x3, 0x80, 0x40, 0x5B, 0x38, 0x47, 0x10, 0x47, 0x8, 0x47, 0xC0, 0x0, 0x46, 0x0, 0xA0, 0x0, 0x47, 0x0, 0x40, 0x2D, 0x0, 0xE9, 0xF0, 0x7, 0x2D, 0xE9, 0x1, 0x0, 0x8F, 0x0, 0xE2, 0x10, 0xFF, 0x2F, 0xE1, 0x28, +0x48, 0x0, 0x0, 0x68, 0x80, 0x46, 0x81, 0x79, 0x0, 0x29, 0x1, 0x0, 0xD1, 0x26, 0x49, 0x8F, 0x46, 0x41, 0x7F, 0x0, 0x0, 0x29, 0x5, 0xD1, 0x0, 0x78, 0x0, 0x28, 0x2, 0x0, 0xD1, 0x23, 0x4A, 0xFF, 0xF7, 0xE2, +0xFF, 0x40, 0x0, 0x46, 0x30, 0x24, 0x4, 0x59, 0x21, 0x4F, 0x3F, 0x1, 0x68, 0x0, 0x20, 0x82, 0x46, 0x40, 0x46, 0x10, 0x1B, 0x1, 0xA, 0xD1, 0x64, 0x8, 0x2, 0xD3, 0x1D, 0x0, 0x1F, 0x0, 0xD2, 0xFF, 0x1, 0x20, +0x82, 0x44, 0x28, 0x37, 0x2, 0x0, 0x2C, 0xF5, 0xD1, 0x9, 0xE0, 0x10, 0x15, 0x19, 0xA0, 0x0, 0x35, 0xC7, 0x80, 0x15, 0x16, 0x4E, 0x36, 0x68, 0x0, 0x0, 0x24, 0x70, 0x7C, 0x0, 0x28, 0xE, 0xD0, 0x14, 0x0, +0x48, 0x0, 0x78, 0xF1, 0x7D, 0x89, 0x9, 0x81, 0x0, 0x42, 0x8, 0xD1, 0x12, 0x49, 0x30, 0x7D, 0x8, 0x0, 0x72, 0x0, 0x20, 0x88, 0x81, 0x35, 0x68, 0x0, 0x0, 0xF0, 0x8D, 0xF8, 0xFF, 0xE7, 0xF0, 0x7D, 0x8, +0x0, 0x21, 0x88, 0x43, 0xF0, 0x75, 0x1C, 0x36, 0x1, 0x20, 0x34, 0xB, 0x0, 0x97, 0x84, 0x42, 0xE3, 0xD1, 0xA, 0x80, 0x0, 0x93, 0x38, 0x5B, 0x0, 0x3, 0x97, 0x27, 0x0, 0x2, 0x3, 0x44, 0xA, 0x0, 0x3, 0x3C, +0x0, 0xB, 0x30, 0x0, 0xB, 0x0, 0x3, 0x70, 0xD, 0x0, 0x3, 0x50, 0xAA, 0x0, 0x17, 0x4D, 0x0, 0x1B, 0x28, 0x0, 0x1F, 0x5C, 0x0, 0x23, 0x15, 0x80, 0x0, 0x23, 0x10, 0xB5, 0x78, 0x7A, 0x1, 0x38, 0x51, 0x0, +0xD3, 0x0, 0xF0, 0x56, 0xF8, 0x0, 0x2E, 0x48, 0x40, 0xD0, 0x10, 0xD, 0x41, 0x46, 0x4A, 0x69, 0x89, 0x68, 0x1, 0x80, 0x0, 0x8, 0x58, 0x80, 0x18, 0x39, 0x0, 0x7D, 0x0, 0x2C, 0xD0, 0xC1, 0x78, 0x89, 0x7, +0x89, 0xF, 0x0, 0x49, 0x0, 0x79, 0x44, 0x8F, 0x46, 0x1C, 0xE0, 0x0, 0x1, 0xE0, 0x8, 0xE0, 0xF, 0xE0, 0xB9, 0x7D, 0x0, 0x49, 0x0, 0x8, 0x31, 0x41, 0x5C, 0xFA, 0x79, 0x5, 0x91, 0x42, 0xC, 0xD0, 0x11, 0x20, +0xF, 0x9, 0x0, 0xF, 0x0, 0x72, 0x7D, 0x91, 0x42, 0x4, 0xD0, 0x9, 0xE0, 0x0, 0x79, 0x7A, 0xB2, 0x7C, 0x91, 0x42, 0x5, 0xD1, 0x40, 0xC1, 0x1, 0x2B, 0xB, 0xD0, 0x1, 0x29, 0xD, 0xD0, 0x30, 0x13, 0xE0, 0x10, +0x4D, 0x30, 0x45, 0x2, 0xE0, 0x2, 0xE0, 0x0, 0x4, 0xE0, 0xA, 0xE0, 0x14, 0xE0, 0x2, 0x21, 0x0, 0x71, 0x74, 0xC, 0xE0, 0xF1, 0x7D, 0x1, 0x22, 0xA, 0x91, 0x43, 0xF1, 0x75, 0x10, 0xD, 0x5, 0x0, 0xD, 0x2, +0x20, 0x22, 0x11, 0x40, 0xD, 0x34, 0x1C, 0x3, 0x49, 0xFF, 0x0, 0xF7, 0x37, 0xFF, 0x38, 0x70, 0x10, 0xBC, 0x8, 0x0, 0xBC, 0x18, 0x47, 0x0, 0x0, 0xD0, 0x9, 0x0, 0x0, 0x3, 0x38, 0x78, 0xFF, 0x28, 0x5, 0xDA, +0x4, 0x80, 0x1, 0x2B, 0x1C, 0x21, 0x48, 0x43, 0x36, 0x18, 0x70, 0x14, 0x47, 0x0, 0x26, 0x0, 0x3, 0x0, 0x10, 0xE3, 0x0, 0xB5, 0x80, 0x11, 0x19, 0x8, 0x42, 0x1, 0xD0, 0x0, 0xBD, 0x0, 0x0, 0xB5, 0xB0, 0x7C, +0x1, 0x38, 0x0, 0xD2, 0xB2, 0x40, 0xE0, 0x90, 0xD5, 0x1, 0x1C, 0x4A, 0x79, 0xC, 0x31, 0x0, 0x52, 0x8, 0x2B, 0xD3, 0xF3, 0x7D, 0x9B, 0x9, 0x0, 0x2, 0xD2, 0x8, 0x78, 0x9, 0x18, 0x25, 0xE0, 0x0, 0x6, 0xB4, +0xF0, 0x88, 0xA, 0x1C, 0x31, 0x7E, 0x0, 0x0, 0xF0, 0x78, 0xF9, 0x31, 0x76, 0xF0, 0x80, 0x0, 0x19, 0x1C, 0x1, 0x2A, 0x8, 0xD1, 0xF0, 0x7D, 0x0, 0x43, 0x46, 0x1B, 0x7E, 0x1B, 0x9, 0x10, 0x23, 0x4, 0x0, +0xD2, 0x12, 0x23, 0x18, 0x1, 0x6F, 0x1, 0x2A, 0x10, 0x6, 0xDB, 0xF0, 0x0, 0xAF, 0x10, 0x42, 0x2, 0xD1, 0x10, 0x2, 0x22, 0x10, 0x1, 0x81, 0xA1, 0x48, 0x2, 0x7A, 0x0, 0x4A, 0x43, 0x12, 0xB, 0x2, 0x72, 0x6, +0xBC, 0x82, 0x10, 0x4B, 0xE, 0xE0, 0xF0, 0x7D, 0x10, 0x0, 0x2B, 0x1, 0x2C, 0x23, 0x18, 0x1, 0xB9, 0x2, 0x20, 0x35, 0x2, 0x9, 0x7E, 0x0, 0x0, 0x9, 0x1, 0xD3, 0x0, 0x20, 0xB0, 0x80, 0x52, 0x0, 0x8, 0x10, +0xD3, 0x6, 0xB4, 0x30, 0x89, 0xA, 0x20, 0x1C, 0x71, 0x0, 0x6D, 0x41, 0xF9, 0x71, 0x76, 0x30, 0x0, 0x81, 0x19, 0x1C, 0x8F, 0x48, 0xC, 0x23, 0xC2, 0x0, 0x5E, 0x9, 0x9, 0x80, 0x39, 0x52, 0x18, 0xC2, 0x0, +0x52, 0x6, 0xBC, 0x52, 0x8, 0x1A, 0xD3, 0x88, 0x0, 0x79, 0x0, 0x28, 0x17, 0xD1, 0x6, 0xB4, 0x70, 0xA0, 0x0, 0x2B, 0xB1, 0x0, 0x99, 0x2B, 0xF9, 0xB1, 0x76, 0x70, 0x80, 0x0, 0x2B, 0xC9, 0x8, 0xFF, 0x39, +0x28, 0x1C, 0x1, 0x8, 0x39, 0x3, 0xD4, 0x83, 0x2, 0x75, 0xA7, 0xFE, 0x3, 0x8, 0xE0, 0x49, 0x42, 0x81, 0x2, 0x7F, 0xA2, 0xFE, 0x5, 0x2, 0x1C, 0x6, 0xBC, 0xF0, 0x7D, 0x2, 0x0, 0xFF, 0xD, 0x60, 0xD0, 0x10, +0xFB, 0x91, 0xCD, 0x40, 0x78, 0xB1, 0x88, 0x9, 0x0, 0x1A, 0x0, 0xD2, 0x0, 0x21, 0xB1, 0x80, 0x70, 0x5, 0x7D, 0x1, 0x38, 0x52, 0xD3, 0x11, 0xEB, 0xC9, 0x51, 0x15, 0x0, 0x89, 0x0, 0x29, 0x1E, 0xD0, 0xB2, +0x89, 0x52, 0x0, 0x18, 0xD1, 0xB, 0x0, 0xD0, 0x6F, 0x4A, 0xB2, 0x0, 0x81, 0x41, 0x79, 0x51, 0x43, 0xB3, 0x7B, 0x82, 0x0, 0x79, 0x9B, 0x18, 0x1B, 0x6, 0x1B, 0xE, 0xB3, 0x0, 0x73, 0x6B, 0x4A, 0xD2, 0x56, +0x4A, 0x43, 0xD2, 0x0, 0x15, 0x5, 0xD4, 0x11, 0x1C, 0x28, 0x1C, 0x68, 0x80, 0x2, 0xEF, 0x6A, 0xFE, 0x4, 0xE0, 0x51, 0x42, 0x28, 0x28, 0x1C, 0x66, 0x2, 0xFB, 0x64, 0x0, 0x7B, 0x10, 0xB4, 0x10, 0x8, 0x20, +0x44, 0x43, 0x64, 0x3, 0x25, 0x24, 0x18, 0xF0, 0x26, 0x7D, 0x4, 0x1, 0x85, 0x20, 0xD0, 0x12, 0xA3, 0x10, 0x6D, 0x1B, 0x80, 0xA0, 0x6D, 0x43, 0x89, 0x59, 0x1C, 0x49, 0xC, 0x3, 0x0, 0xD3, 0xC, 0x30, 0x10, +0x30, 0x20, 0x60, 0x9, 0x0, 0xE0, 0x58, 0x4A, 0x12, 0x68, 0x11, 0x1C, 0xC, 0x0, 0x31, 0x9B, 0x0, 0xC9, 0x58, 0x8, 0x31, 0x88, 0x40, 0x18, 0x10, 0x15, 0x4B, 0x49, 0x49, 0x7A, 0x9, 0x5, 0x28, 0x61, 0x60, +0x10, 0xAB, 0x31, 0xB0, 0xAB, 0xB4, 0x41, 0x46, 0x0, 0x9, 0x7E, 0xC9, 0x8, 0x11, 0xD3, 0x40, 0x88, 0x0, 0x80, 0x0, 0x29, 0xA, 0x41, 0x43, 0x9, 0xA, 0x41, 0x48, 0x3, 0x2D, 0x0, 0x28, 0x3, 0xD1, 0x47, 0x3, +0xA3, 0x0, 0x41, 0x43, 0x89, 0xA, 0x46, 0x48, 0x48, 0x43, 0x0, 0x0, 0xC, 0xE0, 0x60, 0xF, 0xE0, 0x45, 0x48, 0x0, 0x29, 0x1C, 0xC, 0xD0, 0x6, 0xDF, 0x40, 0x49, 0x0, 0x9, 0x78, 0x0, 0x29, 0x3, 0xD1, 0x3F, +0x49, 0x0, 0x9, 0x68, 0x48, 0x43, 0x80, 0xA, 0x3E, 0x49, 0x85, 0x30, 0x21, 0x1, 0xBC, 0xC3, 0x79, 0x12, 0x27, 0x1, 0x1, 0x19, 0x40, 0x1D, 0xA2, 0x29, 0x0, 0x78, 0x43, 0x43, 0x29, 0x49, 0x1, 0x8, 0x7A, +0x43, 0x43, 0x41, 0x46, 0x8, 0x1, 0xBF, 0x0, 0x8, 0x79, 0x0, 0xD3, 0x40, 0x0, 0x43, 0x43, 0x8, 0x9B, 0xA, 0xB0, 0x88, 0x10, 0x5, 0x40, 0x46, 0x34, 0x0, 0x21, 0x40, 0x5A, 0x43, 0x43, 0xD9, 0xC, 0xFF, 0x0, +0x29, 0x0, 0xDB, 0xFF, 0x21, 0x31, 0x74, 0x0, 0x0, 0x29, 0x16, 0xD1, 0xF3, 0x7D, 0x10, 0x22, 0x13, 0x8, 0x42, 0x12, 0xD0, 0x1, 0x0, 0x5, 0xF, 0xD1, 0x26, 0x0, 0x48, 0x20, 0x60, 0x73, 0x7C, 0x3, 0x2B, +0x7, 0x0, 0xD1, 0xB1, 0x7D, 0x28, 0x23, 0x59, 0x43, 0x23, 0x80, 0x4, 0x43, 0x40, 0x18, 0xFF, 0x21, 0x1, 0x70, 0x0, 0x80, 0x2, 0xFB, 0x1F, 0xE0, 0x21, 0x72, 0x20, 0x68, 0xC0, 0x15, 0x17, 0xF, 0xD0, 0x90, +0x23, 0x1A, 0x60, 0x23, 0x17, 0x0, 0x3D, 0x80, 0x10, 0x27, 0xB, 0xE0, 0x7, 0x49, 0xC, 0x23, 0xC8, 0x0, 0x5E, 0xF1, 0x7C, 0x9, 0x18, 0x0, 0x29, 0x0, 0x10, 0xDA, 0x0, 0x21, 0x0, 0x71, 0xDD, 0xFF, 0x21, +0x61, 0x5, 0x72, 0x10, 0xBC, 0x1, 0xBC, 0x4, 0xA9, 0x0, 0x13, 0xD7, 0x4, 0x73, 0x30, 0x0, 0x3, 0x3F, 0x0, 0x3, 0x0, 0x80, 0x85, 0x3, 0x27, 0x37, 0x0, 0x3, 0x69, 0x0, 0xF, 0x35, 0x0, 0x13, 0x2, 0x8, 0x5C, +0x0, 0x3, 0xB4, 0x5A, 0x33, 0xFF, 0x48, 0x80, 0x4, 0x1F, 0x80, 0x42, 0x0, 0x0, 0xEA, 0xF0, 0x61, 0x50, 0x3, 0x9, 0x30, 0x80, 0x24, 0x23, 0xB4, 0x8C, 0x0, 0x8, 0x0, 0x34, 0xA4, 0x18, 0x63, 0x88, 0x5B, +0x6, 0xDB, 0x0, 0xC, 0x0, 0x28, 0x14, 0xD1, 0x95, 0x78, 0xA9, 0x80, 0x2, 0xDF, 0x51, 0x78, 0x2, 0x22, 0x1A, 0xE0, 0xF5, 0x1, 0x7D, 0x6D, 0x8, 0x5, 0xD3, 0x15, 0x79, 0x10, 0x11, 0x0, 0xD1, 0x78, 0x0, 0x22, +0x11, 0xE0, 0x55, 0x79, 0x4, 0x1, 0x3D, 0xA9, 0x42, 0x6, 0x2, 0xFF, 0xB, 0xE0, 0x0, 0x0, 0x25, 0x65, 0x5F, 0x45, 0x43, 0xED, 0x10, 0x0, 0x5B, 0x19, 0x1, 0x30, 0x65, 0x88, 0xED, 0x9, 0x0, 0xA8, 0x42, 0x1, +0xD1, 0x0, 0x20, 0x1, 0x31, 0x9, 0x30, 0xBC, 0x70, 0x47, 0x14, 0x4B, 0x9, 0x69, 0x34, 0x4B, 0x40, 0x70, 0x5, 0x53, 0x70, 0x0, 0x2D, 0xE9, 0x4, 0x56, 0x0, 0x9F, 0xE5, 0x0, 0x50, 0x95, 0xE5, 0x0, 0x16, +0x80, 0x0, 0x7, 0x10, 0x91, 0xE5, 0x10, 0x10, 0x81, 0xE2, 0x0, 0x0, 0x0, 0xA0, 0xE3, 0x2, 0x21, 0xA0, 0xE3, 0x22, 0xFF, 0x30, 0x0, 0x7, 0x60, 0xA0, 0xE3, 0x0, 0x98, 0xEA, 0x40, 0x1C, 0x20, 0x17, 0x55, +0xE3, 0xB, 0x0, 0x0, 0xA, 0x0, 0x1, 0x0, 0x80, 0xE2, 0xA5, 0x50, 0xB0, 0xE1, 0x0, 0xF9, 0xFF, 0xFF, 0x3A, 0xBC, 0x41, 0xD1, 0xE0, 0x0, 0x24, 0x4, 0x56, 0xE1, 0xF7, 0xFF, 0xFF, 0xBA, 0x80, 0x9, 0xF1, 0xCA, +0x84, 0xB, 0x52, 0xE1, 0xF4, 0xFF, 0x0, 0xFF, 0x9A, 0x0, 0x30, 0xA0, 0xE1, 0x84, 0x2B, 0x0, 0xB0, 0xE1, 0xF1, 0xFF, 0xFF, 0xEA, 0x3, 0x0, 0x1, 0xA0, 0xE1, 0x70, 0x0, 0xBD, 0xE8, 0x1E, 0x5, 0xB3, 0x0, +0x0, 0x1C, 0x2D, 0xE9, 0x14, 0xB0, 0x98, 0xE5, 0x0, 0x1, 0xC0, 0xDB, 0xE5, 0x18, 0xB0, 0xD8, 0xE5, 0x2, 0x1, 0xA0, 0xA0, 0xE3, 0x88, 0x5, 0x0, 0x83, 0x90, 0x1, 0x90, 0xE5, 0x24, 0x70, 0x98, 0xE5, 0x80, +0x0, 0xB, 0x10, 0x4, 0x70, 0x80, 0x0, 0x8B, 0xA0, 0xE3, 0x0, 0x50, 0x0, 0xA0, 0xE3, 0x1, 0x30, 0xD7, 0xE4, 0x83, 0x3C, 0x10, 0xB0, 0xE1, 0x27, 0x0, 0x77, 0xA3, 0x3C, 0x6A, 0xE0, 0x4, 0x1A, 0x13, 0x81, +0xE1, 0x28, 0x0, 0x9F, 0x93, 0x90, 0x0, 0x26, 0xE0, 0x1, 0x20, 0xD7, 0x24, 0x1, 0x20, 0x0, 0xC6, 0x25, 0x1, 0x20, 0xD6, 0x35, 0x1, 0x0, 0x30, 0x12, 0xE3, 0xA, 0x71, 0x0, 0x9B, 0xD7, 0xE4, 0xFE, 0x0, 0x2, +0x50, 0xE3, 0x16, 0x0, 0xC6, 0xB5, 0x6, 0x9C, 0xBA, 0x0, 0x80, 0x50, 0x85, 0x3, 0x40, 0x50, 0x85, 0xC3, 0x60, 0x2, 0x0, 0x1F, 0x30, 0xBB, 0xD7, 0xE4, 0xC0, 0x0, 0x15, 0x41, 0xE3, 0xA, 0x51, 0x1A, 0xC, +0x0, 0x50, 0xE1, 0x0, 0xEB, 0x4, 0xC3, 0x9, 0x30, 0xD6, 0xE5, 0xA, 0xC5, 0xE1, 0x2, 0x80, 0x0, 0xDB, 0x2B, 0x33, 0xB0, 0xE1, 0x1, 0x50, 0x85, 0x0, 0x23, 0x10, 0x50, 0x85, 0xE3, 0x9, 0x0, 0xC6, 0x4, 0xE5, +0xA2, 0x1, 0x1A, 0xE1, 0x0, 0x53, 0x24, 0x3, 0x1C, 0x0, 0xC6, 0x25, 0x1, 0xA0, 0x20, 0x5F, 0x10, 0x93, 0x3, 0x4, 0x0, 0x80, 0xE1, 0xB4, 0x0, 0xC6, 0xE1, 0x22, 0x52, 0x1, 0x85, 0xE1, 0x8, 0x50, 0xC6, 0xE5, +0xD3, 0x0, 0xE7, 0x0, 0x24, 0x70, 0x88, 0xE5, 0x30, 0x10, 0x88, 0xE5, 0x30, 0x0, 0x1C, 0x40, 0xEB, 0x6, 0xAF, 0x8, 0x50, 0xD7, 0xE5, 0x66, 0x1, 0x0, 0x6F, 0x1, 0xE2, 0xA, 0x8, 0x0, 0x77, 0x10, 0xA3, 0xB4, +0x0, 0x0, 0xD7, 0xE1, 0xFF, 0x10, 0x0, 0xE2, 0x10, 0xA1, 0x0, 0x87, 0x1C, 0x0, 0x87, 0x7, 0x0, 0x51, 0xE3, 0x8, 0x80, 0x65, 0xA, 0x10, 0xF, 0x8, 0x69, 0x1A, 0x4, 0x0, 0x9F, 0x16, 0x1, 0x67, 0x0, 0x18, +0x0, 0xD8, 0xE5, 0x20, 0x2, 0xB0, 0xE1, 0x9, 0x3, 0x0, 0xD7, 0xE5, 0xA, 0xED, 0x2A, 0xC1, 0x0, 0xD7, 0x56, 0x10, 0x0, 0xD3, 0xCA, 0x0, 0xDF, 0xE, 0x1, 0x6B, 0x0, 0xAF, 0xEA, 0x65, 0xF0, 0x0, 0xEB, 0xB, +0x68, 0xAA, 0xA, 0x2, 0x42, 0x0, 0x0, 0x27, 0x52, 0xFF, 0x0, 0xFB, 0x7, 0x0, 0xF, 0x30, 0x64, 0x1, 0xD7, 0x60, 0x10, 0x96, 0xE5, 0x1C, 0x1, 0x47, 0x90, 0x61, 0x26, 0xE0, 0x0, 0xAC, 0x0, 0x0, 0xEB, 0x1, +0x50, 0xC5, 0xE3, 0x8, 0x8, 0x50, 0xC7, 0xE5, 0x8, 0xA4, 0xEA, 0x1C, 0x24, 0x1, 0x9F, 0xE5, 0xF, 0xE0, 0xA0, 0xE1, 0x12, 0x11, 0x93, 0xC5, 0x40, 0x37, 0x9, 0x98, 0xAA, 0xF8, 0x63, 0xB0, 0x37, 0x9E, 0x0, +0x37, 0x14, 0x15, 0x0, 0xD6, 0x0, 0xC3, 0x50, 0x0, 0xAF, 0x0, 0x3A, 0x0, 0x18, 0x10, 0xD8, 0xE5, 0xA1, 0x11, 0xB0, 0xE1, 0x80, 0x0, 0x63, 0x2A, 0x14, 0x30, 0x98, 0xE5, 0xC, 0x10, 0x2, 0x98, 0xE5, 0x0, +0x1, 0x91, 0xE7, 0x2, 0xE4, 0xE0, 0x0, 0xB2, 0x10, 0xD0, 0xE1, 0x1, 0x11, 0xA0, 0xE1, 0x60, 0xBA, 0x10, 0x6B, 0x2, 0xD2, 0xBC, 0x13, 0x9F, 0xE5, 0x2, 0x82, 0x0, 0x1B, 0x10, 0x0, 0x87, 0xE5, 0x17, 0x0, +0x43, 0x4, 0xE, 0x0, 0x80, 0xE3, 0x17, 0x1, 0x53, 0xB, 0xA5, 0x60, 0xAB, 0x4D, 0xAC, 0x0, 0xBB, 0x84, 0xC0, 0x73, 0x2, 0x1, 0x9F, 0x9, 0xE1, 0xA, 0x9, 0xC1, 0x0, 0xF7, 0x50, 0x77, 0x14, 0x20, 0x98, 0xE5, +0x8, 0x40, 0x6B, 0x40, 0x2, 0x0, 0x6B, 0x4, 0x10, 0x90, 0xE5, 0x14, 0x20, 0x0, 0xD7, 0xE5, 0xC0, 0x20, 0xC2, 0xE3, 0x1, 0x23, 0x0, 0x82, 0xE1, 0x14, 0x20, 0xC7, 0xE5, 0x17, 0x20, 0x10, 0xD6, 0xE5, 0x20, +0x0, 0xF, 0x2, 0xB, 0x11, 0xE3, 0x0, 0x20, 0x20, 0x82, 0x13, 0x17, 0x20, 0xC6, 0xE5, 0x0, 0x81, 0x14, 0xB0, 0xE1, 0x21, 0x1C, 0xA0, 0x21, 0xF, 0x2, 0x10, 0xC7, 0x25, 0x50, 0xC7, 0x1, 0x1F, 0x20, 0x4F, +0x50, 0xBB, 0x0, 0xB2, 0x10, 0x90, 0xE1, 0xE, 0x10, 0xC7, 0xE5, 0x2B, 0x81, 0x18, 0x20, 0x2B, 0xE1, 0x10, 0x2B, 0x3, 0x2, 0x23, 0x1, 0x6B, 0x85, 0x21, 0x83, 0x8, 0x0, 0x10, 0xE3, 0x8, 0xE8, 0xA, 0x10, +0x97, 0xB0, 0x22, 0xFF, 0xB, 0x2, 0x9B, 0x12, 0x9F, 0x20, 0xA0, 0xE3, 0x4, 0x20, 0xC0, 0x86, 0x0, 0x4F, 0x8C, 0xE8, 0xB8, 0x11, 0xC6, 0x19, 0xE1, 0x1A, 0x10, 0x0, 0xDB, 0x0, 0x47, 0x17, 0x10, 0x1, 0x2F, +0x0, 0x10, 0x81, 0xE3, 0x12, 0x10, 0xC1, 0xE3, 0x17, 0xB6, 0x0, 0x13, 0x40, 0x41, 0xF7, 0x30, 0x17, 0xC1, 0x1, 0xE3, 0x30, 0x53, 0x2, 0x16, 0x10, 0x81, 0x13, 0x10, 0x1F, 0x80, 0x2, 0x8F, 0x3, 0x73, 0x13, +0xD, 0xE, 0x0, 0xC7, 0x15, 0x51, 0xA3, 0xD, 0x3C, 0xEA, 0x18, 0xEF, 0xC4, 0x51, 0xD3, 0x4, 0x1C, 0xAA, 0x5C, 0x62, 0xB1, 0xD3, 0x0, 0x60, 0x0, 0xA0, 0xA3, 0x10, 0x50, 0x97, 0xE5, 0x4C, 0x12, 0xC1, 0x3, +0xC3, 0x3, 0xB3, 0x9, 0x0, 0xC1, 0xE5, 0xA, 0x0, 0x3, 0x54, 0xC, 0x0, 0x7, 0xB, 0x0, 0xB, 0x8, 0x22, 0x37, 0x10, 0xE3, 0x8, 0x38, 0x12, 0x9F, 0x15, 0x1, 0xEB, 0x11, 0x11, 0xFF, 0x34, 0x2F, 0x11, 0x10, +0x13, 0x10, 0xCF, 0x28, 0x80, 0x13, 0x0, 0x0, 0x24, 0x56, 0xE3, 0xA, 0x8, 0xA, 0xBE, 0x42, 0x97, 0x20, 0x4, 0x0, 0xA0, 0xE1, 0x91, 0x0, 0x0, 0xE0, 0xA0, 0x2, 0x10, 0xA0, 0xE1, 0x14, 0x3, 0x3, 0xEC, 0x11, +0x9F, 0xE5, 0x0, 0xDA, 0x20, 0xD1, 0xE1, 0x82, 0x1, 0x90, 0xE0, 0x90, 0x4, 0x1B, 0x43, 0x81, 0x3, 0x5F, 0x80, 0x0, 0xA0, 0x23, 0x5A, 0x8, 0x20, 0x67, 0xD1, 0x0, 0xAB, 0x20, 0x9F, 0xA, 0x11, 0xE3, 0x8, +0xCA, 0x41, 0xE3, 0x2, 0x9F, 0xEA, 0x2, 0x2, 0xB7, 0x13, 0x3, 0x43, 0x10, 0x28, 0x0, 0x97, 0x0, 0xCF, 0x86, 0x20, 0xA3, 0xBC, 0x0, 0xC1, 0x50, 0xE1, 0x90, 0x27, 0x10, 0x4, 0x83, 0x0, 0x40, 0xD7, 0xE5, +0x72, 0x9C, 0x0, 0x63, 0x12, 0x8F, 0x0, 0xA3, 0xE1, 0x10, 0x4, 0x2B, 0x0, 0x55, 0x40, 0x34, 0x2F, 0x15, 0x1, 0xE3, 0x6, 0x1, 0xE3, 0x15, 0x1, 0xDF, 0xD3, 0x10, 0xA7, 0x2, 0xE7, 0xA, 0x4, 0x4F, 0xE3, 0x11, +0x3, 0x9B, 0x12, 0x53, 0x4, 0xC0, 0x0, 0xC0, 0xE3, 0x64, 0x0, 0x9F, 0x0, 0x10, 0x0, 0xD1, 0xE5, 0x1, 0x3, 0x80, 0xE1, 0x0, 0x4, 0x2, 0x8A, 0xE1, 0xB6, 0x1, 0xC6, 0xE1, 0x12, 0x3B, 0x12, 0xDD, 0x3, 0xBF, +0x2, 0x43, 0x5, 0x12, 0xBB, 0xA, 0x8C, 0xE2, 0x43, 0x16, 0x2, 0x3F, 0x46, 0xB8, 0x2, 0xB3, 0x2, 0x9, 0x11, 0x20, 0xBF, 0x11, 0x7, 0x15, 0xD, 0x10, 0xC6, 0x15, 0x7, 0x2, 0x4B, 0x14, 0xAB, 0x82, 0x2, 0xD3, +0x1C, 0xB1, 0x0, 0x90, 0x2, 0xEB, 0x30, 0x7B, 0x11, 0x17, 0x15, 0x0, 0x30, 0xC6, 0x15, 0x14, 0xC7, 0x13, 0x9B, 0xA0, 0x1, 0xB0, 0xE1, 0x40, 0x2E, 0x3, 0x97, 0x46, 0x30, 0x8F, 0xE2, 0x2, 0x0, 0x0, 0xD3, +0xE7, 0x1E, 0x30, 0x43, 0xE2, 0x22, 0x21, 0x0, 0xD3, 0xE7, 0xD8, 0x30, 0x9F, 0xE5, 0xB0, 0x0, 0x8, 0x93, 0xE1, 0xAB, 0x3E, 0x5, 0x47, 0x38, 0x83, 0xE3, 0x5A, 0x93, 0x1, 0x4B, 0x30, 0x1, 0x4B, 0xD, 0xFD, +0xEF, 0x25, 0x3, 0x0, 0x1, 0x0, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0xD, 0xE2, 0x2, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0xE, 0xC3, 0x7, 0x0, 0x7, 0x7, 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x0, 0x0, 0x2, 0x4, 0x6, 0x8, 0xA, +0xC, 0xE, 0xF, 0x10, 0x12, 0x14, 0x16, 0xF0, 0xB, 0xF0, 0xB, 0xF0, 0xB, 0xF0, 0xB, 0xC6, 0xF0, 0xB, 0x40, 0xB, 0x0, 0x18, 0x10, 0x33, 0xA3, 0x15, 0x9B, 0xA8, 0xF0, 0x6, 0x93, 0x1A, 0x97, 0x1A, 0xA7, 0x1A, +0x97, 0x61, 0x5, 0x0, 0x3, 0x0, 0xB0, 0x35, 0x0, 0x3, 0xB, 0x28, 0x0, 0x3, 0x2, 0x43, 0x2A, 0x0, 0x3, 0x41, 0x6, 0x3A, 0xB3, 0x90, 0x70, 0x31, 0x6, 0xB3, 0x1C, 0x2F, 0x6, 0xB6, 0x60, 0x0, 0x9F, 0xE5, +0x40, 0xD0, 0x13, 0xF7, 0x10, 0xF0, 0xE1, 0x0, 0x10, 0xC0, 0x48, 0xE5, 0x4, 0x7B, 0xA, 0x50, 0x0, 0x53, 0x11, 0xD, 0xA0, 0x33, 0xE3, 0xB0, 0x1, 0xEB, 0x11, 0xEF, 0xB6, 0xC, 0x70, 0xB, 0x16, 0x4B, 0x58, +0x34, 0x0, 0x33, 0x34, 0x0, 0x77, 0x16, 0x6F, 0x0, 0x10, 0x80, 0x24, 0xE5, 0x2C, 0x0, 0x43, 0xB0, 0x20, 0x4, 0x3B, 0x20, 0x82, 0x2, 0xE3, 0xB0, 0x20, 0xC0, 0xE1, 0x20, 0x0, 0x53, 0x0, 0x35, 0x0, 0x90, +0x22, 0x57, 0x6, 0x33, 0x1, 0x1B, 0xEB, 0x26, 0x7, 0x33, 0x5, 0xC6, 0x0, 0x0, 0x4, 0x0, 0x7, 0x3B, 0xC, 0x7, 0x3F, 0x7, 0xF8, 0x7F, 0x0, 0x3, 0xAC, 0x0, 0xAF, 0x12, 0x7B, 0xE, 0x3E, 0x48, 0x1A, 0x16, +0x5B, 0xF0, 0x4F, 0x1C, 0x1B, 0x2D, 0xE9, 0x7, 0x0, 0xA0, 0x0, 0xE2, 0xA0, 0x21, 0xA0, 0xE1, 0x88, 0x69, 0x4, 0x40, 0x47, 0x6, 0x4B, 0x1, 0x6, 0x8F, 0x1, 0x40, 0x0, 0x3, 0x55, 0x50, 0x0, 0x7, 0x60, 0x0, +0xB, 0x70, 0x0, 0xF, 0x80, 0x0, 0x13, 0x48, 0x90, 0x11, 0x97, 0x52, 0xE3, 0x15, 0xFB, 0xFA, 0x3, 0xA0, 0x0, 0xE8, 0x1, 0x20, 0x52, 0xE2, 0xFC, 0xFF, 0xFF, 0x8, 0x1A, 0x0, 0x0, 0x5A, 0x20, 0x13, 0x4, 0x10, +0x80, 0x9, 0xE4, 0x1, 0xA0, 0x5A, 0x20, 0x13, 0x3C, 0xC4, 0x7, 0x2B, 0x5, 0xC0, 0x9C, 0xE5, 0x0, 0xB0, 0x6, 0x9B, 0xA0, 0x0, 0x7, 0x81, 0x0, 0x23, 0xCD, 0x0, 0x0, 0x4A, 0xC, 0x90, 0x10, 0xB, 0x14, 0x59, +0xE3, 0xCA, 0x0, 0x43, 0x1C, 0x40, 0x73, 0x90, 0x9, 0x0, 0x9, 0xE0, 0x29, 0x97, 0xA0, 0xE1, 0x4, 0x84, 0x90, 0x7, 0x5F, 0x80, 0x98, 0x6, 0xD3, 0x9C, 0xE5, 0x8, 0x60, 0x40, 0xDC, 0x2, 0x8F, 0xDC, 0xE5, +0x1, 0xC, 0x60, 0xE2, 0x0, 0x90, 0x6, 0x5, 0xE0, 0x25, 0x54, 0xA0, 0xE1, 0x8, 0x5, 0xB0, 0x8B, 0xE0, 0x30, 0xF, 0x6, 0xE0, 0x26, 0x0, 0x64, 0xA0, 0xE1, 0x6, 0xB8, 0x8B, 0xE0, 0x0, 0x10, 0x40, 0x9D, 0xE5, +0x14, 0x5B, 0x94, 0x9, 0x1, 0xE0, 0x10, 0x5E, 0xD, 0x59, 0x10, 0x9B, 0xAA, 0x6, 0x7, 0x51, 0x0, 0xE3, 0x6, 0x17, 0xA0, 0x83, 0x1, 0x20, 0xA0, 0x0, 0x83, 0x10, 0x0, 0x1A, 0xE5, 0x0, 0x6, 0x67, 0xA5, 0x3, +0x8B, 0x51, 0x1, 0x73, 0xA0, 0x81, 0xD, 0x84, 0x8A, 0x10, 0xC3, 0xF8, 0xE, 0xFD, 0x4, 0xA3, 0x1D, 0x1F, 0x2, 0x6B, 0x4, 0x9B, 0x9, 0x8, 0x50, 0x4, 0xE0, 0x1, 0x28, 0x82, 0x22, 0x0, 0xCF, 0x2A, 0x9, 0x0, +0x8, 0x80, 0xE0, 0x89, 0x7, 0x50, 0xE1, 0x89, 0x0, 0x7, 0x40, 0x20, 0x2, 0x29, 0x82, 0x22, 0x9, 0xA9, 0x0, 0xB, 0x9, 0x0, 0xB, 0x1, 0x0, 0xB, 0x89, 0x6, 0x0, 0x17, 0x5A, 0x6, 0x0, 0x17, 0x2A, 0x0, 0x17, +0x0, 0xB, 0x9, 0x0, 0xB, 0x1, 0x95, 0x0, 0xB, 0x89, 0x5, 0x0, 0x2F, 0x5, 0x0, 0x2F, 0x2B, 0x0, 0x2F, 0xA9, 0x0, 0xB, 0x9, 0x0, 0xB, 0x1, 0x0, 0xB, 0x89, 0x4, 0x0, 0x47, 0x5A, 0x4, 0x0, 0x47, 0x2C, 0x0, +0x47, 0x0, 0xB, 0x9, 0x0, 0xB, 0x1, 0x90, 0x0, 0xB, 0x89, 0x3, 0x0, 0x5F, 0x3, 0x40, 0x20, 0x80, 0x6A, 0x20, 0x0, 0x5F, 0x0, 0xB, 0x9, 0x0, 0xB, 0x40, 0x0, 0xB, 0x89, 0x44, 0x2, 0x0, 0x77, 0x2, 0x40, +0x20, 0x5, 0x93, 0x22, 0x9, 0xAA, 0x0, 0xB, 0x9, 0x0, 0xB, 0x10, 0x10, 0x17, 0x1, 0x0, 0x8F, 0x1, 0x1A, 0x40, 0x20, 0x8, 0x10, 0x2F, 0x0, 0xB, 0x9, 0x0, 0xB, 0x4, 0xCE, 0x10, 0x2F, 0x7, 0x97, 0x89, 0x0, +0x0, 0xA7, 0x10, 0x47, 0x7, 0xA3, 0x9, 0xDB, 0x0, 0xB, 0xD, 0xA9, 0x22, 0x6, 0x83, 0x6, 0xEB, 0xA2, 0x3, 0x6B, 0x14, 0x1F, 0x34, 0x44, 0xE0, 0x18, 0x63, 0x16, 0x67, 0x4, 0x8, 0x6B, 0x0, 0x40, 0x8, 0xA0, +0xE3, 0x10, 0x18, 0x15, 0x2F, 0x53, 0xE3, 0x4C, 0xD0, 0x1, 0xCB, 0x11, 0x37, 0x31, 0x16, 0xCF, 0x1F, 0x2D, 0xE9, 0x8C, 0x0, 0x2, 0x9F, 0xE5, 0x27, 0xA6, 0x8A, 0xE0, 0x3, 0x0, 0xA0, 0xCA, 0xE3, 0x1, 0x19, +0x81, 0xE2, 0xA, 0x10, 0x19, 0x51, 0xE2, 0x8, 0xC7, 0x3A, 0xFC, 0x4B, 0xBA, 0x7, 0xE8, 0xFC, 0x4B, 0xA0, 0xE8, 0x10, 0xF, 0x16, 0x13, 0x90, 0xF, 0xD1, 0x9, 0x8C, 0xA0, 0x1F, 0xF3, 0x1, 0x43, 0x1, 0x18, +0x91, 0x10, 0x37, 0x10, 0x4A, 0xFC, 0x0, 0x0, 0x37, 0x0, 0xA0, 0xE8, 0x6, 0xF8, 0x50, 0x37, 0x80, 0xF, 0x20, 0x37, 0x80, 0x1F, 0x10, 0x37, 0x6, 0x19, 0x91, 0x80, 0x16, 0x73, 0x4A, 0x4, 0x20, 0x9A, 0xE4, +0x4, 0x20, 0xD8, 0x2, 0x4F, 0x30, 0x5F, 0xDA, 0x90, 0xF, 0x9, 0x3F, 0xCA, 0xF8, 0x1F, 0xA, 0xBD, 0xE8, 0x27, 0x6, 0x2, 0xA7, 0x4, 0x5, 0xF7, 0x76, 0x45, 0xC7, 0x13, 0x2B, 0xE2, 0xD0, 0xA1, 0x9, 0x9F, +0xA0, 0x0, 0xBB, 0x20, 0x0, 0x18, 0x24, 0xFB, 0x27, 0x6, 0xDA, 0xE7, 0x9, 0x0, 0x70, 0x87, 0xE0, 0x90, 0x5, 0x2, 0xE0, 0xB0, 0x0, 0x10, 0xD8, 0xE1, 0xA2, 0x12, 0x81, 0xE0, 0xB4, 0x5, 0x10, 0xC8, 0xE0, +0x90, 0x6, 0x70, 0xF, 0xB2, 0x0, 0xF, 0x43, 0x1, 0x4, 0x8B, 0x6, 0x0, 0x55, 0xE1, 0x7, 0x6B, 0x8, 0x1A, 0x65, 0x55, 0x64, 0xDF, 0xF, 0x90, 0xA, 0xC2, 0xA, 0x6E, 0x66, 0xA, 0x72, 0x45, 0x68, 0x28, 0x33, +0x55, 0xE3, 0x99, 0x3, 0x3F, 0x5F, 0xA, 0x82, 0x80, 0x12, 0x6B, 0x1, 0x4, 0xBD, 0xB8, 0x0, 0x76, 0x87, 0x0, 0xB0, 0x10, 0x18, 0xBD, 0xE8, 0x10, 0x10, 0x1A, 0xA, 0xE5, 0x1, 0x16, 0xA0, 0x7, 0xEB, 0x51, +0x5, 0x93, 0x0, 0x38, 0xCA, 0xC, 0x0, 0xF, 0x2, 0x73, 0x1A, 0xF, 0x4A, 0x1, 0x76, 0x52, 0x47, 0x6, 0xB, 0x54, 0x15, 0x8F, 0xDA, 0x53, 0x9, 0xE3, 0x2, 0x45, 0x11, 0x17, 0x13, 0x8C, 0xE5, 0x24, 0x10, 0xAF, +0x90, 0x9, 0xBB, 0x4B, 0x70, 0x7, 0x1B, 0x30, 0xB0, 0x19, 0x53, 0xDA, 0x11, 0x9B, 0x19, 0xCF, 0x68, 0x96, 0xA, 0xB, 0x10, 0x33, 0x47, 0x3, 0x5F, 0x4, 0x70, 0x8C, 0x2, 0xE5, 0x10, 0xC0, 0x8C, 0xE2, 0xF8, +0x63, 0xEB, 0x5C, 0x29, 0xE1, 0x29, 0x3, 0x77, 0xD4, 0x43, 0xFB, 0xE4, 0x20, 0xA, 0x97, 0x8, 0x20, 0x92, 0xE5, 0xE0, 0x5, 0x4B, 0x0, 0x30, 0x93, 0x4, 0xE5, 0x83, 0x30, 0x82, 0xE0, 0x16, 0x17, 0xAB, 0xC8, +0x0, 0xA0, 0xE1, 0x8C, 0xC1, 0xA0, 0xE1, 0xB, 0xB8, 0x12, 0xA0, 0xE1, 0xAB, 0x0, 0x3, 0x8B, 0xB1, 0x13, 0xD7, 0x54, 0x20, 0xE2, 0x23, 0x11, 0x4F, 0x60, 0x90, 0xE4, 0xB, 0x50, 0x0, 0x46, 0xE0, 0x5, 0x58, +0xA0, 0xE1, 0xC5, 0x59, 0x0, 0xB0, 0xE1, 0x80, 0x0, 0x75, 0xE3, 0x7F, 0x50, 0x10, 0xE0, 0xB3, 0x7F, 0xA, 0xB7, 0x7F, 0x50, 0xA0, 0xC3, 0x2, 0x26, 0x78, 0x7B, 0xE0, 0xC7, 0x71, 0x10, 0x17, 0x77, 0x14, +0xE3, 0x7F, 0x70, 0x10, 0x17, 0x57, 0x0, 0x7, 0xA0, 0xC3, 0x0, 0xFF, 0x50, 0x5, 0xE2, 0x7, 0x54, 0x85, 0xE1, 0xB, 0xB2, 0x50, 0xC2, 0xE0, 0x10, 0x43, 0xC, 0xF0, 0x43, 0x80, 0x43, 0x62, 0x7C, 0xF0, 0x43, +0xA0, 0x43, 0xC3, 0xE0, 0x2, 0x0, 0x8F, 0xDB, 0xC1, 0x1, 0xCF, 0x24, 0xC7, 0x20, 0x80, 0xE5, 0xF0, 0x4F, 0x3A, 0xFB, 0x6A, 0x4, 0xB, 0xF7, 0x1B, 0xFB, 0x1C, 0x4, 0xBF, 0x28, 0x14, 0xC7, 0x10, 0x1A, 0x0, +0x3, 0x18, 0x4, 0xCB, 0x14, 0xD3, 0x10, 0x4, 0xD3, 0x93, 0xB, 0x9, 0x0, 0xE0, 0x0, 0x1, 0xDB, 0x9C, 0xB, 0x33, 0xA, 0x9F, 0x2A, 0xEB, 0x9A, 0xB, 0x4F, 0x99, 0xB, 0x3F, 0x6, 0x4, 0xB3, 0x4, 0x28, 0x80, +0x88, 0x12, 0x93, 0xEB, 0x1B, 0x13, 0x4, 0x80, 0x48, 0x48, 0xE2, 0x6, 0x53, 0xCA, 0x92, 0x10, 0x27, 0x30, 0x53, 0xE2, 0x86, 0xB, 0x1B, 0x4A, 0x6, 0x8, 0x98, 0x2, 0x3B, 0x32, 0x1B, 0x27, 0x40, 0x46, 0x32, +0x23, 0x4, 0x8, 0x80, 0xE1, 0x90, 0x5, 0x1, 0x4, 0xE0, 0x1F, 0x48, 0xC4, 0xE3, 0xA4, 0x2, 0x27, 0xC, 0x8, 0x10, 0x88, 0xE4, 0xF0, 0x23, 0x80, 0x23, 0xB2, 0x8B, 0x7, 0xE0, 0x8, 0xB0, 0x88, 0xE4, 0xF0, +0x4B, 0xF0, 0x4B, 0xF0, 0x4B, 0xE0, 0xF0, 0x4B, 0x10, 0x4B, 0x10, 0x9F, 0xD7, 0xFF, 0xFF, 0x5A, 0x8, 0x16, 0x30, 0x93, 0xE2, 0x1B, 0xFF, 0x6, 0x0, 0xAF, 0x9, 0xDB, 0x4A, 0x2A, 0x56, 0x18, 0x80, 0x63, +0xE6, 0x32, 0xD3, 0xE, 0x20, 0x63, 0xE, 0x2, 0xE0, 0x1F, 0xE8, 0xCE, 0xE3, 0xAE, 0x2, 0xD7, 0xAE, 0x18, 0x22, 0x82, 0xE0, 0xF0, 0x23, 0x80, 0x23, 0x42, 0x84, 0xE0, 0x1C, 0xAE, 0x62, 0x86, 0xF0, 0x23, +0x90, 0x47, 0x0, 0xD3, 0xAE, 0xC2, 0x2, 0x8C, 0xE0, 0x56, 0x18, 0xA8, 0xE8, 0x10, 0x7B, 0xE0, 0xAC, 0x0, 0x8B, 0x5, 0x5, 0xFF, 0x6, 0x0, 0x8F, 0xD, 0x76, 0xCA, 0x41, 0xB1, 0xC, 0x9F, 0xA, 0x1, 0x43, 0x5, +0x3B, 0x4A, 0x16, 0x48, 0x80, 0xF7, 0x50, 0xC6, 0x33, 0x67, 0xC, 0x20, 0xF7, 0xC, 0xE0, 0x1F, 0xC8, 0x13, 0xCC, 0xE3, 0xAC, 0x3, 0x6B, 0x90, 0x6, 0x40, 0xB, 0x90, 0x9B, 0x9F, 0xF0, 0x2B, 0xE3, 0xAC, 0x0, +0x9B, 0x60, 0x2B, 0x1, 0x57, 0xF0, 0x2B, 0x80, 0x57, 0x1, 0xE2, 0x8E, 0xE0, 0x16, 0x48, 0xA8, 0xE8, 0x10, 0x7F, 0xFF, 0x60, 0x5F, 0x3, 0xD7, 0xF0, 0x33, 0x80, 0x8B, 0x1, 0x1B, 0x60, 0x8B, 0x1, 0x7, 0xF0, +0x2B, 0xFA, 0x80, 0xB7, 0x1, 0xD7, 0x60, 0xB7, 0x40, 0x6B, 0x10, 0xF3, 0xC2, 0x1, 0x97, 0xA, 0xC4, 0x1, 0x97, 0x7, 0x3F, 0xCA, 0xFF, 0xFE, 0x2, 0x67, 0xB8, 0x85, 0x44, 0xE1, 0x54, 0x5F, 0x9B, 0x0, 0x4, +0x24, 0x5F, 0xFF, 0x28, 0x29, 0xC4, 0xE3, 0x54, 0x53, 0xB2, 0x4, 0x6F, 0xA4, 0x1A, 0x24, 0x5F, 0x37, 0xE1, 0x2, 0x2, 0x77, 0xC, 0x73, 0xBA, 0xF0, 0x2F, 0x30, 0x2F, 0x14, 0x93, 0xCA, 0x14, 0x9F, 0x40, +0x2F, 0xE0, 0xE8, 0x4, 0xDF, 0xE6, 0x0, 0x63, 0x1, 0x8, 0x43, 0xA0, 0xE3, 0x4C, 0x5, 0x8F, 0x4, 0x0, 0x4, 0xA0, 0xA, 0xE3, 0xF, 0x3, 0x5F, 0xC0, 0xE3, 0x0, 0xF0, 0x29, 0x81, 0x1D, 0x87, 0xE3, 0x34, 0x1, +0x84, 0xE5, 0x34, 0x5, 0xAB, 0x41, 0x28, 0x0, 0x7, 0x3C, 0x6, 0x9F, 0xE5, 0x20, 0x0, 0xF, 0x44, 0x8, 0xE, 0x8B, 0x4, 0x0, 0x84, 0xD, 0x43, 0xA0, 0xE3, 0x5, 0x8, 0x2, 0x84, 0xE5, 0x81, 0xE, 0x9B, 0x0, +0x0, 0x7, 0x89, 0x10, 0x17, 0xB4, 0x0, 0xC4, 0xD, 0x9B, 0x8F, 0xE2, 0x18, 0x1F, 0x2, 0x81, 0x48, 0x82, 0x49, 0x1, 0x80, 0x0, 0x3, 0xC9, 0x0, 0x0, 0x28, 0x0, 0xD1, 0x81, 0x49, 0x81, 0x48, 0x0, 0x1, 0x62, +0x2, 0xB4, 0x0, 0xF0, 0xC9, 0xFC, 0x0, 0x80, 0x4F, 0x20, 0xBC, 0x28, 0x88, 0x69, 0x88, 0x0, 0x79, 0x81, 0x7E, 0x49, 0x0, 0x22, 0x2E, 0x1C, 0x8, 0xC, 0x35, 0x0, 0x28, 0xF, 0x13, 0x21, 0xE, 0xE0, 0x0, 0x10, +0xCD, 0x0, 0x2C, 0x5, 0xD0, 0xA4, 0x19, 0x0, 0xA4, 0x79, 0x0, 0x2C, 0x1, 0xD0, 0xA, 0x80, 0x0, 0x2, 0x31, 0x1, 0x32, 0x1, 0x38, 0xF3, 0xD1, 0x0, 0x74, 0x48, 0x9, 0x1A, 0x49, 0x8, 0xB9, 0x81, 0x0, 0x73, +0x49, 0x74, 0x4A, 0x4A, 0x60, 0x74, 0x48, 0x40, 0x8, 0x0, 0x3, 0x74, 0x49, 0x75, 0x4A, 0x8, 0x23, 0x0, 0x14, 0x24, 0x10, 0x80, 0x2, 0x32, 0x1, 0x3B, 0x0, 0xFB, 0xD1, 0x40, 0x1A, 0x8, 0x23, 0x1, 0x3C, +0x0, 0xF7, 0xD1, 0x70, 0x48, 0x71, 0x49, 0x71, 0x4A, 0x0, 0x10, 0xDF, 0x71, 0x48, 0x72, 0x49, 0x90, 0x22, 0x10, 0x52, 0x0, 0xB, 0x0, 0x9, 0x71, 0x49, 0xC, 0x22, 0x80, 0x10, 0x7, 0x80, 0x21, 0x1, 0x80, +0x2, 0x30, 0x1, 0x10, 0x31, 0x10, 0x22, 0x20, 0x7, 0x3A, 0xFB, 0xD1, 0x6D, 0x81, 0x0, 0xA3, 0xB, 0x22, 0x82, 0x21, 0x1E, 0x30, 0x40, 0x19, 0x68, 0x23, 0x20, 0x21, 0x0, 0x4F, 0x67, 0x0, 0xBD, 0x1, 0x3A, +0xF1, 0x10, 0xD1, 0x66, 0x49, 0x10, 0x1B, 0x1, 0x31, 0x2, 0x30, 0xA0, 0x70, 0x35, 0x62, 0x0, 0xD9, 0x5D, 0x49, 0x62, 0x48, 0x1, 0x0, 0x22, 0x52, 0x2, 0x61, 0x4C, 0x8, 0xC9, 0x1B, 0x0, 0x19, 0x8, 0xC0, +0x1, 0x3A, 0xFA, 0xD1, 0x5F, 0x2, 0x48, 0x60, 0x49, 0x1, 0x60, 0x60, 0x0, 0x5, 0x10, 0xD0, 0x0, 0x6F, 0x10, 0x7, 0x8, 0x20, 0x7, 0x1, 0x21, 0x49, 0x2, 0x10, 0x80, 0x22, 0x6, 0x0, 0x23, 0xFC, 0xD1, 0x40, +0x4F, 0x0, 0x1, 0x20, 0x80, 0x2, 0xF8, 0x80, 0x38, 0x81, 0x0, 0x2, 0x20, 0x2, 0x21, 0xD, 0xA2, 0x0, 0xF0, 0x1, 0x94, 0xF9, 0x2, 0x20, 0x4, 0x21, 0xE, 0x0, 0x9, 0x45, 0x8F, 0x0, 0x9, 0x6, 0x21, 0x10, 0x0, +0x13, 0x8A, 0x0, 0x13, 0x10, 0x8, 0x21, 0x11, 0x0, 0x1D, 0x85, 0xF9, 0xFF, 0x21, 0x0, 0xB9, 0x73, 0x0, 0xF0, 0xD1, 0xF9, 0x0, 0xF0, 0x40, 0x8C, 0x0, 0x3, 0x97, 0xF9, 0x1F, 0xE0, 0x4D, 0x75, 0x8, 0x73, +0x69, 0x63, 0x3A, 0x7, 0xBE, 0x20, 0x2D, 0x2D, 0x0, 0x0, 0x0, 0xC0, 0x46, 0x45, 0x66, 0x66, 0x65, 0x30, 0x63, 0x74, 0x10, 0x10, 0x30, 0xF, 0x54, 0x65, 0x6D, 0x70, 0x42, 0x6F, 0x0, 0x1F, 0x31, 0x30, 0x30, +0x25, 0x10, 0x1F, 0x50, 0x8, 0x69, 0x74, 0x63, 0x68, 0x80, 0xF, 0x5, 0xDF, 0x3C, 0x30, 0x48, 0x3C, 0x1, 0x9D, 0x10, 0x7, 0x0, 0x88, 0xC5, 0x43, 0x0, 0x3C, 0x88, 0x3D, 0x80, 0x26, 0x1C, 0x2E, 0x40, 0x0, +0x6E, 0x40, 0xF0, 0x9, 0x1, 0xD3, 0x0, 0xF0, 0x8, 0xAC, 0xF8, 0x30, 0xA, 0x10, 0x7, 0xB0, 0xF8, 0x30, 0x0, 0x1C, 0x34, 0x49, 0x0, 0xF0, 0x6D, 0xF8, 0x20, 0x8, 0x1C, 0x28, 0x40, 0x33, 0x0, 0x9, 0x68, 0xF8, +0x28, 0x2, 0x1C, 0x20, 0x40, 0x60, 0x40, 0x31, 0x0, 0x15, 0x62, 0x8, 0xF8, 0x0, 0xF0, 0x50, 0x0, 0x95, 0x84, 0xF9, 0xB8, 0x40, 0x7B, 0x1, 0xC1, 0xD0, 0x0, 0xF0, 0x3C, 0xF9, 0x0, 0x20, 0x20, 0xB8, 0x0, +0xAB, 0x4, 0xFC, 0xD1, 0xE7, 0xD4, 0x50, 0x1D, 0xA, 0x93, 0x50, 0xA, 0x20, 0x2, 0x0, 0x4, 0x14, 0x0, 0x40, 0x0, 0x0, 0xFC, 0x33, 0x0, 0x2, 0x0, 0x0, 0x34, 0x0, 0x8, 0xBC, 0x1E, 0x0, 0x3, 0x58, 0x90, 0xA, +0xD7, 0x88, 0x52, 0x1A, 0x2B, 0x0, 0x5, 0x60, 0x5D, 0xB, 0xFF, 0x7F, 0x0, 0x0, 0x0, 0x3, 0x7C, 0xA, 0x35, 0xF, 0x54, 0x2, 0x48, 0x51, 0x0, 0x3, 0x54, 0x0, 0x5, 0x83, 0x4, 0x12, 0x0, 0x6, 0xE0, 0x0, 0x2B, +0x54, 0x3, 0x5, 0x8F, 0x10, 0x1A, 0x0, 0x6, 0xE8, 0x0, 0x37, 0x5, 0x83, 0x4, 0x2, 0x4D, 0x6, 0x54, 0x80, 0xF, 0x7C, 0x82, 0xF, 0x80, 0x80, 0x5, 0x94, 0x80, 0xC, 0x8A, 0xA, 0x6D, 0x30, 0x0, 0x6, 0xA, 0xFC, +0x10, 0x10, 0x6E, 0x4A, 0x8, 0x35, 0x8, 0x8, 0x14, 0x10, 0x3F, 0x0, 0x1, 0x6, 0x4B, 0x34, 0x10, 0x47, 0x2, 0x0, 0xF, 0xE2, 0x0, 0xF, 0x82, 0xA, 0xAB, 0x80, 0xF, 0x68, 0x30, 0x1, 0x0, 0x4, 0x77, 0x1B, +0x0, 0x28, 0x3, 0x8F, 0x0, 0x3, 0xA1, 0x0, 0x7, 0x30, 0xB5, 0x4, 0x0, 0x1C, 0xD, 0x1C, 0x60, 0x8, 0x2, 0xD3, 0x0, 0x2, 0x20, 0x0, 0xF0, 0x10, 0xF8, 0xA0, 0x0, 0x9, 0x1, 0x80, 0x0, 0x9, 0xB, 0xF8, 0xA0, +0x9, 0x2, 0xD3, 0x2, 0x8A, 0x0, 0x13, 0x6, 0xF8, 0x60, 0x0, 0x9, 0x3, 0x0, 0x1D, 0x1, 0x0, 0xF8, 0x30, 0xBD, 0x28, 0x47, 0x1, 0x21, 0xB9, 0x0, 0x74, 0xF8, 0x74, 0x0, 0x21, 0x3A, 0x7C, 0x52, 0x0, 0x0, +0x7A, 0x44, 0x97, 0x46, 0x41, 0xE0, 0x54, 0x0, 0xE0, 0x63, 0xE0, 0x89, 0xE0, 0xB9, 0x7C, 0x0, 0x0, 0x29, 0x4, 0xD0, 0xF9, 0x7C, 0x88, 0x42, 0x1, 0x0, 0xD1, 0x1, 0x21, 0xEF, 0xE7, 0x70, 0x47, 0x79, 0xB0, +0x10, 0x11, 0xD1, 0x30, 0x11, 0x1, 0x19, 0x74, 0x70, 0x47, 0x38, 0x0, 0x7C, 0x1, 0x38, 0x0, 0xD5, 0x3, 0x20, 0x38, 0x40, 0x82, 0x60, 0xF, 0x30, 0x3, 0x28, 0xF7, 0xDD, 0x0, 0x0, 0x20, 0xF5, 0xE7, 0x0, +0x2A, 0x3, 0xD5, 0x0, 0x10, 0x20, 0x78, 0x74, 0x10, 0x27, 0x1, 0x29, 0xFC, 0xD0, 0x0, 0x7, 0x21, 0x79, 0x74, 0x1, 0x28, 0x2, 0xDC, 0x0, 0x0, 0xD0, 0x9F, 0x46, 0xA7, 0x46, 0xB9, 0x5B, 0x0, 0x3, 0x28, 0x3, +0xD0, 0x1, 0x39, 0x5, 0xD5, 0x0, 0x11, 0x1C, 0x3, 0xE0, 0x1, 0x31, 0x91, 0x42, 0x0, 0x0, 0xDD, 0x0, 0x21, 0xB9, 0x53, 0xB8, 0x7B, 0x0, 0x28, 0x43, 0xB8, 0x73, 0x70, 0x47, 0x70, 0xB5, 0x0, 0x7A, 0x89, +0x1, 0x3A, 0x3, 0xA3, 0x5, 0xA4, 0x0, 0x1, 0x25, 0x2, 0x26, 0xFF, 0xF7, 0xD8, 0xFF, 0x0, 0x70, 0xBD, 0x0, 0x20, 0xF8, 0x73, 0x78, 0x88, 0x2, 0x0, 0x21, 0xB5, 0x4B, 0x18, 0x47, 0x10, 0xB, 0xB4, 0x28, 0x48, +0x0, 0x0, 0x27, 0xBA, 0x20, 0x27, 0xB2, 0x4C, 0x2, 0x28, 0x25, 0x4, 0x0, 0x27, 0xC4, 0x0, 0x27, 0xB0, 0x49, 0xB8, 0x2, 0x88, 0x40, 0x0, 0x8, 0x58, 0xAF, 0x10, 0x27, 0xB5, 0x0, 0x0, 0x28, 0x2, 0xD1, 0xB8, +0x74, 0x78, 0x74, 0x0, 0x0, 0xBD, 0xFA, 0x88, 0x2, 0x28, 0x7, 0xD0, 0x1, 0xC, 0xDC, 0x0, 0x29, 0xF8, 0xD1, 0x7, 0x0, 0x99, 0x0, 0x1, 0x22, 0x92, 0x2, 0xC, 0xE0, 0x4, 0x3A, 0x8, 0x50, 0xA, 0x7, 0xD1, 0x12, +0xFB, 0x4, 0xE0, 0x4, 0x0, 0x32, 0xD0, 0xA, 0x1, 0xD0, 0x1, 0x22, 0xD2, 0x40, 0x2, 0x10, 0xB9, 0xFA, 0x80, 0xB8, 0x7B, 0x4, 0x21, 0x40, 0x8, 0x0, 0x8F, 0x10, 0x1C, 0x0, 0xF0, 0x6B, 0xFC, 0x27, 0x0, 0xBD, +0x90, 0x4D, 0x3A, 0x89, 0xF0, 0x4D, 0xF0, 0x4D, 0x70, 0x4D, 0x5, 0x3A, 0x81, 0xB8, 0x7B, 0x8, 0x60, 0x4D, 0x5D, 0x0, 0x4D, 0x0, 0x49, 0x1, 0x40, 0x18, 0x40, 0x0, 0x87, 0x49, 0x4, 0x9, 0x18, 0x1, 0xE0, +0x8, 0x4, 0x1D, 0x10, 0x78, 0x0, 0x1, 0x32, 0x0, 0x28, 0xF9, 0xD1, 0x70, 0x47, 0x0, 0x10, 0xB4, 0x1, 0x24, 0x64, 0x2, 0x80, 0x48, 0x80, 0x4, 0x67, 0x4A, 0x8, 0xC8, 0x9B, 0x18, 0x8, 0xC1, 0x0, 0x1, 0x3C, +0xFA, 0xD1, 0x10, 0xBC, 0x70, 0x47, 0x4C, 0x78, 0x1, 0x71, 0x3, 0xD4, 0x0, 0xCD, 0x4, 0x85, 0xB8, 0x74, 0x10, 0x7B, 0x48, 0x30, 0x1, 0xB7, 0x12, 0x1, 0x89, 0x18, 0x8, 0x1, 0x80, 0x79, 0x4A, 0x0, 0x5, +0x81, 0x3C, 0x21, 0x0, 0xBA, 0x7C, 0x0, 0x2A, 0x0, 0xD0, 0x1, 0x31, 0x40, 0x41, 0x3, 0xE5, 0x41, 0x81, 0x0, 0x21, 0x81, 0x80, 0x0, 0x1, 0x21, 0x9, 0x3, 0x81, 0x81, 0x70, 0x47, 0x0, 0x64, 0x22, 0x50, 0x43, +0xFF, 0x30, 0xFF, 0x30, 0x0, 0x80, 0xA, 0xA, 0x1C, 0xA, 0x21, 0x6, 0xDF, 0x0, 0x30, 0x31, 0x91, 0x80, 0xA, 0x28, 0x6, 0xDB, 0x80, 0x30, 0xB, 0x51, 0x80, 0x30, 0x30, 0x10, 0x80, 0x3, 0x0, 0xE0, 0x30, 0x30, +0x50, 0x80, 0x0, 0x20, 0x10, 0x0, 0x80, 0x70, 0x47, 0xF0, 0xB5, 0xBC, 0x7B, 0x64, 0x2, 0x8, 0x6, 0xD3, 0x78, 0x89, 0x0, 0x1, 0xAB, 0x78, 0x1, 0x88, 0x61, 0x49, 0xFF, 0xF7, 0xE2, 0xFF, 0x10, 0x11, 0x45, +0xB8, 0x20, 0x11, 0xB8, 0x88, 0x5E, 0x0, 0x11, 0xD9, 0x0, 0x11, 0x5, 0x3, 0xD3, 0xF8, 0x88, 0x5C, 0x0, 0x1D, 0xCE, 0x20, 0xB, 0x10, 0x38, 0x89, 0x5A, 0x0, 0x29, 0xC8, 0xFF, 0xF0, 0xBD, 0x8, 0xC0, 0x46, +0x1, 0x3, 0x9, 0x9B, 0x12, 0x90, 0xE5, 0x40, 0x21, 0x0, 0xE3, 0x2, 0x2C, 0x80, 0xE2, 0xB2, 0x10, 0x6, 0xC2, 0xE1, 0xB8, 0x20, 0x50, 0x1D, 0x8B, 0x0, 0x7, 0x40, 0x91, 0x8, 0xFF, 0x11, 0xE3, 0xA, 0xF3, +0x1A, 0x34, 0x1, 0x1D, 0xAF, 0xE0, 0x5, 0x83, 0x1D, 0xAF, 0xF, 0xAB, 0x5, 0x24, 0xA0, 0xE3, 0x6, 0xA1, 0xB, 0x3, 0x24, 0x2F, 0x7B, 0x80, 0xE5, 0x1F, 0x1B, 0xD, 0xEF, 0xB0, 0x0, 0x3B, 0x18, 0x0, 0x27, +0x1D, 0xAF, 0x20, 0x21, 0x90, 0xE5, 0x45, 0x80, 0xF, 0x7, 0x3, 0x0, 0x52, 0x1E, 0xEF, 0xA, 0x2E, 0xF7, 0xAB, 0xC, 0xD3, 0xC6, 0x9, 0xF, 0xC4, 0x9, 0x13, 0xD0, 0x9, 0x17, 0x1D, 0xEB, 0x42, 0x84, 0x9, 0x1F, +0x54, 0x40, 0x9F, 0xE5, 0xA, 0x47, 0xEB, 0x9C, 0xC, 0xDB, 0xE1, 0xDC, 0x19, 0xEF, 0xB, 0xCB, 0xA, 0xB7, 0xEB, 0x4, 0x0, 0x10, 0x83, 0xE4, 0x1, 0x40, 0x84, 0xE0, 0x4, 0x84, 0xD, 0x93, 0xFA, 0xFF, 0xFF, +0x8A, 0xB, 0xEB, 0xEB, 0xBC, 0xA0, 0xF, 0x5B, 0x13, 0x10, 0x5F, 0x41, 0x80, 0xE5, 0x28, 0x11, 0x83, 0x0, 0x63, 0x10, 0x81, 0xE3, 0x28, 0x11, 0x40, 0xB, 0x0, 0xAB, 0xB0, 0x1D, 0xBB, 0x20, 0x0, 0x17, 0x1F, +0x67, 0x42, 0x4F, 0x4F, 0x54, 0x0, 0x4F, 0x4B, 0x41, 0x59, 0x42, 0x52, 0x53, 0x54, 0xA0, 0x13, 0x94, 0x20, 0x40, 0x3, 0xC8, 0x45, 0x0, 0x3, 0xC8, 0x5, 0x4A, 0x0, 0x3, 0x48, 0x4E, 0x0, 0x7, 0x3A, 0x0, +0x7, 0x6E, 0x40, 0x24, 0x1B, 0x4, 0x5, 0x1, 0x4, 0x11, 0x10, 0x7, 0xE, 0x67, 0x5, 0x0, 0x0, 0x6, 0xC8, 0xFF, 0xE0, 0xFF, 0xC7, 0xFF, 0x0, 0xDF, 0xFF, 0xD0, 0xFF, 0xE8, 0xFF, 0xCA, 0xFF, 0x0, 0xE2, 0xFF, +0xED, 0x23, 0x0, 0x3, 0xE9, 0x25, 0x9, 0x0, 0x3, 0x6F, 0x21, 0x34, 0x4F, 0x79, 0x1F, 0x9, 0xBB, 0x5D, 0x18, 0x4, 0xB, 0x20, 0x34, 0xF, 0x13, 0xF7, 0x10, 0x41, 0x96, 0x0, 0x13, 0x4, 0x16, 0x19, 0x0, 0x6, +0x94, 0x0, 0x3, 0x14, 0x1A, 0x18, 0x0, 0x6, 0xB0, 0xE, 0xB7, 0x14, 0x67, 0x1, 0x0, 0x40, 0x38, 0xA2, 0x10, 0x9, 0xF3, 0x10, 0x73, 0x1, 0xC1, 0x21, 0xAF, 0x4A, 0x80, 0x26, 0x4D, 0x39, 0xFB, 0xD1, 0xAE, +0x4A, 0x10, 0x60, 0x0, 0x70, 0x47, 0xAC, 0x48, 0x0, 0x68, 0x1, 0x21, 0x0, 0x40, 0x8, 0x1, 0xD3, 0x1, 0x31, 0xFB, 0xE7, 0x11, 0x11, 0x29, 0x0, 0x6, 0xA5, 0x8, 0x1C, 0x70, 0x3, 0x23, 0x0, 0x1, 0x21, 0x89, +0x2, 0xA6, 0x4A, 0x7, 0xB4, 0x0, 0x68, 0x46, 0x0, 0xF0, 0x3, 0xF8, 0x3, 0xB0, 0x10, 0x8, 0xBC, 0x18, 0x3, 0x81, 0x4, 0x1C, 0xE5, 0x88, 0x20, 0xFF, 0x2D, 0x6, 0xCB, 0x25, 0x19, 0xE0, 0x0, 0x2D, 0x0, 0xB, +0xD0, 0x29, 0x6, 0xC9, 0xD, 0x2, 0x39, 0x0, 0x9A, 0x48, 0x40, 0x5C, 0x0, 0x28, 0x10, 0xD0, 0x40, 0x28, 0x3, 0x13, 0x9C, 0xF8, 0x0, 0x28, 0xB, 0xD1, 0x0, 0xFF, 0xF7, 0xD2, 0xFF, 0x5, 0x1C, 0x7, 0xD0, 0x0, +0x96, 0x48, 0x1, 0x78, 0x1, 0x31, 0x1, 0x70, 0x0, 0x9, 0x2, 0xD, 0x43, 0x2D, 0x4, 0x2D, 0xC, 0x40, 0x93, 0x5, 0x6B, 0x32, 0xF9, 0xFF, 0x28, 0x42, 0xDA, 0x0, 0x6, 0x1C, 0x0, 0x2D, 0xF, 0xD0, 0x8B, 0x49, +0x0, 0x6A, 0x1E, 0x12, 0x6, 0x12, 0xE, 0x1, 0x23, 0x0, 0x93, 0x40, 0x52, 0x0, 0x89, 0x18, 0x42, 0x1C, 0x0, 0xA, 0x70, 0x2A, 0xA, 0x4A, 0x70, 0x86, 0x49, 0x0, 0xA, 0x68, 0x1A, 0x43, 0xB, 0x60, 0x88, 0x49, +0x0, 0x9, 0x68, 0x1C, 0x22, 0x42, 0x43, 0x89, 0x18, 0x4, 0xC8, 0x22, 0xA, 0x74, 0x0, 0x0, 0x79, 0x2, 0x22, 0x0, 0x0, 0xE0, 0x4, 0x22, 0x4A, 0x74, 0x80, 0x22, 0x14, 0xCA, 0x75, 0x82, 0x0, 0x1D, 0x10, 0x0, +0x1D, 0x8B, 0x18, 0x40, 0x80, 0x0, 0xC7, 0x21, 0x88, 0x89, 0x0, 0xC, 0x31, 0x0, 0x41, 0x58, 0x9, 0x18, 0x4A, 0x8A, 0x18, 0x31, 0x0, 0x19, 0x60, 0xA0, 0x88, 0x42, 0x43, 0x12, 0xA, 0x0, 0xDA, 0x60, 0x0, +0x21, 0x59, 0x60, 0x20, 0x7A, 0x40, 0x79, 0x0, 0x49, 0x48, 0x43, 0x80, 0xA, 0x18, 0x72, 0x0, 0x60, 0x7A, 0x58, 0x72, 0x28, 0x1C, 0x70, 0xBC, 0x1A, 0x2, 0xBC, 0x8, 0x4, 0x33, 0x30, 0x7, 0x1, 0x0, 0xC7, +0x0, 0x0, 0x29, 0xB, 0xD0, 0x20, 0x29, 0x9, 0xDC, 0x6F, 0x0, 0x4A, 0x53, 0x5A, 0x19, 0xA, 0x2, 0xA, 0x91, 0x0, 0x42, 0x3, 0xD1, 0x1B, 0x6, 0x1B, 0xE, 0x1, 0x44, 0x3B, 0x1, 0xF, 0x23, 0xDB, 0x43, 0x1, +0x15, 0x21, 0x5F, 0x4, 0x4A, 0x40, 0x0, 0x11, 0x52, 0x11, 0x31, 0x81, 0x40, 0x2, 0x5D, 0x4A, 0x10, 0x68, 0x88, 0x43, 0x11, 0x45, 0x2, 0x0, 0xB5, 0xDB, 0x46, 0xFF, 0xF7, 0xDD, 0xFF, 0x2, 0x8, 0xBC, 0x6, +0xD4, 0x5F, 0x1, 0x51, 0x41, 0x43, 0x89, 0x0, 0xA, 0x18, 0x1C, 0x1, 0xF0, 0x3C, 0xFC, 0x1, 0x22, 0xBC, 0x0, 0x0, 0x1D, 0xFF, 0xF7, 0xCF, 0x0, 0x1B, 0x2, 0x55, 0xD4, 0x10, 0x13, 0x39, 0x60, 0x13, 0xC5, +0x60, 0x13, 0x5, 0x20, 0x27, 0x40, 0x1, 0x0, 0x27, 0xBB, 0xFF, 0x1, 0xBC, 0x14, 0xD4, 0x0, 0x1C, 0x21, 0x59, 0x43, 0x4A, 0x4A, 0x12, 0x68, 0x4, 0x52, 0x18, 0x2, 0x21, 0x51, 0x5, 0x87, 0x11, 0x74, 0x80, +0x5, 0xFD, 0xE, 0x1, 0x38, 0xFF, 0xF7, 0xBE, 0xFF, 0x21, 0x0, 0x21, 0x10, 0x59, 0xF, 0xFC, 0x1, 0x20, 0x30, 0xBF, 0xD5, 0x20, 0xBD, 0x0, 0x61, 0x9E, 0x0, 0x39, 0xB, 0x20, 0x39, 0x3B, 0x70, 0x39, 0xB4, +0x40, 0x35, 0xA3, 0x0, 0x55, 0x30, 0x87, 0x8B, 0x60, 0x87, 0xD2, 0xFB, 0xB1, 0x10, 0x9B, 0x81, 0x14, 0xDB, 0x7, 0xAD, 0x31, 0x49, 0x8, 0x2, 0xD, 0x0, 0xF0, 0xB5, 0x28, 0x4C, 0x24, 0x68, 0x26, 0x4E, 0x0, +0x0, 0x25, 0x64, 0x8, 0xF, 0xD3, 0x77, 0x5D, 0x0, 0x1, 0x3F, 0xC, 0xD4, 0x38, 0x1C, 0x0, 0x21, 0x4, 0x1, 0xF0, 0xD7, 0xFB, 0x26, 0x2, 0x29, 0x1C, 0x21, 0x14, 0x79, 0x43, 0x40, 0x0, 0x93, 0x41, 0x6, 0x1B, +0x1, 0x74, 0x1, 0x2, 0x35, 0x64, 0x8, 0xEC, 0xD2, 0xFB, 0x11, 0xEB, 0x15, 0xFE, 0xF0, 0xBC, 0x32, 0x1F, 0x18, 0x0, 0x3F, 0x16, 0x20, 0x3F, 0x0, 0x13, 0xD3, 0x70, 0x5D, 0x1, 0x38, 0x10, 0xD4, 0x40, 0x19, +0x41, 0xA3, 0x89, 0x18, 0xA, 0x68, 0xD2, 0x17, 0x10, 0x8, 0xD0, 0x14, 0x61, 0xD1, 0x0, 0x20, 0x48, 0x74, 0x9, 0xC8, 0x75, 0x70, 0x55, 0x10, 0x47, 0xE8, 0xD2, 0x10, 0x4D, 0x0, 0xE5, 0xD2, 0xF8, 0xD1, 0x0, +0x24, 0x1, 0x25, 0x0, 0x2D, 0x4, 0x5, 0x4E, 0x30, 0x78, 0x2, 0x36, 0x80, 0x9, 0x57, 0xD0, 0x2C, 0x43, 0x6D, 0x0, 0xF8, 0xD1, 0x0, 0x24, 0xC, 0x2, 0x48, 0x4, 0x60, 0x70, 0xBD, 0x50, 0x70, 0x7, 0x57, 0x90, +0x7, 0x5B, 0xFF, 0x80, 0x0, 0x0, 0x40, 0x94, 0x7, 0x63, 0xD0, 0x9, 0x0, 0x3, 0x50, 0x5B, 0xAA, 0x3C, 0xE3, 0xB4, 0x7, 0x73, 0x6C, 0x7, 0x77, 0x6E, 0x7, 0x7B, 0x38, 0x0, 0x47, 0x8, 0x47, 0x10, 0x47, 0x18, +0x47, 0x3A, 0x80, 0x20, 0xD7, 0xC0, 0x46, 0x0, 0xB5, 0x39, 0x4A, 0x20, 0x0, 0x21, 0x41, 0x58, 0x11, 0x60, 0x38, 0x4A, 0x1, 0x0, 0x69, 0x11, 0x60, 0xC1, 0x68, 0x51, 0x60, 0x41, 0x0, 0x68, 0x91, 0x60, 0x81, +0x68, 0xD1, 0x60, 0x1, 0x8, 0xF0, 0x76, 0xFB, 0x33, 0x2, 0x67, 0x1, 0x20, 0x88, 0x8, 0x40, 0x1, 0x38, 0x32, 0x1, 0x9, 0x32, 0x48, 0x0, 0x8, 0xF0, 0x4C, 0xF9, 0x30, 0x0, 0x5, 0x51, 0xF9, 0x2F, 0x2, 0x48, +0xFF, 0xF7, 0x6C, 0xFF, 0x2D, 0x0, 0x11, 0x74, 0x20, 0xF9, 0x2C, 0x0, 0x17, 0x8A, 0xF9, 0xFF, 0xF7, 0x5A, 0x50, 0xFE, 0x11, 0xD7, 0x29, 0x21, 0x33, 0x0, 0xB5, 0xF0, 0xB4, 0x1, 0x28, 0x4F, 0x1, 0xF0, 0xFE, +0xFB, 0x27, 0x0, 0x5, 0x5, 0xFB, 0xFB, 0x27, 0x48, 0x27, 0x10, 0x4B, 0x60, 0x40, 0x7, 0x12, 0x70, 0x27, 0x48, 0x1, 0x3F, 0x70, 0x26, 0x0, 0x15, 0x8, 0x20, 0x60, 0x27, 0x1, 0x5D, 0x81, 0x79, 0x0, 0x29, +0x22, 0x20, 0xD0, 0x23, 0x3, 0x77, 0x2A, 0x21, 0x45, 0x5A, 0x2C, 0x1, 0x21, 0x46, 0x5A, 0xAD, 0x1B, 0x0, 0x2D, 0xE, 0xB1, 0x0, 0x25, 0xA5, 0x42, 0x0, 0xDB, 0xB, 0xE0, 0x2C, 0x0, 0x21, 0x0, 0x27, 0x47, +0x52, 0x64, 0x1B, 0x28, 0x24, 0x1C, 0x1C, 0x0, 0x55, 0xD3, 0xFB, 0x10, 0x5, 0xD0, 0xFB, 0x0, 0xE6, 0xE7, 0x2C, 0x21, 0x36, 0x19, 0x46, 0x52, 0x0, 0x20, 0x1C, 0x17, 0x49, 0x1, 0xF0, 0xBC, 0xFB, 0x45, 0xF0, +0x22, 0xBD, 0x20, 0x1C, 0x13, 0x0, 0xD, 0xB5, 0x40, 0xD, 0x75, 0x98, 0x8, 0x73, 0x11, 0x3, 0x11, 0xF, 0x5C, 0x1, 0x13, 0xA8, 0x8, 0x83, 0xA8, 0x18, 0x6F, 0xAC, 0x8, 0x8B, 0xAF, 0x4, 0x3F, 0xAF, 0x26, +0x0, 0x2A, 0x3, 0x3C, 0x1, 0x2B, 0x54, 0x1, 0x2F, 0x4C, 0x1, 0x33, 0x58, 0xAE, 0x1, 0x37, 0x4D, 0x1, 0x3B, 0xB8, 0x11, 0x2F, 0x1, 0x43, 0x1E, 0xF, 0x94, 0x80, 0xE, 0x1F, 0x7D, 0x4, 0x0, 0x3, 0x70, 0xB4, +0x30, 0x80, 0x6, 0xF, 0x79, 0x43, 0x0, 0x22, 0x4, 0xC0, 0x1, 0x0, 0x39, 0xFC, 0xD1, 0x30, 0x1C, 0x28, 0x38, 0x28, 0x82, 0x1, 0xFD, 0xFF, 0x22, 0x42, 0x54, 0x28, 0x0, 0xF, 0x45, 0x80, 0x2, 0x27, 0x45, +0x4E, 0x36, 0x78, 0x45, 0x4D, 0x46, 0xA0, 0x4, 0x41, 0x46, 0x3, 0xA5, 0x0, 0x22, 0xC3, 0x7D, 0x9B, 0x0, 0x9, 0xB3, 0x42, 0x4, 0xD1, 0x18, 0x23, 0xC2, 0x0, 0x50, 0x4, 0x3B, 0xFC, 0xD5, 0x25, 0x60, 0x1C, +0x0, 0x30, 0x10, 0x34, 0x1, 0x39, 0xF2, 0xD1, 0x70, 0x8A, 0x6, 0xA5, 0x10, 0xB5, 0x3B, 0x4, 0x6B, 0x37, 0x3, 0xCF, 0x3A, 0x91, 0x2, 0xD9, 0x0, 0x24, 0x10, 0x2D, 0x0, 0xD1, 0xCC, 0x10, 0x23, 0x1, 0x31, +0x1, 0x3A, 0xF7, 0xD1, 0x10, 0xBD, 0x0, 0x6B, 0x20, 0xB4, 0x34, 0x2, 0xF5, 0x13, 0x88, 0x9B, 0x0, 0xC, 0x10, 0x33, 0x9B, 0x18, 0xB, 0xA7, 0x18, 0x0, 0x68, 0x80, 0x1, 0x18, 0x4, 0xBC, 0x8, 0x30, 0x3, 0xE0, +0x8, 0x31, 0x4, 0x22, 0x1, 0x21, 0xED, 0xE7, 0x11, 0x6F, 0x27, 0x4B, 0x0, 0x1A, 0x70, 0x0, 0x2A, 0x5, 0xD1, 0x2A, 0x4D, 0x0, 0x2A, 0x4E, 0x36, 0x68, 0x2A, 0x4F, 0x3F, 0x68, 0x20, 0x2, 0xE0, 0x10, 0xB, +0x4, 0x27, 0x2E, 0x22, 0xA9, 0x4, 0x54, 0x4, 0x1C, 0x6C, 0x61, 0x13, 0xF, 0x63, 0x78, 0x0, 0xA2, 0x78, 0x9B, 0x0, 0x92, 0x0, 0x20, 0x1C, 0x0, 0xFF, 0x30, 0x15, 0x30, 0xA8, 0x60, 0xC0, 0x18, 0x2, 0xE8, +0x60, 0x80, 0x18, 0x28, 0x61, 0x19, 0x5, 0xF3, 0x0, 0xF8, 0xE0, 0x79, 0x0, 0xF0, 0xD2, 0xF8, 0x60, 0x0, 0x79, 0x28, 0x71, 0x20, 0x79, 0x28, 0x76, 0x80, 0x0, 0x7, 0xC0, 0xF, 0x68, 0x76, 0xA0, 0x79, 0x68, +0x0, 0x71, 0x1, 0x20, 0xA8, 0x71, 0x29, 0x21, 0x68, 0x8, 0x54, 0x0, 0xF0, 0xBE, 0xA, 0x1B, 0xF, 0x30, 0x3B, 0x0, 0x1C, 0xC, 0x34, 0x21, 0x78, 0x1, 0x70, 0x28, 0x0, 0x30, 0x1, 0x34, 0x1, 0x3B, 0xF9, 0xD1, +0x20, 0x3, 0x34, 0xE4, 0x1B, 0x30, 0x1C, 0x2, 0x0, 0x17, 0x90, 0x15, 0x27, 0xF0, 0xBC, 0x13, 0xE9, 0x0, 0x0, 0x1F, 0x6B, 0x11, 0x53, 0x6, 0x7F, 0x7D, 0x80, 0x51, 0x87, 0x12, 0x97, 0x11, 0x63, 0x11, 0x77, +0x11, 0x73, 0xF0, 0xA, 0x1B, 0x40, 0x60, 0x10, 0x23, 0xB5, 0x20, 0xB4, 0x39, 0x4D, 0x29, 0x6D, 0x20, 0xF, 0x97, 0x8, 0xF7, 0x0, 0x0, 0x77, 0x12, 0x69, 0x20, 0x20, 0x49, 0xE, 0x33, 0x49, 0x29, 0x20, 0xF, +0xB7, 0xA, 0x73, 0x2, 0x95, 0x71, 0x3, 0x70, 0x47, 0x2F, 0x48, 0x80, 0x79, 0x50, 0x5, 0x53, 0xB3, 0x2, 0x2A, 0x49, 0x34, 0x22, 0x88, 0x52, 0x70, 0xF, 0x27, 0x94, 0x40, 0xF, 0x0, 0xB5, 0x3, 0xAB, 0x78, +0x17, 0x9F, 0x23, 0x4D, 0x41, 0x24, 0x1, 0x13, 0x4, 0xE0, 0x20, 0x4D, 0x23, 0x1, 0x27, 0x71, 0x23, 0x1, 0x27, 0x10, 0x65, 0x10, 0xDD, 0xFF, 0xF7, 0xE, 0x24, 0x13, 0x0, 0x30, 0xB5, 0x19, 0x4D, 0x1, 0xB4, +0xFF, 0xF7, 0x6A, 0x7, 0x14, 0x21, 0xA, 0xFB, 0x30, 0x23, 0xC7, 0x20, 0x5, 0xFD, 0xC9, 0x26, 0x2, 0x88, 0x9, 0x7F, 0x8, 0x1C, 0x1B, 0xD9, 0x0, 0x9, 0xDA, 0x11, 0x8, 0x1C, 0x14, 0x4, 0x23, 0xD, 0x4D, 0xF, +0x22, 0xCF, 0x23, 0xE8, 0x79, 0x3B, 0xF, 0x31, 0xF8, 0x20, 0xF0, 0x31, 0x60, 0x31, 0x7F, 0x9, 0x4, 0x55, 0x30, 0x1F, 0x12, 0x63, 0x10, 0xF7, 0x12, 0x6F, 0x10, 0xFB, 0x51, 0xB, 0x50, 0x44, 0x3, 0xBB, 0x48, +0x11, 0x13, 0xB5, 0x12, 0x49, 0x0, 0x1, 0x20, 0x8, 0x70, 0xFF, 0xF7, 0xA0, 0xFF, 0x34, 0x4B, 0x0, 0xFF, 0x20, 0xA8, 0x76, 0x0, 0x20, 0xE8, 0x76, 0x0, 0x70, 0x47, 0xE8, 0x71, 0xB, 0x49, 0x9, 0x78, 0x6, +0x0, 0x29, 0xC, 0xD1, 0xA, 0x6, 0xD, 0x15, 0x5B, 0x9, 0x80, 0xB, 0xD3, 0x6, 0xDF, 0x40, 0x8, 0x40, 0x0, 0x2A, 0x4, 0x21, 0x68, 0x52, 0x2C, 0x21, 0x3, 0xE1, 0x3, 0x95, 0xCD, 0x8, 0xBD, 0x10, 0xD, 0x70, +0x47, 0x12, 0xD3, 0x10, 0x57, 0x24, 0x1, 0x8B, 0x0, 0x0, 0xB5, 0xA8, 0x70, 0x69, 0x69, 0xB, 0x1C, 0x2, 0x4C, 0x31, 0x9, 0x5C, 0xFE, 0x29, 0xA, 0xB5, 0x30, 0x1, 0xF6, 0xE7, 0xFF, 0x29, 0x16, 0xD1, 0x2E, +0x1, 0x75, 0x0, 0x1, 0x28, 0x0, 0xDA, 0xA, 0xE0, 0xFF, 0xF7, 0x4, 0x67, 0xFF, 0x2B, 0x20, 0x22, 0x12, 0x93, 0x2A, 0x3, 0x33, 0xD0, 0x21, 0x0, 0x69, 0x8, 0xD1, 0xFD, 0xA8, 0x0, 0xDF, 0x7, 0xB, 0x0, 0xBD, +0x68, 0x69, 0x0, 0x7A, 0xDD, 0xE7, 0x8, 0x0, 0x1C, 0x29, 0x69, 0x80, 0x0, 0x9, 0x58, 0xC9, 0x0, 0x18, 0xA, 0x78, 0xEA, 0x70, 0x0, 0x22, 0x2A, 0x0, 0x80, 0x2A, 0x77, 0x6A, 0x77, 0x24, 0x20, 0x1, 0x1, 0x31, +0x29, 0x50, 0x20, 0x20, 0x29, 0x50, 0x1, 0xBB, 0x3, 0x77, 0xE8, 0x77, 0x0, 0xBD, 0x13, 0x1, 0xA5, 0x1E, 0xB, 0x4, 0x70, 0x47, 0x11, 0x48, 0x12, 0xD, 0x27, 0x12, 0x48, 0x50, 0x4, 0x3, 0xFB, 0xC, 0xD, 0x1D, +0x1, 0x70, 0x0, 0xB5, 0x10, 0xB, 0x48, 0xF, 0x5, 0x65, 0x2A, 0x21, 0x41, 0x5A, 0x0, 0x2C, 0x22, 0x83, 0x5A, 0x49, 0x0, 0x5B, 0x18, 0x0, 0x83, 0x52, 0x1B, 0xC, 0x6, 0xD0, 0x8, 0xB4, 0x40, 0xA, 0x9, 0x45, +0xA7, 0xFD, 0x8, 0xBC, 0x1, 0x3B, 0xF, 0xF8, 0xDC, 0x0, 0xBD, 0x13, 0xC7, 0x13, 0x97, 0x12, 0x27, 0x13, 0xAF, 0xF1, 0x12, 0x2B, 0x13, 0xAF, 0x13, 0xA3, 0x13, 0x9B, 0x45, 0x46, 0x29, 0x7, 0x53, 0x0, 0x6A, +0x79, 0x91, 0x42, 0x7, 0xDB, 0x2A, 0x7F, 0x0, 0x0, 0x2A, 0x2, 0xD0, 0x1, 0x3A, 0x2A, 0x77, 0x20, 0x1, 0xE0, 0x5, 0xA7, 0xE0, 0x29, 0x70, 0x30, 0xE0, 0x60, 0x6A, 0x0, 0x13, 0xB, 0x47, 0x3A, 0x6A, 0x77, +0x0, 0xD0, 0x0, 0xF6, 0xE7, 0x29, 0x70, 0xA9, 0x7E, 0xFF, 0x29, 0x0, 0xC, 0xD0, 0xFF, 0x22, 0xAA, 0x76, 0x8, 0x1C, 0x0, 0xFF, 0xF7, 0x76, 0xFF, 0xE9, 0x7E, 0x0, 0x29, 0x80, 0x2, 0x6F, 0x22, 0xEA, 0x76, +0x0, 0xF0, 0xBF, 0xFC, 0x0, 0x18, 0xE0, 0x28, 0x23, 0xE9, 0x5C, 0x0, 0x29, 0x0, 0x8, 0xD0, 0x0, 0x21, 0xE9, 0x54, 0xA9, 0x7F, 0x0, 0x69, 0x70, 0x20, 0x23, 0xE9, 0x58, 0x24, 0x23, 0x5, 0xE9, 0x50, 0xB, +0xE0, 0x69, 0x7, 0xBB, 0xEA, 0xA, 0x81, 0x40, 0x91, 0x3, 0xD5, 0xA8, 0x78, 0x1, 0x30, 0xFF, 0xF7, 0x1, 0x57, 0xFF, 0x0, 0xE0, 0x69, 0x70, 0x4, 0xB, 0x65, 0x0, 0x0, 0x0, 0xF0, 0x7, 0xBD, 0xE8, 0x1, 0x0, +0x24, 0xBD, 0xE8, 0x19, 0x7B, 0x9C, 0x27, 0x38, 0xCF, 0x2, 0x3, 0xE2, 0xC, 0xE0, 0x8, 0xC7, 0xC, 0x8C, 0x8, 0x9, 0xA, 0x9, 0xC5, 0x0, 0x6C, 0x0, 0x1C, 0xBD, 0x9, 0x8E, 0xD, 0x30, 0x1E, 0xC, 0xB5, 0x4, +0x5, 0x38, 0x2, 0x2, 0x0, 0x21, 0x10, 0x1F, 0xC, 0xD9, 0xD, 0x0, 0xE, 0x80, 0xD, 0xCF, 0x42, 0x46, 0x12, 0x7E, 0x12, 0x9, 0x1, 0x0, 0xD2, 0x43, 0x4A, 0x0, 0xE0, 0x43, 0x4A, 0x12, 0x0, 0x5C, 0x1, 0x3A, +0x5, 0xD3, 0x17, 0x32, 0x0, 0x80, 0x1, 0xB1, 0xB9, 0x5C, 0x79, 0x71, 0xB9, 0x54, 0x70, 0x0, 0x47, 0x40, 0x46, 0x2, 0x78, 0x40, 0x69, 0x0, 0x0, 0x79, 0x0, 0x9, 0xF8, 0x78, 0x0, 0xD3, 0x86, 0x0, 0xE0, 0x40, +0x28, 0xC, 0xDD, 0x54, 0x28, 0xE, 0x0, 0xDD, 0x68, 0x28, 0x24, 0xDD, 0x7C, 0x28, 0x2E, 0x0, 0xDD, 0xC0, 0x28, 0x4A, 0xDD, 0xCA, 0x28, 0x52, 0x5, 0xDD, 0xD4, 0x28, 0x70, 0xDD, 0x8, 0xBF, 0x2A, 0xB, 0xB, +0x80, 0xC, 0x33, 0x0, 0x2A, 0xF8, 0xD1, 0xB9, 0x7B, 0x25, 0x1, 0x22, 0x4B, 0x28, 0x8, 0xDA, 0x41, 0x38, 0xB, 0x1F, 0x0, 0x5C, 0xB8, 0x54, 0x9, 0x18, 0x40, 0x29, 0x8, 0x2, 0xDB, 0x40, 0x21, 0x6, 0xE0, +0x4B, 0x50, 0x11, 0x1A, 0x30, 0x0, 0xD2, 0xC, 0x69, 0x20, 0x2F, 0xE0, 0xD0, 0xB9, 0x7B, 0x0, 0x5F, 0x28, 0x2, 0xDA, 0x25, 0x22, 0x55, 0x38, 0x0, 0xE6, 0xE7, 0x25, 0x22, 0x5F, 0x38, 0xEC, 0xE7, 0x88, 0x6, +0x3F, 0x2A, 0xF0, 0xD0, 0x9, 0x13, 0x1C, 0x10, 0x20, 0x0, 0x38, 0x58, 0x73, 0x29, 0x7, 0xDA, 0x69, 0x39, 0x1, 0x89, 0x0, 0x0, 0xD1, 0x79, 0x7E, 0x79, 0x1, 0x43, 0x4, 0xC7, 0xFB, 0x6, 0xE0, 0x73, 0x80, +0xF, 0xD9, 0xFB, 0x0, 0x10, 0x22, 0xB9, 0x58, 0xB8, 0x50, 0x40, 0x1A, 0x20, 0x2D, 0x18, 0x24, 0x15, 0x2A, 0xB6, 0xD1, 0x80, 0x38, 0x0, 0x80, 0x0, 0xFF, 0x28, 0x0, 0xDB, 0xFF, 0x20, 0x20, 0xB8, 0x70, 0x26, +0x8F, 0x2A, 0xFB, 0xD0, 0xC1, 0x38, 0x0, 0xA, 0x49, 0x8, 0x5C, 0x41, 0x46, 0x9, 0x7E, 0x8, 0x49, 0x8, 0x4, 0xD2, 0x16, 0xEB, 0xF8, 0x7D, 0xF8, 0x10, 0x75, 0x31, 0xE1, 0x16, 0xF5, 0x78, 0x7E, 0x78, 0x76, +0x5, 0xF8, 0x75, 0x2B, 0xE1, 0xCB, 0x1, 0x57, 0xAC, 0x1, 0x5B, 0x21, 0xC, 0x29, 0x9, 0xBF, 0x1, 0x4, 0x8, 0x10, 0xE, 0x9A, 0x20, 0x80, 0xFF, 0x10, 0x8F, 0x4, 0xD0, 0xCB, 0x38, 0x1, 0x1, 0xD0, 0x80, 0x0, +0x38, 0x73, 0x72, 0xE1, 0x9, 0xAF, 0x0, 0x28, 0x11, 0xD0, 0x50, 0x28, 0xB, 0xDD, 0x80, 0x0, 0x28, 0xF, 0xDB, 0xA0, 0x28, 0x2B, 0xDB, 0xC0, 0x0, 0x28, 0x35, 0xDB, 0xD0, 0x28, 0x43, 0xDB, 0xF0, 0x4, 0x28, +0x4D, 0xDB, 0x72, 0xE0, 0x10, 0xBF, 0x1, 0xD1, 0x34, 0x10, 0x38, 0x1D, 0x45, 0x10, 0xCB, 0x8A, 0x0, 0xE3, 0x23, 0x23, 0x8, 0xFA, 0x5C, 0x70, 0x28, 0x9, 0x1E, 0x38, 0x3, 0xD1, 0x80, 0xC, 0xCB, 0x7, 0x0, +0xF, 0x3, 0xE0, 0x12, 0x9, 0x0, 0x12, 0x1, 0x2, 0x43, 0xFA, 0x54, 0x76, 0xE7, 0x10, 0x70, 0x38, 0x2, 0x10, 0x15, 0x9, 0x5, 0xE0, 0x12, 0x8, 0x7, 0x12, 0xF, 0x0, 0x0, 0x15, 0x0, 0x9, 0xFA, 0x2A, 0x54, +0x61, 0xD, 0xC1, 0xDD, 0x1, 0x4F, 0x24, 0x0, 0x3B, 0x90, 0x0, 0x28, 0x1, 0xDA, 0x80, 0x38, 0xE0, 0xE7, 0x90, 0x20, 0x38, 0xE9, 0x21, 0x1F, 0xB, 0xD0, 0xB0, 0x28, 0x4, 0x20, 0xDA, 0xA0, 0x0, 0xE7, 0x0, +0xD0, 0x38, 0x73, 0x28, 0x8, 0xE1, 0xB0, 0x38, 0xC0, 0x0, 0x9, 0xF8, 0x72, 0x23, 0xC0, 0x0, 0x9D, 0x11, 0x3F, 0x7, 0xD1, 0xC0, 0x38, 0x0, 0x1, 0x70, 0xF0, 0x4, 0xD1, 0x11, 0x1, 0x91, 0x7, 0xBA, 0x78, +0xBB, 0x7F, 0x0, 0xE0, 0x28, 0xE, 0xDA, 0xD0, 0x38, 0x1, 0xD1, 0x45, 0x18, 0x0, 0x71, 0x1B, 0x7, 0x1B, 0x0, 0x71, 0x3, 0x0, 0x71, 0x0, 0xBB, 0x77, 0x80, 0x0, 0x12, 0x1A, 0xF, 0xD2, 0x5, 0x0, 0x22, 0xD, +0xE0, 0xE0, 0x0, 0x91, 0x18, 0x20, 0xA5, 0x18, 0x1B, 0x9, 0x1B, 0x0, 0x1D, 0x20, 0x1B, 0x18, 0xFF, 0x2A, 0x91, 0x1, 0x53, 0x22, 0xBA, 0x41, 0x53, 0x7, 0xD0, 0xF0, 0x0, 0x63, 0x0, 0x1, 0xD0, 0x25, 0x21, +0x78, 0x54, 0x78, 0x5C, 0x10, 0x1, 0x1C, 0x8D, 0x6, 0x35, 0x0, 0xB5, 0x38, 0x79, 0x20, 0x79, 0x79, 0xC, 0x87, 0xFE, 0x40, 0x0, 0x4, 0xBC, 0x40, 0x96, 0x12, 0x69, 0x78, 0x0, 0x2A, 0x78, 0x44, 0x87, 0x0, +0x46, 0x23, 0xE0, 0x1D, 0xE0, 0x22, 0xE0, 0x25, 0x2, 0xE0, 0x2E, 0xE0, 0x35, 0xE0, 0x34, 0xE, 0xDF, 0xC0, 0x0, 0xE0, 0x1A, 0xE0, 0xF4, 0xE0, 0x15, 0xE1, 0x1E, 0x0, 0xE1, 0x29, 0xE1, 0x2E, 0xE1, 0x35, +0xE1, 0x13, 0x0, 0xE0, 0x43, 0xE1, 0x84, 0xE1, 0x9D, 0xE1, 0x4C, 0x0, 0xE2, 0x6F, 0xE2, 0x7C, 0xE2, 0x89, 0xE2, 0x9A, 0x0, 0xE2, 0x9D, 0xE2, 0x9E, 0xE2, 0x9F, 0xE2, 0xA2, 0x0, 0xE2, 0xAB, 0xE2, 0xAE, +0xE2, 0xC0, 0x46, 0x3, 0x42, 0xD1, 0x2, 0x9F, 0xD0, 0x40, 0x46, 0x41, 0x5, 0x9F, 0x1, 0xA, 0xD1, 0x40, 0x46, 0x81, 0x4, 0xAB, 0x7, 0x0, 0x7, 0xC1, 0x23, 0x76, 0x81, 0x3, 0x71, 0x2, 0xD1, 0x81, 0xA, 0xF9, +0x10, 0x13, 0x0, 0x0, 0xB5, 0xB8, 0x7B, 0x0, 0xF0, 0x20, 0xFB, 0x31, 0xB8, 0x73, 0x1A, 0xD, 0x18, 0x8B, 0x0, 0x23, 0x8, 0x1, 0x5B, 0x0, 0xE, 0x28, 0x5, 0xD1, 0x0, 0x2A, 0x25, 0xD1, 0x0, 0x9, 0x7, 0x9, +0xF, 0x1, 0x23, 0x8, 0xE0, 0x14, 0xF, 0x28, 0x4, 0x0, 0xF, 0x1D, 0x30, 0xF, 0xE0, 0x0, 0x0, 0x2A, 0x18, 0xD0, 0x38, 0x79, 0x10, 0x22, 0x5, 0x0, 0x28, 0xB8, 0x58, 0x7, 0xD1, 0x0, 0x2B, 0x2, 0x0, 0xD1, +0x0, 0xF0, 0x92, 0xFA, 0x9, 0xE0, 0x0, 0x4, 0xF0, 0xD3, 0xFA, 0x6, 0xE0, 0x30, 0xF, 0xA4, 0xFA, 0x80, 0x3, 0xF5, 0xF0, 0xC1, 0xFA, 0x10, 0x22, 0x39, 0x69, 0x28, 0x38, 0x61, 0x52, 0x6F, 0x10, 0x0, 0x8B, +0x0, 0x7E, 0x40, 0xE0, 0xD, 0x93, 0x13, 0x3F, 0x2, 0xA3, 0x71, 0x79, 0x76, 0xF9, 0x75, 0x20, 0x5, 0xE0, 0x13, 0x4D, 0xF9, 0x7D, 0x79, 0x71, 0xF9, 0x40, 0x75, 0x1B, 0xDF, 0xF9, 0x7D, 0x2, 0xB4, 0x0, 0x2E, +0x10, 0x1, 0xD1, 0xA, 0x1B, 0xD7, 0x7D, 0x1, 0x38, 0x41, 0x2, 0x46, 0x4A, 0x69, 0xC9, 0x68, 0x80, 0xF, 0x23, 0x80, 0x20, 0x18, 0x41, 0xB, 0x49, 0xFA, 0x79, 0x34, 0x4B, 0xFF, 0x0, 0xF7, 0x5E, 0xFB, 0x2, +0xBC, 0x1, 0xB4, 0x3, 0x4, 0x1C, 0x10, 0x22, 0xB8, 0x58, 0x13, 0xA3, 0xD2, 0x8, 0x0, 0x19, 0xD3, 0x98, 0x42, 0x3, 0xDB, 0x9, 0xDC, 0x40, 0x1, 0x29, 0xF1, 0x0, 0xF0, 0x62, 0xFA, 0x2, 0xBC, 0x49, 0x88, +0x4, 0x89, 0x8, 0x1C, 0x0, 0x61, 0xF0, 0x41, 0x20, 0xD, 0x1C, 0x0, 0xDC, 0x8, 0x0, 0x31, 0x53, 0x3, 0x15, 0xCD, 0x98, 0x42, 0x15, 0xA, 0xDB, 0x2, 0x60, 0x33, 0x48, 0x20, 0x33, 0xED, 0x0, 0x25, 0x5, 0xEB, +0xE7, 0x0, 0xF0, 0x27, 0x20, 0x41, 0xE6, 0x0, 0x41, 0x2, 0xE4, 0xE7, 0xC, 0xD1, 0x8, 0x9, 0x32, 0xD5, 0x8, 0x0, 0x7, 0x5, 0xD0, 0x80, 0xE, 0x41, 0x46, 0x49, 0x2, 0x7E, 0x88, 0x40, 0xF8, 0x72, 0x0, 0x7, +0xFF, 0x40, 0x0, 0x46, 0x1, 0x78, 0x40, 0x7E, 0x0, 0x28, 0x4, 0x21, 0xD0, 0x0, 0x1, 0x5D, 0x0, 0xB5, 0x79, 0x7B, 0x1, 0x7, 0x0, 0xB5, 0x38, 0x7B, 0x79, 0x7B, 0x9, 0x18, 0x9, 0x0, 0x6, 0x9, 0xE, 0x79, +0x73, 0x9, 0x4A, 0x51, 0x1, 0x56, 0xF8, 0x7A, 0x41, 0x43, 0x9, 0x12, 0xC, 0x89, 0x0, 0x29, 0x2, 0xDB, 0x0, 0xF0, 0x13, 0xFA, 0x2, 0x0, 0xE0, 0x49, 0x42, 0x0, 0xF0, 0xF5, 0xF9, 0x5, 0x4B, 0x1C, 0x1B, 0x8B, +0xC, 0xF, 0xA, 0x33, 0x37, 0x8, 0xDF, 0xA, 0x13, 0x80, 0xC, 0xC5, 0x20, 0xB8, 0x71, 0x0, 0x2E, 0x5, 0xD0, 0x3, 0xB8, 0x79, 0x1, 0x28, 0x13, 0xDC, 0x5, 0x47, 0x0, 0xF, 0xC0, 0xB, 0xCD, 0x0, 0x15, 0x28, +0x1C, 0x9, 0x9, 0x2A, 0x1C, 0x82, 0x3, 0x75, 0xDB, 0x52, 0x19, 0x9, 0x1, 0xC, 0xD7, 0xB5, 0x1F, 0x0, 0xF0, 0xF2, 0x40, 0x43, 0x10, 0x35, 0x0, 0x1F, 0x1, 0xB5, 0x18, 0x8D, 0x40, 0x6, 0x7, 0x3D, 0xB2, 0xFF, +0x6, 0xBC, 0x0, 0x2A, 0x18, 0xFF, 0xF7, 0xA, 0x2B, 0x67, 0x10, 0x13, 0xF9, 0x7D, 0xFF, 0x28, 0xF7, 0x3B, 0x40, 0x15, 0xFF, 0x2A, 0x2D, 0xC0, 0x46, 0x2, 0x2, 0xD1, 0x40, 0x29, 0x0, 0xDC, 0xF9, 0x33, 0x83, +0xB5, 0x46, 0xF8, 0x2, 0x13, 0x16, 0xFA, 0xF8, 0x42, 0x13, 0x6, 0x99, 0x48, 0x4, 0x41, 0x72, 0x70, 0x47, 0x28, 0x28, 0x17, 0xFF, 0x20, 0x0, 0x1, 0xB4, 0xB8, 0x78, 0x0, 0xF0, 0x8, 0xFA, 0x28, 0xB8, 0x70, +0x32, 0x33, 0xB8, 0x7, 0x6F, 0x4, 0xD1, 0x8, 0x90, 0x3, 0xA5, 0x1, 0x30, 0x10, 0xA3, 0x1, 0x38, 0x1, 0x28, 0x0, 0xFA, 0xD1, 0xBA, 0x7B, 0x8, 0x9, 0x11, 0xD0, 0x0, 0x5, 0x28, 0x10, 0xDD, 0x6, 0x28, 0x15, +0xD0, 0x0, 0x7, 0x28, 0x17, 0xD0, 0x8, 0x28, 0x9, 0xD0, 0x0, 0xD, 0x28, 0x15, 0xDD, 0xE, 0x28, 0x1B, 0xD0, 0x0, 0xF, 0x28, 0xFF, 0xD0, 0x52, 0x0, 0x40, 0x2A, 0x2, 0x19, 0xDB, 0x40, 0x22, 0x17, 0xE0, 0x0, +0x31, 0x23, 0x4, 0x83, 0x40, 0xD2, 0x1A, 0x12, 0x3, 0x4D, 0x10, 0xE0, 0x20, 0xAB, 0x20, 0x1D, 0x1B, 0xC, 0xE0, 0x52, 0x8, 0xA, 0x21, 0xE0, 0x9, 0x30, 0x19, 0x18, 0x40, 0x2A, 0x4, 0x0, 0x29, 0x10, 0x2, +0xE0, 0xC0, 0x0, 0x1B, 0xD2, 0x9, 0xBA, 0x73, 0x0, 0x0, 0x2E, 0xC6, 0xD0, 0xF0, 0x7D, 0x4, 0x22, 0x5, 0x10, 0x43, 0xF0, 0x75, 0xC1, 0x5, 0x3, 0x4, 0x1, 0x27, 0x10, 0xB, 0x9, 0x9B, 0x9, 0x95, 0xB8, 0x71, +0xB8, 0x79, 0xD, 0x7, 0x4B, 0x18, 0x56, 0x12, 0xB9, 0xD, 0x53, 0x11, 0x14, 0xC3, 0x0, 0x9, 0x9, 0x0, 0xD2, 0x40, 0x10, 0x2, 0x49, 0x78, 0x88, 0x0, 0xC5, 0x4, 0x2, 0x1, 0x63, 0x10, 0xCB, 0x8, 0x9, 0x40, +0x40, 0x0, 0x33, 0x6D, 0xF, 0xE0, 0x18, 0xE0, 0x20, 0xE0, 0x40, 0x32, 0x40, 0x1, 0x37, 0xE0, 0x53, 0xE0, 0x55, 0xE0, 0x40, 0x58, 0x0, 0x1, 0x71, 0xE0, 0x77, 0xE0, 0x7F, 0xE0, 0x42, 0x88, 0x9, 0xDF, 0x7, +0xD1, 0xB8, 0x7B, 0x13, 0xB, 0x40, 0x25, 0x18, 0x40, 0x5, 0x29, 0x40, 0x20, 0x14, 0xAD, 0x6, 0x50, 0x13, 0xD6, 0x15, 0xA1, 0x20, 0x11, 0x3, 0x23, 0x2F, 0xB9, 0x9, 0x13, 0x1, 0xB5, 0x38, 0x62, 0x8, 0x21, +0x13, 0x11, 0xC5, 0x3, 0xD0, 0xF1, 0x0, 0xAB, 0x11, 0x1E, 0x43, 0xF1, 0x75, 0x11, 0xC3, 0x30, 0x1, 0x30, 0x2B, 0x2, 0x37, 0x77, 0x10, 0x70, 0x47, 0x1A, 0x23, 0x67, 0x2, 0x29, 0x4, 0xDD, 0x1, 0x6, 0x29, +0x3, 0xDD, 0x8, 0x29, 0x9, 0x6, 0x25, 0x80, 0x0, 0x4D, 0x39, 0x3A, 0x7D, 0x92, 0x6, 0x92, 0xE, 0x4, 0x89, 0x1, 0xA, 0x43, 0x3A, 0x13, 0x17, 0x2E, 0x6, 0x0, 0xD0, 0xF2, 0x7D, 0x20, 0x20, 0x82, 0x43, 0x7, +0x28, 0x39, 0x49, 0x0, 0x13, 0xF2, 0x3, 0x2B, 0x9, 0x1, 0xB9, 0x84, 0x5, 0xB3, 0x91, 0x29, 0x0, 0xD0, 0x30, 0x57, 0x15, 0xD1, 0x20, 0x42, 0x46, 0x13, 0xB3, 0x6, 0xD1, 0x51, 0x78, 0x91, 0x0, 0x77, 0x8, +0x49, 0x49, 0x68, 0x20, 0x23, 0xD1, 0x4, 0x50, 0x70, 0x47, 0xD0, 0x7F, 0x9, 0xAF, 0xD1, 0xD1, 0x24, 0x77, 0x2, 0x1, 0x6B, 0xD0, 0x77, 0x12, 0x4D, 0x28, 0x23, 0x73, 0xD0, 0x6, 0xB9, 0x11, 0xD3, 0x13, 0xE3, +0x91, 0x42, 0x22, 0x71, 0x6, 0x95, 0xC0, 0x16, 0xCB, 0x13, 0xF5, 0x8A, 0x42, 0x1, 0xDA, 0xD, 0x48, 0x56, 0xC1, 0x1, 0xF7, 0x7, 0x40, 0xA9, 0x42, 0x7, 0xBB, 0x8, 0xA5, 0x31, 0x5A, 0x41, 0x0, 0xB1, 0xFD, +0x2, 0xE3, 0x14, 0x1B, 0x5, 0x28, 0x9B, 0x2, 0x1, 0xD0, 0x2A, 0x20, 0xFF, 0xF7, 0x95, 0xF9, 0x3A, 0x67, 0xC0, 0x12, 0x27, 0x1B, 0xEF, 0x20, 0x29, 0x12, 0xDA, 0x0, 0x2A, 0x40, 0x1B, 0x4, 0x85, 0xC2, 0x79, +0x10, 0x29, 0x5, 0xDA, 0x0, 0x52, 0x1A, 0x20, 0x2A, 0x0, 0xDA, 0x20, 0x22, 0xA, 0x10, 0x1C, 0x9, 0xE0, 0x14, 0x57, 0x52, 0x5, 0x21, 0xF8, 0xB0, 0x5, 0x21, 0xF6, 0x5, 0xB9, 0x1, 0x2B, 0x1C, 0x20, 0xB5, +0x45, 0x26, 0x46, 0x3, 0x8, 0x6D, 0x70, 0xF9, 0x39, 0x97, 0x11, 0xAB, 0x5, 0xB4, 0xC, 0x17, 0xA, 0x83, 0x77, 0x3, 0x5F, 0xF, 0x53, 0x77, 0x44, 0xE6, 0x10, 0xC0, 0x46, 0xB, 0x4, 0xDB, 0x2, 0x7E, 0x28, +0x23, 0x31, 0x1A, 0x42, 0x4, 0xED, 0xF, 0x7D, 0x80, 0x22, 0x91, 0xC, 0xA9, 0x12, 0x11, 0x1C, 0x1, 0xA, 0x97, 0x0, 0xB5, 0x14, 0x6B, 0x0, 0x83, 0x7, 0xB9, 0x80, 0x20, 0x0, 0xE0, 0x40, 0x2, 0xB7, 0x4, 0x7B, +0x81, 0xB, 0x59, 0xAB, 0xF8, 0x41, 0x46, 0x8, 0x71, 0x44, 0xEF, 0x4E, 0xD1, 0x11, 0x3F, 0xC0, 0x46, 0x50, 0x3, 0x0, 0xF, 0x26, 0x87, 0x91, 0x60, 0x42, 0x4, 0xFF, 0x1, 0xB7, 0xF0, 0x7D, 0x1, 0x21, 0x88, +0xCE, 0x2, 0x63, 0x43, 0x93, 0x2E, 0xFF, 0x1, 0x67, 0x19, 0x43, 0x12, 0xF3, 0xE, 0x0, 0xD1, 0x78, 0x7D, 0x6, 0x23, 0x58, 0x40, 0x78, 0x0, 0x75, 0xC0, 0x8, 0x3, 0xD3, 0x9, 0x9, 0x1, 0xD, 0x31, 0xB9, 0x71, +0x6, 0x20, 0xD9, 0x10, 0x9, 0x1, 0x1, 0x69, 0x0, 0xB8, 0x71, 0x7A, 0x7D, 0xD2, 0x8, 0x2, 0xD2, 0x6, 0xC0, 0x21, 0x27, 0x4A, 0x91, 0x3, 0x41, 0x38, 0x4B, 0xD2, 0x4, 0x8, 0xE, 0xD3, 0x3, 0xE0, 0x54, 0xB1, +0x22, 0x4A, 0x0, 0x49, 0x0, 0x51, 0x5A, 0x40, 0x9, 0x48, 0x43, 0x22, 0xC0, 0xA, 0x9, 0x9F, 0xDA, 0x0, 0x20, 0x11, 0xD5, 0x40, 0x8, 0x18, 0x41, 0xD, 0xFA, 0x3, 0xF3, 0x40, 0x5, 0xF4, 0x50, 0xE7, 0x34, +0xDB, 0x15, 0x60, 0x33, 0xE5, 0xD3, 0x16, 0x4A, 0x12, 0x3, 0x1C, 0xC0, 0x3, 0xFF, 0xDB, 0x18, 0x70, 0x3B, 0xC0, 0x4, 0x18, 0x1, 0x1C, 0x49, 0xD, 0x1B, 0x93, 0x40, 0x5, 0x98, 0x20, 0x41, 0x1A, 0xFB, 0x2, +0x95, 0x70, 0x73, 0x2, 0xD3, 0x9, 0x83, 0x0, 0x35, 0xE6, 0xE7, 0x89, 0x0, 0xF1, 0x8, 0x33, 0x35, 0x2F, 0x4, 0x1, 0xD3, 0x5, 0x4A, 0xBF, 0x0, 0x11, 0xC7, 0xE7, 0x96, 0x13, 0xDB, 0xAC, 0x33, 0xD, 0x97, +0x31, 0xE, 0xC3, 0x4, 0x83, 0xB0, 0x9C, 0x4, 0x87, 0x0, 0x29, 0x1A, 0x2D, 0x1, 0xBD, 0x29, 0x65, 0xF9, 0xDA, 0x1, 0x41, 0x70, 0x80, 0xB5, 0x4, 0x4F, 0x2, 0xB, 0x91, 0x22, 0x9E, 0xF8, 0x5, 0x79, 0x39, +0xF9, 0xD1, 0x3C, 0x57, 0x44, 0x0, 0xA, 0x0, 0x3, 0x40, 0x23, 0x8, 0xB4, 0x43, 0x0, 0x46, 0x1B, 0x7E, 0x1B, 0x9, 0x2B, 0xD2, 0xF, 0x88, 0x0, 0x37, 0x15, 0xE0, 0xF0, 0x15, 0x7, 0x2A, 0x22, 0xD1, 0x1, 0x4, +0xE0, 0xB, 0x1C, 0x1B, 0x7, 0x8, 0x6, 0x4D, 0xD, 0x1C, 0xD0, 0x9, 0x9, 0xF, 0xA1, 0x5, 0x91, 0x18, 0x5, 0x91, 0x51, 0x16, 0x10, 0x17, 0x9, 0x6, 0x3D, 0x2A, 0x10, 0xD0, 0x33, 0x45, 0x52, 0xC, 0x3, 0x45, +0xA, 0x6, 0x5B, 0x8, 0xD1, 0x10, 0x31, 0x1B, 0x4, 0xF, 0xF, 0x2B, 0xE6, 0xD0, 0x10, 0x23, 0xF, 0x2B, 0x19, 0xEE, 0xD0, 0x2, 0xD, 0xA5, 0x18, 0x97, 0xB, 0x9, 0x16, 0x91, 0x14, 0x5B, 0x1A, 0xC0, 0x20, 0x47, +0x0, 0x5, 0xD9, 0x0, 0x28, 0x20, 0xF1, 0xDC, 0x30, 0xE7, 0x80, 0x35, 0x80, 0x32, 0xA0, 0x0, 0x2F, 0x0, 0x2D, 0x60, 0x2A, 0x0, 0x28, 0xC0, 0x0, 0x25, 0xA0, 0x23, 0xA0, 0x21, 0xC0, 0x1F, 0x0, 0x0, 0x1E, +0x58, 0x1C, 0x0, 0x0, 0xED, 0x0, 0xDB, 0x0, 0x1, 0xCA, 0x2, 0xB9, 0x3, 0xAA, 0x4, 0x9B, 0x0, 0x5, 0x8D, 0x6, 0x80, 0x7, 0x74, 0x8, 0x69, 0x0, 0x9, 0x5F, 0xA, 0x56, 0xB, 0x4D, 0xC, 0x45, 0x0, 0xD, 0x3F, +0xE, 0x39, 0xF, 0x34, 0x10, 0x30, 0x0, 0x11, 0x2D, 0x12, 0x2B, 0x13, 0x25, 0x14, 0x29, 0x0, 0x15, 0x2A, 0x16, 0x2C, 0x17, 0x2E, 0x18, 0x31, 0x0, 0x19, 0x36, 0x1A, 0x3B, 0x1B, 0x41, 0x1C, 0x48, 0x0, 0x1D, +0x51, 0x1E, 0x5A, 0x1F, 0x64, 0x20, 0x6F, 0x0, 0x21, 0x5B, 0x1F, 0x88, 0x23, 0x96, 0x24, 0xA4, 0x0, 0x25, 0xB4, 0x26, 0xC5, 0x27, 0xD7, 0x28, 0xEA, 0x0, 0x29, 0xFE, 0x2A, 0x13, 0x2C, 0x28, 0x2D, 0x3F, +0x0, 0x2E, 0x57, 0x2F, 0x70, 0x30, 0x8A, 0x31, 0xA5, 0x0, 0x32, 0xC1, 0x33, 0xDD, 0x34, 0xFB, 0x35, 0x1A, 0x0, 0x37, 0x3A, 0x38, 0x5C, 0x39, 0x7E, 0x3A, 0xA1, 0x0, 0x3B, 0xC5, 0x3C, 0xEA, 0x3D, 0x11, +0x3F, 0x38, 0x0, 0x40, 0x61, 0x41, 0x8A, 0x42, 0xB5, 0x43, 0xE1, 0x0, 0x44, 0xD, 0x46, 0x3B, 0x47, 0x6A, 0x48, 0x9A, 0x0, 0x49, 0xCB, 0x4A, 0xFE, 0x4B, 0x31, 0x4D, 0x66, 0x0, 0x4E, 0x9B, 0x4F, 0xD2, 0x50, +0xA, 0x52, 0x43, 0x0, 0x53, 0x7D, 0x54, 0xB8, 0x55, 0xF4, 0x56, 0x32, 0x0, 0x58, 0x71, 0x59, 0xB0, 0x5A, 0xF1, 0x5B, 0x34, 0x0, 0x5D, 0x77, 0x5E, 0xBB, 0x5F, 0x1, 0x61, 0x48, 0x0, 0x62, 0x90, 0x63, 0xD9, +0x64, 0x24, 0x66, 0x6F, 0x0, 0x67, 0xBC, 0x68, 0xA, 0x6A, 0x59, 0x6B, 0xAA, 0x0, 0x6C, 0xFB, 0x6D, 0x4E, 0x6F, 0xA2, 0x70, 0xF7, 0x0, 0x71, 0x4E, 0x73, 0xA6, 0x74, 0xFF, 0x75, 0x59, 0x0, 0x77, 0xB4, 0x78, +0x10, 0x7A, 0x6F, 0x7B, 0xCF, 0x0, 0x7C, 0x2F, 0x7E, 0x91, 0x7F, 0xF4, 0x80, 0x59, 0x0, 0x82, 0xBE, 0x83, 0x25, 0x85, 0x8E, 0x86, 0xF7, 0x0, 0x87, 0x62, 0x89, 0xCE, 0x8A, 0x3C, 0x8C, 0xAB, 0x0, 0x8D, +0x1B, 0x8F, 0x8C, 0x90, 0xFF, 0x91, 0x73, 0x0, 0x93, 0xE9, 0x94, 0x60, 0x96, 0xD8, 0x97, 0x52, 0x0, 0x99, 0xCD, 0x9A, 0x49, 0x9C, 0xC7, 0x9D, 0x46, 0x0, 0x9F, 0xC6, 0xA0, 0x48, 0xA2, 0xCC, 0xA3, 0x50, +0x0, 0xA5, 0xD6, 0xA6, 0x5E, 0xA8, 0xE7, 0xA9, 0x71, 0x0, 0xAB, 0xFD, 0xAC, 0x8A, 0xAE, 0x19, 0xB0, 0xA9, 0x0, 0xB1, 0x3A, 0xB3, 0xCD, 0xB4, 0x62, 0xB6, 0xF7, 0x0, 0xB7, 0x8F, 0xB9, 0x2D, 0xBB, 0xC2, +0xBC, 0x5E, 0x0, 0xBE, 0xFB, 0xBF, 0x9A, 0xC1, 0x3A, 0xC3, 0xDC, 0x0, 0xC4, 0x7F, 0xC6, 0x24, 0xC8, 0xCA, 0xC9, 0x72, 0x0, 0xCB, 0x1B, 0xCD, 0xC6, 0xCE, 0x73, 0xD0, 0x21, 0x0, 0xD2, 0xD0, 0xD3, 0x82, +0xD5, 0x34, 0xD7, 0xE9, 0x0, 0xD8, 0x9E, 0xDA, 0x56, 0xDC, 0xF, 0xDE, 0xC9, 0x0, 0xDF, 0x86, 0xE1, 0x43, 0xE3, 0x3, 0xE5, 0xC4, 0x0, 0xE6, 0x87, 0xE8, 0x4B, 0xEA, 0x11, 0xEC, 0xD9, 0x0, 0xED, 0xA2, 0xEF, +0x6D, 0xF1, 0x39, 0xF3, 0x7, 0x0, 0xF5, 0xD7, 0xF6, 0xA9, 0xF8, 0x7C, 0xFA, 0x51, 0x0, 0xFC, 0x28, 0xFE, 0x0, 0x0, 0xDA, 0x1, 0xB6, 0x0, 0x3, 0x93, 0x5, 0x72, 0x7, 0x53, 0x9, 0x36, 0x0, 0xB, 0x1B, 0xD, +0x1, 0xF, 0xE7, 0x10, 0xD2, 0x0, 0x12, 0xBE, 0x14, 0xAB, 0x16, 0x9A, 0x18, 0x8B, 0x0, 0x1A, 0x7E, 0x1C, 0x72, 0x1E, 0x68, 0x20, 0x60, 0x0, 0x22, 0x5A, 0x24, 0x56, 0x26, 0x53, 0x28, 0x53, 0x0, 0x2A, 0x54, +0x2C, 0x57, 0x2E, 0x5C, 0x30, 0x63, 0x0, 0x32, 0x6B, 0x34, 0x76, 0x36, 0x83, 0x38, 0x91, 0x0, 0x3A, 0xA1, 0x3C, 0xB3, 0x3E, 0xC7, 0x40, 0xDD, 0x0, 0x42, 0xF5, 0x44, 0xF, 0x47, 0x2B, 0x49, 0x49, 0x0, 0x4B, +0x69, 0x4D, 0x8A, 0x4F, 0xAE, 0x51, 0xD4, 0x0, 0x53, 0xFB, 0x55, 0x25, 0x58, 0x51, 0x5A, 0x7E, 0x0, 0x5C, 0xAE, 0x5E, 0xE0, 0x60, 0x13, 0x63, 0x49, 0x0, 0x65, 0x99, 0x63, 0xBB, 0x69, 0xF7, 0x6B, 0x35, +0x0, 0x6E, 0x75, 0x70, 0xB7, 0x72, 0xFB, 0x74, 0x42, 0x0, 0x77, 0x8A, 0x79, 0xD5, 0x7B, 0x21, 0x7E, 0x70, 0x0, 0x80, 0xC1, 0x82, 0x14, 0x85, 0xC0, 0x46, 0xFF, 0x0, 0xFF, 0x14, 0xFF, 0x29, 0xFE, 0x3E, +0xFD, 0x54, 0x0, 0xFC, 0x6C, 0xFB, 0x84, 0xFA, 0x9D, 0xF9, 0xB6, 0x0, 0xF8, 0xD1, 0xF7, 0xEC, 0xF6, 0x8, 0xF6, 0x25, 0x0, 0xF5, 0x43, 0xF4, 0x62, 0xF3, 0x81, 0xF2, 0xA2, 0x0, 0xF1, 0xC3, 0xF0, 0xE5, 0xEF, +0x7, 0xEF, 0x2B, 0x0, 0xEE, 0x4F, 0xED, 0x74, 0xEC, 0x9A, 0xEB, 0xC1, 0x0, 0xEA, 0xE8, 0xE9, 0x10, 0xE9, 0x39, 0xE8, 0x63, 0x0, 0xE7, 0x8E, 0xE6, 0xB9, 0xE5, 0xE5, 0xE4, 0x12, 0x0, 0xE4, 0x40, 0xE3, 0x6E, +0xE2, 0x9D, 0xE1, 0xCD, 0x0, 0xE0, 0xFD, 0xDF, 0x2F, 0xDF, 0x61, 0xDE, 0x94, 0x0, 0xDD, 0xC7, 0xDC, 0xFC, 0xDB, 0x31, 0xDB, 0x67, 0x0, 0xDA, 0x9D, 0xD9, 0xD4, 0xD8, 0xC, 0xD8, 0x45, 0x0, 0xD7, 0x7E, 0xD6, +0xB9, 0xD5, 0xF3, 0xD4, 0x2F, 0x0, 0xD4, 0x6B, 0xD3, 0xA8, 0xD2, 0xE6, 0xD1, 0x24, 0x0, 0xD1, 0x63, 0xD0, 0xA3, 0xCF, 0xE3, 0xCE, 0x25, 0x0, 0xCE, 0x66, 0xCD, 0xA9, 0xCC, 0xEC, 0xCB, 0x30, 0x0, 0xCB, +0x75, 0xCA, 0xBA, 0xC9, 0x0, 0xC9, 0x46, 0x0, 0xC8, 0x8D, 0xC7, 0xD5, 0xC6, 0x1E, 0xC6, 0x67, 0x0, 0xC5, 0xB1, 0xC4, 0xFC, 0xC3, 0x47, 0xC3, 0x93, 0x0, 0xC2, 0xDF, 0xC1, 0x2C, 0xC1, 0x7A, 0xC0, 0xC9, +0x0, 0xBF, 0x18, 0xBF, 0x67, 0xBE, 0xB8, 0xBD, 0x9, 0x0, 0xBD, 0x0, 0xBC, 0xAC, 0xBB, 0xFF, 0xBA, 0x53, 0x0, 0xBA, 0xA7, 0xB9, 0xFC, 0xB8, 0x51, 0xB8, 0xA7, 0x0, 0xB7, 0xFE, 0xB6, 0x55, 0xB6, 0xAD, 0xB5, +0x5, 0x0, 0xB5, 0x5E, 0xB4, 0xB8, 0xB3, 0x12, 0xB3, 0x6D, 0x0, 0xB2, 0xC8, 0xB1, 0x24, 0xB1, 0x81, 0xB0, 0xDE, 0x0, 0xAF, 0x3B, 0xAF, 0x9A, 0xAE, 0xF9, 0xAD, 0x58, 0x0, 0xAD, 0xB8, 0xAC, 0x19, 0xAC, 0x7A, +0xAB, 0xDC, 0x0, 0xAA, 0x3E, 0xAA, 0xA1, 0xA9, 0x5, 0xA9, 0x69, 0x0, 0xA8, 0xCE, 0xA7, 0x33, 0xA7, 0x99, 0xA6, 0xFF, 0x0, 0xA5, 0x66, 0xA5, 0xCD, 0xA4, 0x35, 0xA4, 0x9E, 0x0, 0xA3, 0x7, 0xA3, 0x70, 0xA2, +0xDA, 0xA1, 0x45, 0x0, 0xA1, 0xB0, 0xA0, 0x1C, 0xA0, 0x88, 0x9F, 0xBF, 0x0, 0x9E, 0x76, 0x9E, 0xD0, 0x9D, 0x3D, 0x9D, 0xAE, 0x0, 0x9C, 0x1D, 0x9C, 0x8D, 0x9B, 0xFE, 0x9A, 0x6F, 0x0, 0x9A, 0xE0, 0x99, +0x52, 0x99, 0xC5, 0x98, 0x38, 0x0, 0x98, 0xAC, 0x97, 0x20, 0x97, 0x94, 0x96, 0x9, 0x0, 0x96, 0x7F, 0x95, 0xF5, 0x94, 0x6C, 0x94, 0xE3, 0x0, 0x93, 0x5A, 0x93, 0xD2, 0x92, 0x4B, 0x92, 0xC4, 0x0, 0x91, 0x3D, +0x91, 0xB7, 0x90, 0x32, 0x90, 0xAD, 0x0, 0x8F, 0x28, 0x8F, 0xA4, 0x8E, 0x21, 0x8E, 0x9E, 0x0, 0x8D, 0x1B, 0x8D, 0x99, 0x8C, 0x17, 0x8C, 0x96, 0x0, 0x8B, 0x15, 0x8B, 0x95, 0x8A, 0x15, 0x8A, 0x95, 0x0, +0x89, 0x17, 0x89, 0x98, 0x88, 0x1A, 0x88, 0x9C, 0x0, 0x87, 0x1F, 0x87, 0xA3, 0x86, 0x27, 0x86, 0xAB, 0x0, 0x85, 0x2F, 0x85, 0xB5, 0x84, 0x3A, 0x84, 0xC0, 0x0, 0x83, 0x47, 0x83, 0xCE, 0x82, 0x55, 0x82, +0xDD, 0x4, 0x81, 0x65, 0x81, 0xED, 0x80, 0xB, 0x2A, 0x80, 0x8A, 0x0, 0x7F, 0x14, 0x7F, 0x9F, 0x7E, 0x2A, 0x7E, 0xB6, 0x0, 0x7D, 0x42, 0x7D, 0xCE, 0x7C, 0x5B, 0x7C, 0xE8, 0x0, 0x7B, 0x76, 0x7B, 0x4, 0x7B, +0x93, 0x7A, 0x22, 0x0, 0x7A, 0xB1, 0x79, 0x41, 0x79, 0xD1, 0x78, 0x61, 0x0, 0x78, 0xF2, 0x77, 0x84, 0x77, 0x15, 0x77, 0xA8, 0x0, 0x76, 0x12, 0x76, 0xCD, 0x75, 0x60, 0x75, 0xF4, 0x0, 0x74, 0x88, 0x74, +0x1D, 0x74, 0xB2, 0x73, 0x47, 0x0, 0x73, 0xDD, 0x72, 0x73, 0x72, 0x9, 0x72, 0xA0, 0x0, 0x71, 0x37, 0x71, 0xCF, 0x70, 0x66, 0x70, 0xFF, 0x0, 0x6F, 0x97, 0x6F, 0x30, 0x6F, 0xCA, 0x6E, 0x64, 0x0, 0x6E, 0xFE, +0x6D, 0x98, 0x6D, 0x33, 0x6D, 0xCF, 0x0, 0x6C, 0x6A, 0x6C, 0x6, 0x6C, 0xA2, 0x6B, 0x3F, 0x0, 0x6B, 0xDC, 0x6A, 0x7A, 0x6A, 0x17, 0x6A, 0xB6, 0x0, 0x69, 0x54, 0x69, 0xF3, 0x68, 0x92, 0x68, 0x32, 0x0, 0x68, +0xD1, 0x67, 0x72, 0x67, 0x12, 0x67, 0xB3, 0x1, 0x66, 0x54, 0x66, 0xF6, 0x65, 0x98, 0x65, 0x8, 0xD7, 0xA, 0x8, 0x0, 0x0, 0x7A, 0x0, 0x3, 0xFB, 0x0, 0x7, 0x83, 0x0, 0x9, 0x0, 0x0, 0x14, 0xA, 0x0, 0x0, 0xAE, +0xAA, 0x0, 0x3, 0x50, 0xE, 0xA, 0xFD, 0xE, 0xE, 0xB3, 0xE, 0xD, 0x74, 0x81, 0xE, 0xA, 0x41, 0xE, 0x0, 0x0, 0x1A, 0xF, 0xE, 0x30, 0x8, 0x10, 0x0, 0x0, 0xF4, 0x0, 0x3, 0xF6, 0x11, 0x0, 0x0, 0x0, 0x7, 0x13, +0x0, 0x0, 0x29, 0x14, 0x0, 0x0, 0x0, 0x5C, 0x15, 0x0, 0x0, 0xA1, 0x16, 0x0, 0x0, 0x0, 0xF9, 0x17, 0x0, 0x0, 0x66, 0x19, 0x0, 0x2, 0x0, 0xE9, 0x1A, 0x0, 0x0, 0x82, 0x4, 0x61, 0x34, 0x40, 0x1E, 0xE, 0x60, +0x20, 0x0, 0x0, 0xE7, 0x21, 0x0, 0x0, 0x0, 0xEB, 0x23, 0x0, 0x0, 0xE, 0x26, 0x0, 0x1, 0x0, 0x51, 0x28, 0x0, 0x0, 0xB7, 0x2A, 0x0, 0x4F, 0x0, 0x2D, 0x0, 0x0, 0xF2, 0x2F, 0x0, 0x0, 0xCC, 0x50, 0x32, 0xD, +0x86, 0x35, 0xE, 0x63, 0x39, 0x0, 0x0, 0x68, 0x60, 0x3C, 0xE, 0x90, 0x8, 0x7E, 0xCE, 0x43, 0x0, 0x0, 0xD6, 0x80, 0xE, 0xAF, 0x1C, 0x4C, 0x0, 0x0, 0xA3, 0x50, 0x0, 0x10, 0x0, 0x6E, 0x55, 0x0, 0x4F, 0x5A, +0x0, 0x0, 0xE4, 0x0, 0x5F, 0x0, 0x0, 0x98, 0x65, 0x0, 0x0, 0xA2, 0x5, 0x6B, 0x0, 0x0, 0x9, 0x72, 0xD, 0xBE, 0x78, 0xE, 0xC0, 0x80, 0xC, 0xBE, 0x9C, 0x87, 0x0, 0x0, 0xAD, 0x8F, 0x0, 0x0, 0x0, 0x38, 0x98, +0x0, 0x0, 0x45, 0xA1, 0x0, 0x10, 0x0, 0xDC, 0xAA, 0xE, 0xD2, 0xB5, 0x0, 0x0, 0xC9, 0x4, 0xBF, 0x0, 0x0, 0x30, 0xCB, 0x0, 0x13, 0xD7, 0x0, 0x14, 0x0, 0x12, 0xE4, 0x0, 0x37, 0xF1, 0x1E, 0xF1, 0x1, 0x0, +0x0, 0x39, 0xF, 0x1, 0x0, 0x5A, 0x1F, 0x1, 0x0, 0x8, 0x70, 0x30, 0x1, 0x0, 0x7, 0xD1, 0x0, 0xB8, 0x55, 0x0, 0x1, 0x0, 0xA, 0x6A, 0x1, 0x0, 0x91, 0x7F, 0x8, 0x1, 0x0, 0x60, 0x96, 0x0, 0x13, 0xAE, 0x1, +0x0, 0x1, 0x24, 0xC8, 0x1, 0x0, 0x43, 0xE3, 0x1, 0x1F, 0x21, 0x0, 0x0, 0x72, 0x1E, 0x2, 0x0, 0xB3, 0x3E, 0x2, 0x0, 0x0, 0xE0, 0x60, 0x2, 0x0, 0x14, 0x85, 0x2, 0x10, 0x0, 0x70, 0xAB, 0x0, 0x7, 0xD4, 0x2, +0x0, 0x22, 0x0, 0xFF, 0x2, 0x0, 0xC0, 0x2C, 0x3, 0x0, 0x14, 0x0, 0x5D, 0x3, 0x0, 0x48, 0x90, 0x3, 0x0, 0x87, 0x40, 0xC6, 0x1F, 0x52, 0x4, 0x0, 0xE4, 0x3C, 0x4, 0x0, 0x0, 0x67, 0x7D, 0x4, 0x0, 0xC0, 0xC1, +0x4, 0x0, 0x0, 0x29, 0xA, 0x5, 0x0, 0xE0, 0x56, 0x5, 0x0, 0x0, 0x28, 0xA8, 0x5, 0x0, 0x44, 0xFE, 0x5, 0x0, 0x0, 0x80, 0x59, 0x6, 0x0, 0x28, 0xBA, 0x6, 0x0, 0x3, 0x90, 0x20, 0x7, 0x0, 0xE, 0x8D, 0xF, 0x75, +0x1, 0x80, 0x0, 0xC8, 0x79, 0x8, 0x0, 0xCD, 0xFA, 0x8, 0x0, 0x50, 0x7F, 0x1, 0x80, 0x51, 0x1, 0x80, 0xC1, 0xAD, 0xA, 0x0, 0x40, 0x4F, 0x1, 0x80, 0x88, 0xFC, 0xB, 0x0, 0xFF, 0xB2, 0x15, 0xC, 0x0, 0x50, +0x1, 0x80, 0x1F, 0x1, 0x80, 0x1C, 0x41, 0x80, 0x0, 0x90, 0xF3, 0x10, 0x0, 0x9B, 0xF5, 0x11, 0x0, 0x0, 0xFE, 0x6, 0x13, 0x0, 0xA3, 0x28, 0x14, 0x0, 0x0, 0x81, 0x5B, 0x15, 0x0, 0x9E, 0xA0, 0x16, 0x0, 0x40, +0x11, 0x1, 0x80, 0xFF, 0x65, 0x19, 0x0, 0xA0, 0xE8, 0x14, 0x1A, 0x0, 0x3E, 0x1, 0x80, 0x38, 0x21, 0x80, 0x3B, 0x0, 0x10, 0x76, 0x0, 0xB2, 0x5, 0xED, 0x28, 0x1, 0x64, 0x1, 0x0, 0x9F, 0x1, 0xDB, 0x1, 0x17, +0x2, 0x52, 0x2, 0x0, 0x8E, 0x2, 0xCA, 0x2, 0x5, 0x3, 0x41, 0x3, 0x0, 0x7D, 0x3, 0xFF, 0xFF, 0xC5, 0xFF, 0x8A, 0xFF, 0x41, 0x4F, 0x4, 0x9, 0xD9, 0xFE, 0x9E, 0xFE, 0x4F, 0x4, 0xF, 0x0, 0xEE, 0xFD, 0xB3, +0xFD, 0x78, 0xFD, 0x3E, 0xFD, 0x0, 0x4, 0xFD, 0xC9, 0xFC, 0x85, 0xFC, 0x0, 0x2, 0x0, 0x3, 0x5, 0x6, 0x8, 0x9, 0xB, 0xC, 0xE, 0x0, 0x10, 0x11, 0x13, 0x14, 0x16, 0x17, 0x18, 0x1A, 0x0, 0x1B, 0x1D, 0x1E, +0x20, 0x21, 0x22, 0x24, 0x25, 0x0, 0x26, 0x27, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x0, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x0, 0x37, 0x38, 0x38, 0x39, 0x3A, 0x3B, 0x3B, 0x3C, 0x0, 0x3C, +0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x1C, 0x3F, 0x40, 0x40, 0x60, 0x1, 0x0, 0xD, 0x0, 0x13, 0x3D, 0x3D, 0x0, 0x3C, 0x3C, 0x3B, 0x3B, 0x3A, 0x39, 0x38, 0x38, 0x0, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, +0x31, 0x30, 0x0, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x27, 0x0, 0x26, 0x25, 0x24, 0x22, 0x21, 0x20, 0x1E, 0x1D, 0x0, 0x1B, 0x1A, 0x18, 0x17, 0x16, 0x14, 0x13, 0x11, 0x0, 0x10, 0xE, 0xC, 0xB, 0x9, +0x8, 0x6, 0x5, 0x0, 0x3, 0x2, 0x0, 0xFE, 0xFD, 0xFB, 0xFA, 0xF8, 0x0, 0xF7, 0xF5, 0xF4, 0xF2, 0xF0, 0xEF, 0xED, 0xEC, 0x0, 0xEA, 0xE9, 0xE8, 0xE6, 0xE5, 0xE3, 0xE2, 0xE0, 0x0, 0xDF, 0xDE, 0xDC, 0xDB, +0xDA, 0xD9, 0xD7, 0xD6, 0x0, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xD0, 0xCF, 0xCE, 0x0, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8, 0xC8, 0xC7, 0x0, 0xC6, 0xC5, 0xC5, 0xC4, 0xC4, 0xC3, 0xC3, 0xC2, 0x1, 0xC2, 0xC2, +0xC1, 0xC1, 0xC1, 0xC0, 0xC0, 0x60, 0x1, 0xC0, 0x0, 0xD, 0x0, 0x13, 0xC3, 0xC3, 0xC4, 0xC4, 0xC5, 0xC5, 0x0, 0xC6, 0xC7, 0xC8, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0x0, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, +0xD4, 0x0, 0xD5, 0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDE, 0x0, 0xDF, 0xE0, 0xE2, 0xE3, 0xE5, 0xE6, 0xE8, 0xE9, 0x0, 0xEA, 0xEC, 0xED, 0xEF, 0xF0, 0xF2, 0xF4, 0xF5, 0x0, 0xF7, 0xF8, 0xFA, 0xFB, 0xFD, +0xFE, 0x10, 0x22, 0x10, 0x50, 0x43, 0x5B, 0x9, 0xCF, 0x80, 0x18, 0x10, 0x31, 0x0, 0x1, 0x60, 0x0, 0x21, 0x41, 0x60, 0x70, 0x47, 0xB4, 0x10, 0x13, 0x56, 0x20, 0x13, 0x50, 0xD, 0x53, 0x20, 0x21, 0x81, 0x81, +0xA0, 0x30, 0x1B, 0x4F, 0x20, 0x2F, 0xC3, 0x68, 0x4B, 0x43, 0x9B, 0x20, 0xA, 0xC3, 0x10, 0x2F, 0x21, 0x48, 0x43, 0x4A, 0x49, 0x0, 0x9, 0x68, 0x40, 0x18, 0x1, 0x21, 0xC9, 0x7, 0x50, 0x1, 0x40, 0x11, 0x46, +0x20, 0x11, 0x0, 0x68, 0xC0, 0x17, 0x2B, 0xC0, 0x43, 0x30, 0x53, 0x41, 0x20, 0x67, 0x1, 0xC, 0x55, 0x10, 0x75, 0x60, 0x3E, 0x30, 0x61, 0xC, 0x63, 0x3C, 0x4A, 0x81, 0x68, 0x11, 0x0, 0x61, 0x10, 0x23, 0x59, +0x43, 0x43, 0x69, 0x53, 0x0, 0x60, 0x5B, 0x18, 0x53, 0x61, 0x81, 0x69, 0x11, 0x0, 0x60, 0xC1, 0x69, 0x91, 0x60, 0x1, 0x68, 0x49, 0x0, 0x0, 0x28, 0xA3, 0x5B, 0x5A, 0xD3, 0x60, 0x29, 0x89, 0x0, 0x5, 0x93, +0x61, 0x2B, 0x10, 0xB, 0x61, 0x2C, 0x0, 0x11, 0x0, 0x30, 0x4A, 0x13, 0x60, 0x30, 0x48, 0x0, 0x68, 0x40, 0x30, 0x0, 0x77, 0x0, 0x22, 0x4, 0xC0, 0x1, 0x39, 0x0, 0xFC, 0xD1, 0x2E, 0x48, 0x2, 0x70, 0x28, +0x48, 0x0, 0xC1, 0x68, 0x0, 0x68, 0x2D, 0x4B, 0x3, 0x60, 0x0, 0x10, 0x30, 0x1, 0x39, 0xFB, 0xD1, 0x2B, 0x48, 0x0, 0x2C, 0x49, 0x1, 0x60, 0x2C, 0x48, 0x2, 0x60, 0x0, 0x42, 0x60, 0x2B, 0x48, 0x2, 0x80, +0x2B, 0x49, 0x0, 0x1, 0x80, 0x2B, 0x48, 0x22, 0x49, 0x4A, 0x68, 0x0, 0x9, 0x68, 0x1, 0x60, 0x89, 0x18, 0x89, 0x18, 0x0, 0xC1, 0x60, 0x24, 0x49, 0x41, 0x60, 0x4, 0x31, 0x0, 0x1, 0x61, 0x26, 0x49, 0x81, +0x60, 0x41, 0x61, 0x0, 0x26, 0x48, 0x80, 0x21, 0x1, 0x80, 0x25, 0x48, 0x2, 0x1, 0x88, 0xA0, 0x29, 0xFC, 0xDA, 0x20, 0x5, 0xDB, 0x88, 0x90, 0xB, 0x20, 0x48, 0x20, 0x0, 0xEB, 0x80, 0x22, 0x12, 0x10, 0x4, +0x11, 0x43, 0x10, 0xEB, 0xC0, 0x46, 0x88, 0x0, 0x0, 0xB0, 0x0, 0xE0, 0x0, 0x8, 0x1, 0x30, 0x1, 0x20, 0x60, 0x1, 0x3, 0xAF, 0x60, 0x6D, 0x4B, 0x0, 0x40, 0x0, 0x94, 0x37, 0x0, 0x30, 0xEE, 0xF7, 0xC4, 0xF9, +0x0, 0x1A, 0xFB, 0xD8, 0xFB, 0x64, 0xFC, 0xE2, 0xFC, 0x0, 0x4E, 0x4F, 0xA8, 0x66, 0xA7, 0x82, 0xFC, 0x99, 0x0, 0x51, 0xB1, 0x50, 0xCD, 0x8, 0x5C, 0x0, 0x3, 0x55, 0x4, 0x0, 0x3, 0x24, 0x0, 0x7, 0xC, 0x0, +0xB, 0x10, 0x0, 0xF, 0x64, 0x26, 0x0, 0x13, 0x13, 0xED, 0x10, 0x10, 0x10, 0x7, 0xA0, 0xE1, 0x50, 0xA0, 0x4, 0x32, 0x82, 0x4, 0x36, 0xC, 0x9A, 0x0, 0x0, 0x42, 0xBC, 0x13, 0x74, 0x0, 0x0, 0xB6, 0x84, 0x4, +0x46, 0x6, 0x86, 0x13, 0x80, 0x1, 0x0, 0x4, 0x20, 0x10, 0x2F, 0xF, 0xBB, 0x8, 0xAA, 0xF, 0xBF, 0x10, 0xF, 0xC3, 0x18, 0xF, 0xC7, 0x20, 0xF, 0xCB, 0x28, 0xAA, 0xF, 0xCF, 0x30, 0xF, 0xD3, 0x38, 0xF, 0xD7, +0x40, 0xF, 0xDB, 0x48, 0xAA, 0xF, 0xDF, 0x50, 0xF, 0xE3, 0x58, 0xF, 0xE7, 0x60, 0xF, 0xEB, 0x68, 0xF0, 0x4A, 0xF7, 0x82, 0xBC, 0xF0, 0x1, 0x90, 0x6, 0xA, 0x0, }; + +void Write_GBA( void ) +{ + int x; + + for( x = 0; x < sizeof( GBA_ROM ); x++ ) + write8( GBA_ROM[x] ); + + for( ; x < 0x3400-4; x++ ) + write8( x ); +} + diff --git a/tools/mmutil/gba.h b/tools/mmutil/gba.h new file mode 100644 index 0000000..a890870 --- /dev/null +++ b/tools/mmutil/gba.h @@ -0,0 +1,28 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include +#include "defs.h" +#include "mas.h" +#include "it.h" +#include "files.h" +#include "simple.h" +#include "errors.h" +#include "samplefix.h" + +#ifdef SUPER_ASCII +#define vstr_it_div "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n" +#define vstr_it_instr_top "ÚÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\n" +#define vstr_it_instr_head "³INDEX³VOLUME³ NNA ³ ENV ³ NAME ³\n" +#define vstr_it_instr_slice "ÃÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n" +#define vstr_it_instr "³%3i ³ %3i%% ³ %3s ³ %s%s%s ³ %-26s³\n" +#define vstr_it_instr_bottom "ÀÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\n" + +#define vstr_it_samp_top "ÚÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\n" +#define vstr_it_samp_head "³INDEX³VOLUME³DVOLUME³ LOOP ³ MID-C ³ NAME ³\n" +#define vstr_it_samp_slice "ÃÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n" +#define vstr_it_samp "³%3i ³ %3i%% ³ %3i%% ³ %4s ³%6ihz ³ %-26s³\n" +#define vstr_it_samp_bottom "ÀÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\n" + +#define vstr_it_pattern " \x0e %2i" +#else +#define vstr_it_div "--------------------------------------------\n" +#define vstr_it_instr_top vstr_it_div +#define vstr_it_instr_head " INDEX VOLUME NNA ENV NAME\n" +//#define vstr_it_instr_slice "" +#define vstr_it_instr " %-3i %3i%% %3s %s%s%s %-26s \n" +#define vstr_it_instr_bottom vstr_it_div + +#define vstr_it_samp_top vstr_it_div +#define vstr_it_samp_head " INDEX VOLUME DVOLUME LOOP MID-C NAME \n" +//#define vstr_it_samp_slice "" +#define vstr_it_samp " %-3i %3i%% %3i%% %4s %6ihz %-26s \n" +#define vstr_it_samp_bottom vstr_it_div + +#define vstr_it_pattern " * %2i" +#endif + +bool Load_IT_Envelope( Instrument_Envelope* env, bool unsign ) +{ + // read envelopes + u8 a; + u8 node_count; + int x; + + bool env_loop=false; + bool env_sus=false; + bool env_enabled=false; + bool env_filter=false; + + memset( env, 0, sizeof( Instrument_Envelope ) ); + + a=read8(); + + if( a & 1 ) + env_enabled = true; + if( !(a & 2) ) + { + env->loop_start=255; + env->loop_end =255; + } + else + env_loop=true; + if( !(a & 4) ) + { + env->sus_start=255; + env->sus_end=255; + } + else + env_sus=true; + + if( a & 128 ) + { + unsign=false; + env_filter=true; + env->env_filter=env_filter; + } + + node_count=read8(); + if( node_count != 0 ) + env->env_valid=true; + + env->node_count = node_count; + if( env_loop ) + { + env->loop_start=read8(); + env->loop_end=read8(); + } + else + { + skip8( 2 ); + } + if( env_sus ) + { + env->sus_start=read8(); + env->sus_end=read8(); + } + else + { + skip8( 2 ); + } + for( x = 0; x < 25; x++ ) + { + env->node_y[x] = read8(); + if( unsign ) + env->node_y[x] += 32; + env->node_x[x] = read16(); + + } + read8(); // unused byte + env->env_enabled = env_enabled; + return env_enabled; +} + +int Load_IT_Instrument( Instrument* inst, bool verbose, int index ) +{ + u16 a; + int x; + + memset( inst, 0, sizeof( Instrument ) ); + + skip8( 17 ); + inst->nna =read8(); + inst->dct =read8(); + inst->dca =read8(); + a=read16(); if( a > 255 ) a = 255; + inst->fadeout =(u8)a; + skip8( 2 ); + inst->global_volume =read8(); + a= read8(); + a = (a&128) | ((a&127)*2 > 127 ? 127 : (a&127)*2); + inst->setpan =a^128; + inst->random_volume =read8(); + skip8( 5 ); + for( x = 0; x < 26; x++ ) + inst->name[x] = read8(); + skip8( 6 ); + + for( x = 0; x < 120; x++ ) + inst->notemap[x] = read16(); + + inst->env_flags=0; + + Load_IT_Envelope( &inst->envelope_volume, false ); + inst->env_flags |= inst->envelope_volume.env_valid ? 1 : 0; + inst->env_flags |= inst->envelope_volume.env_enabled ? 8 : 0; + + Load_IT_Envelope( &inst->envelope_pan, true ); + inst->env_flags |= inst->envelope_pan.env_enabled ? 2 : 0; + + Load_IT_Envelope( &inst->envelope_pitch, true ); + inst->env_flags |= inst->envelope_pitch.env_enabled ? 4 : 0; + + if( verbose ) + { + printf( vstr_it_instr, \ + index+1, \ + (inst->global_volume*100)/128, \ + ((inst->nna==0)?"CUT":((inst->nna==1)?"CON":((inst->nna==2)?"OFF":((inst->nna==3)?"FAD":"???")))), \ + (inst->env_flags&8)?"V":"-", \ + (inst->env_flags&2)?"P":"-", \ + (inst->env_flags&4)?"T":"-", \ + inst->name ); + + /* printf( "%i%% ", (inst->global_volume*100) / 128 ); + switch( inst->nna ) + { + case 0: + printf( "%s ", "CUT" ); break; + case 1: + printf( "%s ", "OFF" ); break; + case 2: + printf( "%s ", "CONT" ); break; + case 3: + printf( "%s ", "FADE" ); break; + } + if( (!(inst->env_flags & 2)) && (!(inst->env_flags & 4)) && (!(inst->env_flags & 8)) ) + { + printf( "- " ); + } + else + { + if( inst->env_flags & 8) + printf( "V" ); + if( inst->env_flags & 2) + printf( "P" ); + if( inst->env_flags & 4) + printf( "S" ); + printf( " " ); + } + printf( "%s\n", inst->name );*/ + } + + skip8( 7 ); + return 0; +} + +void Create_IT_Instrument( Instrument* inst, int sample ) +{ + int x; + + memset( inst, 0, sizeof( Instrument ) ); + + inst->global_volume =128; + + for( x = 0; x < 120; x++ ) + inst->notemap[x] = x+sample*256; +} + +int Load_IT_Sample( Sample* samp ) +{ + bool bit16; + bool hasloop; + bool pingpong; + bool samp_unsigned=false; + u8 a; + u32 samp_length; + u32 loop_start; + u32 loop_end; + u32 c5spd; + u32 data_address; + int x; + + memset( samp, 0, sizeof( Sample ) ); + samp->msl_index = 0xFFFF; + + if( read32() != 'SPMI' ) + return ERR_UNKNOWNSAMPLE; + for( x = 0; x < 12; x++ ) // dos filename + samp->filename[x] = read8(); + if( read8() != 0 ) + return ERR_UNKNOWNSAMPLE; + samp->global_volume = read8(); + a = read8(); + samp->it_compression = a & 8 ? 1 : 0; + bit16 = a & 2; + hasloop = a & 16; + pingpong = a & 64; + samp->default_volume = read8(); + for( x = 0; x < 26; x++ ) + samp->name[x] = read8(); + a=read8(); + samp->default_panning = read8(); + samp->default_panning = (((samp->default_panning&127) == 64) ? 127 : (samp->default_panning<<1)) | (samp->default_panning&128); + if( !(a & 1) ) + samp_unsigned=true; + samp_length = read32(); + loop_start=read32(); + loop_end=read32(); + c5spd=read32(); + + samp->frequency = c5spd; + samp->sample_length = samp_length; + samp->loop_start = loop_start; + samp->loop_end = loop_end; + + skip8( 8 ); // susloop start/end + data_address = read32(); + samp->vibspeed = read8(); + samp->vibdepth = read8(); + samp->vibrate = read8(); + samp->vibtype = read8(); + samp->datapointer = data_address; + if( hasloop ) + { + if( pingpong ) + samp->loop_type = 2; + else + samp->loop_type = 1; + samp->loop_start = loop_start; + samp->loop_end = loop_end; + } + else + { + samp->loop_type = 0; + } + samp->format = (bit16 ? SAMPF_16BIT : 0) | (samp_unsigned ? 0 : SAMPF_SIGNED ); + if( samp->sample_length == 0 ) samp->loop_type = 0; + return 0; +} + +int Load_IT_Sample_CMP( u8 *p_dest_buffer, int samp_len, u16 cmwt, bool bit16 ); +int Load_IT_SampleData( Sample* samp, u16 cwmt ) +{ + u32 x; + int a; + if( samp->sample_length == 0 ) return 0; + if( samp->format & SAMPF_16BIT ) + samp->data = (u16*)malloc( (u32)(samp->sample_length)*2 ); + else + samp->data = (u8*)malloc( (u32)(samp->sample_length) ); + + if( !samp->it_compression ) + { + + for( x = 0; x < samp->sample_length; x++ ) + { + if( samp->format & SAMPF_16BIT ) + { + if( !(samp->format & SAMPF_SIGNED) ) + { + a = (unsigned short)read16(); + } + else + { + a = (signed short)read16(); + a += 32768; + } + ((u16*)samp->data)[x] = (u16)a; + } + else + { + if( !(samp->format & SAMPF_SIGNED) ) + { + a = (unsigned char)read8(); + } + else + { + a = (signed char)read8(); + a += 128; + } + ((u8*)samp->data)[x] = (u8)a; + } + + } + } + else + { + Load_IT_Sample_CMP( samp->data, samp->sample_length, cwmt, (bool)(samp->format & SAMPF_16BIT) ); + } + FixSample( samp ); + return 0; +} + +int Empty_IT_Pattern( Pattern *patt ) { + + int x; + memset( patt, 0, sizeof( Pattern ) ); + patt->nrows = 64; + for( x = 0; x < patt->nrows*MAX_CHANNELS; x++ ) { + patt->data[x].note = 250; // special clears for vol¬e + patt->data[x].vol = 255; + } + return ERR_NONE; +} + +int Load_IT_Pattern( Pattern* patt ) +{ + int x; + int clength; + u8 chanvar; + u8 chan; + u8 maskvar; + + u8 old_maskvar[MAX_CHANNELS]; + u8 old_note[MAX_CHANNELS]; + u8 old_inst[MAX_CHANNELS]; + u8 old_vol[MAX_CHANNELS]; + u8 old_fx[MAX_CHANNELS]; + u8 old_param[MAX_CHANNELS]; + + memset( patt, 0, sizeof( Pattern ) ); + + clength = read16(); + patt->nrows = read16(); + skip8(4); + + patt->clength = clength; + + for( x = 0; x < patt->nrows*MAX_CHANNELS; x++ ) + { + patt->data[x].note = 250; // special clears for vol¬e + patt->data[x].vol = 255; + } + + + // DECOMPRESS IT PATTERN + + for( x = 0; x < patt->nrows; x++ ) + { +GetNextChannelMarker: + chanvar = read8(); // Read byte into channelvariable. + if( chanvar == 0 ) // if(channelvariable = 0) then end of row + continue; + + chan = (chanvar-1) & 63; // Channel = (channelvariable-1) & 63 + if( chan >= MAX_CHANNELS ) + return ERR_MANYCHANNELS; + + if( chanvar & 128 ) // if(channelvariable & 128) then read byte into maskvariable + old_maskvar[chan] = read8(); + + maskvar = old_maskvar[chan]; + + if( maskvar & 1 ) // if(maskvariable & 1), then read note. (byte value) + { + old_note[chan] = read8(); + patt->data[x*MAX_CHANNELS+chan].note = old_note[chan]; + } + + if( maskvar & 2 ) // if(maskvariable & 2), then read instrument (byte value) + { + old_inst[chan] = read8(); + patt->data[x*MAX_CHANNELS+chan].inst = old_inst[chan]; + } + + if( maskvar & 4 ) // if(maskvariable & 4), then read volume/panning (byte value) + { + old_vol[chan] = read8(); + patt->data[x*MAX_CHANNELS+chan].vol = old_vol[chan]; + } + + if( maskvar & 8 ) // if(maskvariable & 8), then read command (byte value) and commandvalue + { + old_fx[chan] = read8(); + patt->data[x*MAX_CHANNELS+chan].fx = old_fx[chan]; + old_param[chan] = read8(); + patt->data[x*MAX_CHANNELS+chan].param = old_param[chan]; + } + + if( maskvar & 16 ) // if(maskvariable & 16), then note = lastnote for channel + patt->data[x*MAX_CHANNELS+chan].note = old_note[chan]; + if( maskvar & 32 ) // if(maskvariable & 32), then instrument = lastinstrument for channel + patt->data[x*MAX_CHANNELS+chan].inst = old_inst[chan]; + if( maskvar & 64 ) // if(maskvariable & 64), then volume/pan = lastvolume/pan for channel + patt->data[x*MAX_CHANNELS+chan].vol = old_vol[chan]; + if( maskvar & 128 ) // if(maskvariable & 128), then { + { + patt->data[x*MAX_CHANNELS+chan].fx = old_fx[chan]; // command = lastcommand for channel and + patt->data[x*MAX_CHANNELS+chan].param = old_param[chan];// commandvalue = lastcommandvalue for channel + } + goto GetNextChannelMarker; + } + + return ERR_NONE; +} + +int Load_IT( MAS_Module* itm, bool verbose ) +{ + u8 b; + u16 w; + int x; + int cc; + + u16 cwt; + u16 cmwt; + + u32* parap_inst; + u32* parap_samp; + u32* parap_patt; + + bool instr_mode; + + memset( itm, 0, sizeof( MAS_Module ) ); + + if( read32() != 'MPMI' ) + return ERR_INVALID_MODULE; + for( x = 0; x < 28; x++ ) + itm->title[x] = read8(); + itm->order_count = (u16)read16(); + itm->inst_count = (u8)read16(); + itm->samp_count = (u8)read16(); + itm->patt_count = (u8)read16(); + cwt = read16(); + cmwt = read16(); // upward compatible + //skip8( 4 ); // created with tracker / upward compatible + w = read16(); // flags + itm->stereo = w & 1; + itm->inst_mode = instr_mode = w & 4; + itm->freq_mode = w & 8; + itm->old_effects = w & 16; + itm->link_gxx = w & 32; + skip8( 2 ); // special + itm->global_volume = read8(); + skip8( 1 ); // mix volume + itm->initial_speed = read8(); + itm->initial_tempo = read8(); + + if( verbose ) + { + printf( vstr_it_div ); + printf( "Loading IT, \"%s\"\n", itm->title ); + printf( vstr_it_div ); + printf( "#Orders......%i\n", itm->order_count ); + printf( "#Instr.......%i\n", itm->inst_count ); + printf( "#Samples.....%i\n", itm->samp_count ); + printf( "#Patterns....%i\n", itm->patt_count ); + printf( "Stereo.......%s\n", itm->stereo ? "Yes" : "No" ); + printf( "Slides.......%s\n", itm->freq_mode ? "Linear" : "Amiga" ); + printf( "Old Effects..%s\n", itm->old_effects ? "Yes" : "No" ); + printf( "Global Vol...%i%%\n", (itm->global_volume*100)/128 ); + printf( "Speed........%i\n", itm->initial_speed ); + printf( "Tempo........%i\n", itm->initial_tempo ); + printf( "Instruments..%s\n", instr_mode ? "Yes" : "Will be supplied" ); + printf( vstr_it_div ); + } + skip8( 12 ); // SEP, PWD, MSGLENGTH, MESSAGE OFFSET, [RESERVED] + for( x = 0; x < 64; x++ ) + { + b = read8(); + if( x < MAX_CHANNELS ) + itm->channel_panning[x] = b*4 > 255 ? 255 : b*4; // map 0->64 to 0->255 + } + for( x = 0; x < 64; x++ ) + { + b = read8(); + if( x < MAX_CHANNELS ) + itm->channel_volume[x] = b; + } + for( x = 0; x < itm->order_count; x++ ) + itm->orders[x] = read8(); + + parap_inst = (u32*)malloc( itm->inst_count * sizeof( u32 ) ); + parap_samp = (u32*)malloc( itm->samp_count * sizeof( u32 ) ); + parap_patt = (u32*)malloc( itm->patt_count * sizeof( u32 ) ); + + for( x = 0; x < itm->inst_count; x++ ) + parap_inst[x] = read32(); + for( x = 0; x < itm->samp_count; x++ ) + parap_samp[x] = read32(); + for( x = 0; x < itm->patt_count; x++ ) + parap_patt[x] = read32(); + + itm->samples = (Sample*)malloc( itm->samp_count * sizeof( Sample ) ); + itm->patterns = (Pattern*)malloc( itm->patt_count * sizeof( Pattern ) ); + + if( instr_mode ) + { + itm->instruments = (Instrument*)malloc( itm->inst_count * sizeof( Instrument ) ); + if( verbose ) + { + printf( "Loading Instruments...\n" ); + printf( vstr_it_instr_top ); + printf( vstr_it_instr_head ); +#ifdef vstr_it_instr_slice + printf( vstr_it_instr_slice ); +#endif + //printf( "INDEX VOLUME NNA ENV NAME\n" ); + } + + // read instruments + for( x = 0; x < itm->inst_count; x++ ) + { + // if( verbose ) + // printf( "%i ", x+1 ); + file_seek_read( parap_inst[x], SEEK_SET ); + Load_IT_Instrument( &itm->instruments[x], verbose, x ); + } + + if( verbose ) + { + printf( vstr_it_instr_bottom ); + } + } + + if( verbose ) + { + printf( "Loading Samples...\n" ); + printf( vstr_it_samp_top ); + printf( vstr_it_samp_head ); +#ifdef vstr_it_samp_slice + printf( vstr_it_samp_slice ); +#endif + //printf( "INDEX VOLUME DVOLUME LOOP MID-C NAME\n" ); + } + + // read samples + for( x = 0; x < itm->samp_count; x++ ) + { + file_seek_read( parap_samp[x], SEEK_SET ); + Load_IT_Sample( &itm->samples[x] ); + if( verbose ) + { + printf( vstr_it_samp, x+1, (itm->samples[x].global_volume * 100) / 64, (itm->samples[x].default_volume * 100) / 64, itm->samples[x].loop_type == 0 ? "None" : (itm->samples[x].loop_type == 1 ? "Forw" : "BIDI"), itm->samples[x].frequency, itm->samples[x].name ); + //printf( "%i %i%% %i%% %s %ihz %s\n", x+1, (itm->samples[x].global_volume*100) / 64, (itm->samples[x].default_volume*100) / 64, itm->samples[x].loop_type == 0 ? "None" : (itm->samples[x].loop_type == 1 ? "Yes" : "BIDI"), itm->samples[x].frequency, itm->samples[x].name ); + } + } + + if( verbose ) + { + printf( vstr_it_samp_bottom ); + } + + if( !instr_mode ) + { + if( verbose ) + { + printf( "Adding Instrument Templates...\n" ); + printf( vstr_it_div ); + } + itm->inst_count = itm->samp_count; + itm->instruments = (Instrument*)malloc( itm->inst_count * sizeof( Instrument ) ); + cc=0; + for( x = 0; x < itm->samp_count; x++ ) + { + if( verbose ) + { + printf( " * %2i", x+1 ); + cc++; + if( cc == 15) + { + cc=0; + printf("\n"); + } + } + Create_IT_Instrument( &itm->instruments[x], x+1 ); + } + if( verbose ) + { + if( cc != 0 ) + printf( (((x+1)%15)==0)?"":"\n" ); + printf( vstr_it_div ); + } + } + + if(verbose) + { + printf( "Reading Patterns...\n" ); + printf( vstr_it_div ); + } + + // read patterns + cc=0; + for( x = 0; x < itm->patt_count; x++ ) + { + file_seek_read( parap_patt[x], SEEK_SET ); + if( parap_patt[x] != 0 ) + { + if( verbose ) + { + printf( vstr_it_pattern, x+1 ); + cc++; + if( cc == 15 ) + { + cc=0; + printf("\n"); + } + } + Load_IT_Pattern( &itm->patterns[x] ); + + } + else + { + Empty_IT_Pattern( &itm->patterns[x] ); + //memset( &itm->patterns[x], 0, sizeof( Pattern ) ); + } + } + + + if( verbose ) + { + if( cc != 0 ) + printf( "\n" ); + printf( vstr_it_div ); + printf( "Loading Sample Data...\n" ); + } + // read sample data + for( x = 0; x < itm->samp_count; x++ ) + { + file_seek_read( itm->samples[x].datapointer, SEEK_SET ); + Load_IT_SampleData( &itm->samples[x], cmwt ); + } + + if( verbose ) + { + printf( vstr_it_div ); + } + + free( parap_inst ); + free( parap_samp ); + free( parap_patt ); + + return ERR_NONE; +} + +/* * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE + + -The following sample decompression code is based on CHIBITRACKER's code (http://chibitracker.berlios.de) which is based on xmp's code.(http://xmp.helllabs.org) which is based in openCP code. + +* NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE * NOTICE */ + +int Load_IT_CompressedSampleBlock( u8** buffer ) +{ + u32 size; + u32 x; + size = read16(); + (*buffer) = (u8*)malloc( size+4 ); + (*buffer)[size+0]=0; + (*buffer)[size+1]=0; + (*buffer)[size+2]=0; + (*buffer)[size+3]=0; + for( x = 0; x < size; x++ ) + (*buffer)[x] = read8(); + return ERR_NONE; +} + +int Load_IT_Sample_CMP( u8 *p_dest_buffer, int samp_len, u16 cmwt, bool bit16 ) +{ + u8* c_buffer=NULL; + u16 block_length; // length of compressed data block in samples + u16 block_position; // position in block + u8 bit_width; // actual "bit width" + u32 aux_value; // value read from file to be processed + s16 d1, d2; // integrator buffers (d2 for it2.15) + s8 d18, d28; + s8 v8; // sample value + s16 v16; // sample value 16 bit + bool it215; // is this an it215 module? + u16 border; + u8 tmp_shift; + u32 bit_readpos=0; + int i; + + u32 nbits, dsize; + + u8 *dest8_write = (u8 *)p_dest_buffer; + u16 *dest16_write = (u16 *)p_dest_buffer; + + nbits = bit16 ? 16 : 8; + dsize = bit16 ? 4 : 3; + for (i=0;i read new width; + bit_readpos += dsize; + bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; + // and expand it + continue; // ... next value + } + } + else + { + if ( aux_value == ((u32)1 << ((u32)bit_width - 1)) ) { // check for "100..." + + aux_value = readbits( c_buffer, bit_readpos, dsize )+1; //read_n_bits_from_IT_compressed_block(3) + 1; // yes -> read new width; + bit_readpos += dsize; + bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; + // and expand it + continue; // ... next value + } + } + + } else if ( bit_width < nbits + 1 ) { // method 2 (7-8 bits) + + if( bit16 ) + { + border = (0xFFFF >> ((nbits+1) - bit_width)) - (nbits/2); + // lower border for width chg + + if ( (int)aux_value > (int)border && (int)aux_value <= ((int)border + nbits) ) { + + aux_value -= border; // convert width to 1-8 + bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; + // and expand it + continue; // ... next value + } + } + else + { + border = (0xFF >> ((nbits+1) - bit_width)) - (nbits/2); + // lower border for width chg + + if ( aux_value > border && aux_value <= (border + nbits) ) { + + aux_value -= border; // convert width to 1-8 + bit_width = (aux_value < bit_width) ? aux_value : aux_value + 1; + // and expand it + continue; // ... next value + } + } + + } else if ( bit_width == nbits+1 ) { // method 3 (9 bits) + + if ( aux_value & (1<>=tmp_shift; + } + else + { + v8=(aux_value << tmp_shift); + v8>>=tmp_shift; + } + + } + else + { + if( bit16 ) + v16 = (s16) aux_value; + else + v8 = (s8) aux_value; + } + + if( bit16 ) + { + // integrate upon the sample values + d1 += v16; + d2 += d1; + + // ... and store it into the buffer + *(dest16_write++) = (it215 ? d2+32768 : d1+32768); + } + else + { + // integrate upon the sample values + d18 += v8; + d28 += d18; + + // ... and store it into the buffer + *(dest8_write)++ = (it215 ? (int)d28+128 : (int)d18+128); + } + block_position++; + + } + + // now subtract block lenght from total length and go on + if( c_buffer ) { + free( c_buffer ); c_buffer=NULL; } + samp_len -= block_length; + } + + return ERR_NONE; +} diff --git a/tools/mmutil/it.h b/tools/mmutil/it.h new file mode 100644 index 0000000..c7ac6af --- /dev/null +++ b/tools/mmutil/it.h @@ -0,0 +1,28 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include +#include + +u32 time_start; + +void kiwi_start( void ) +{ + int r; + time_start = time(NULL); + srand( time_start ); + r=0; + + rand();rand();rand();rand();rand();rand();rand();rand();rand();rand();rand();rand();rand();rand(); + + switch( r ) + { + case 0: + printf( "Your lucky number today is %i!\n", rand() ); + break; + } + +} diff --git a/tools/mmutil/main.c b/tools/mmutil/main.c new file mode 100644 index 0000000..4d0dae4 --- /dev/null +++ b/tools/mmutil/main.c @@ -0,0 +1,493 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include +#include +#include + +#include "defs.h" +#include "mas.h" +#include "mod.h" +#include "s3m.h" +#include "xm.h" +#include "it.h" +#include "gba.h" +#include "nds.h" +#include "files.h" +#include "errors.h" +#include "simple.h" +#include "msl.h" +#include "systems.h" +#include "wav.h" +#include "samplefix.h" + +extern void kiwi_start(void); + +int target_system; + +bool ignore_sflags; +int PANNING_SEP; + +int number_of_inputs; + +#define USAGE "\n\ +************************\n\ +* Maxmod Utility *\n\ +************************\n\ +\n\ +Usage:\n\ + mmutil [options] input files ...\n\ +\n\ + Input may be MOD, S3M, XM, IT, and/or WAV\n\ +\n\ +.------------.----------------------------------------------------.\n\ +| Option | Description |\n\ +|------------|----------------------------------------------------|\n\ +| -o | Set output file. |\n\ +| -h
| Set header output file. |\n\ +| -m | Output MAS file rather than soundbank. |\n\ +| -d | Use for NDS projects. |\n\ +| -b | Create test ROM. (use -d for .nds, otherwise .gba) |\n\ +| -i | Ignore sample flags. |\n\ +| -v | Enable verbose output. |\n\ +| -p | Set initial panning separation for MOD/S3M. |\n\ +`-----------------------------------------------------------------'\n\ +\n\ +.-----------------------------------------------------------------.\n\ +| Examples: |\n\ +|-----------------------------------------------------------------|\n\ +| Create DS soundbank file (soundbank.bin) from input1.xm |\n\ +| and input2.it Also output header file (soundbank.h) |\n\ +| |\n\ +| mmutil -d input1.xm input2.it -osoundbank.bin -hsoundbank.h |\n\ +|-----------------------------------------------------------------|\n\ +| Create test GBA ROM from two inputs |\n\ +| |\n\ +| mmutil -b input1.mod input2.s3m -oTEST.gba |\n\ +|-----------------------------------------------------------------|\n\ +| Create test NDS ROM from three inputs |\n\ +| |\n\ +| mmutil -d -b input1.xm input2.s3m testsound.wav |\n\ +`-----------------------------------------------------------------'\n\ + www.maxmod.org\n\ +" + +void print_usage( void ) +{ + printf( USAGE ); +} + +void print_error( int err ) +{ + switch( err ) + { + case ERR_INVALID_MODULE: + printf( "Invalid module!\n" ); + break; + case ERR_MANYARGS: + printf( "Too many arguments!\n" ); + break; + case ERR_NOINPUT: + printf( "No input file!\n" ); + break; + case ERR_NOWRITE: + printf( "Unable to write file!\n" ); + break; + case ERR_BADINPUT: + printf( "Cannot parse input filename!\n" ); + break; + } +} + +int GetYesNo( void ) +{ + char c = 0; + c = tolower(getchar()); + while( getchar() != '\n' ); + while( c != 'y' && c != 'n' ) + { + printf( "Was that a yes? " ); + c = tolower(getchar()); + while( getchar() != '\n' ); + } + return c == 'y' ? 1 : 0; +} + +//------------------------------------------------------------------------------------------------ +int main(int argc, char* argv[]) +//------------------------------------------------------------------------------------------------ +{ + char* str_input=NULL; + char* str_output=NULL; + char* str_header=NULL; + + MAS_Module mod; + + int strl; + + int input_type=0; + + int strp; + int strpi; + + bool g_flag=false; + bool v_flag=false; + bool m_flag=false; + bool z_flag=false; + int a; + + int output_size; + + ignore_sflags=false; + + number_of_inputs=0; + + PANNING_SEP = 128; + + //------------------------------------------------------------------------ + // parse arguments + //------------------------------------------------------------------------ + + for( a = 1; a < argc; a++ ) + { + if( argv[a][0] == '-' ) + { + if( argv[a][1] == 'b' ) + g_flag = true; + else if( argv[a][1] == 'v' ) + v_flag = true; + else if( argv[a][1] == 'd' ) + target_system = SYSTEM_NDS; + else if( argv[a][1] == 'i' ) + ignore_sflags = true; + else if( argv[a][1] == 'p' ) + PANNING_SEP = ((argv[a][2] - '0') * 256)/9; + else if( argv[a][1] == 'o' ) + str_output = argv[a]+2; + else if( argv[a][1] == 'h' ) + str_header = argv[a]+2; + else if( argv[a][1] == 'm' ) + m_flag = true; + else if( argv[a][1] == 'z' ) + z_flag = true; + } + else if( !str_input ) + { + str_input = argv[a]; + number_of_inputs=1; + } + else + { + number_of_inputs++; + } + } + + if( number_of_inputs==0 ) + { + print_usage(); + return 0; + } + + if( z_flag ) + { + kiwi_start(); + file_open_read( str_input ); + Sample s; + + Load_WAV( &s, false,false ); + + s.name[0] = '%'; + s.name[1] = 'c'; + s.name[2] = 0; + + FixSample( &s ); + + file_close_read(); + file_open_write( str_output ); + + int i; + for( i = 0; i < s.sample_length; i++ ) + write8( ((u8*)s.data)[i] ); + + file_close_write(); + printf("okay\n"); + return 0; + } + + if( m_flag & g_flag ) + { + printf("-m and -g cannot be combined.\n"); + return -1; + } + + if( m_flag && number_of_inputs != 1 ) + { + printf( "-m only supports one input.\n" ); + return -1; + } + + //--------------------------------------------------------------------------- + // m/g generate output target if not given + //--------------------------------------------------------------------------- + + if( m_flag || g_flag) + { + if( !str_output ) + { + if( number_of_inputs == 1 ) + { + if( strlen(str_input) < 4 ) + { + print_error( ERR_BADINPUT ); + return -1; + } + strp = strlen(str_input); + str_output = (char*)malloc( strp+2 ); + strcpy(str_output, str_input); + strp=strlen(str_output)-1; + + for( strpi=strp; str_output[strpi] != '.' && strpi != 0; strpi-- ); + if( strpi == 0 ) + { + print_error( ERR_BADINPUT ); + return -1; + } + + str_output[strpi++] = '.'; + if( !g_flag ) + { + str_output[strpi++] = 'm'; + str_output[strpi++] = 'a'; + str_output[strpi++] = 's'; + str_output[strpi++] = 0; + } + else + { + if( target_system == SYSTEM_GBA ) + { + str_output[strpi++] = 'g'; + str_output[strpi++] = 'b'; + str_output[strpi++] = 'a'; + str_output[strpi++] = 0; + } + else if( target_system == SYSTEM_NDS ) + { + str_output[strpi++] = 'n'; + str_output[strpi++] = 'd'; + str_output[strpi++] = 's'; + str_output[strpi++] = 0; + } + else + { + // error! + } + } + str_output[strpi++] = 0; + } + else + { + printf( "No output file! (-o option)\n" ); + return -1; + } + } + } + + // catch filename too small + strl=strlen(str_input); + if( strl < 4 ) + { + print_error( ERR_BADINPUT ); + return -1; + } + + if( m_flag ) + { + if( file_open_read( str_input ) ) + { + printf( "Cannot open %s for reading!\n", str_input ); + return -1; + } + input_type = get_ext( str_input ); + + switch( input_type ) + { + //------------------------------------------------------ + case INPUT_TYPE_MOD: + //------------------------------------------------------ + if( Load_MOD( &mod, v_flag ) ) + { + print_error( ERR_INVALID_MODULE ); + file_close_read(); + return -1; + } + break; + //------------------------------------------------------ + case INPUT_TYPE_S3M: + //------------------------------------------------------ + if( Load_S3M( &mod, v_flag ) ) + { + print_error( ERR_INVALID_MODULE ); + file_close_read(); + return -1; + } + break; + //------------------------------------------------------ + case INPUT_TYPE_XM: + //------------------------------------------------------ + if( Load_XM( &mod, v_flag ) ) + { + print_error( ERR_INVALID_MODULE ); + file_close_read(); + return -1; + } + break; + //------------------------------------------------------ + case INPUT_TYPE_IT: + //------------------------------------------------------ + if( Load_IT( &mod, v_flag ) ) + { + // ERROR! + print_error( ERR_INVALID_MODULE ); + file_close_read(); + return -1; + } + break; + } + + file_close_read(); + + if( file_exists( str_output ) ) + { + printf( "Output file exists! Overwrite? (y/n) " ); + if( !GetYesNo() ) + { + printf( "Operation Canceled!\n" ); + return -1; + } + + } + + if( file_open_write( str_output ) ) + { + print_error( ERR_NOWRITE ); + return -1; + } + + printf( "Writing .mas............\n" ); + + // output MAS + output_size = Write_MAS( &mod, v_flag, false ); + + + file_close_write(); + + Delete_Module( &mod ); + + if( v_flag ) + { +#ifdef SUPER_ASCII + printf( "Success! \x02 \n" ); +#else + printf( "Success! :) \n" ); +#endif + } + } + else if( g_flag ) + { + int i; + + MSL_Create( argv, argc, "tempSH308GK.bin", 0, v_flag ); + + if( file_exists( str_output ) ) + { + printf( "Output file exists! Overwrite? (y/n) " ); + if( !GetYesNo() ) + { + printf( "Operation Canceled!\n" ); + return -1; + } + + } + + if( file_open_write( str_output ) ) + { + print_error( ERR_NOWRITE ); + return -1; + } + + if( target_system == SYSTEM_GBA ) + { + if( v_flag ) + printf( "Making GBA ROM.......\n" ); + Write_GBA(); + } + else if( target_system == SYSTEM_NDS ) + { + if( v_flag ) + printf( "Making NDS ROM.......\n" ); + Write_NDS(); + } + + output_size = file_size( "tempSH308GK.bin" ); + file_open_read( "tempSH308GK.bin" ); + + if( target_system == SYSTEM_GBA ) + { + write32( (output_size < 248832) ? 1 : 0 ); + } + + for( i = 0; i < output_size; i++ ) + { + write8( read8() ); + } + + file_close_read(); + file_close_write(); + + file_delete( "tempSH308GK.bin" ); + + if( g_flag && target_system == SYSTEM_NDS ) + Validate_NDS( str_output, output_size ); + + if( v_flag ) + { + printf( "Success! :D\n" ); + + if( g_flag && target_system == SYSTEM_GBA ) + { + if( output_size < 262144 ) + { + printf("ROM can be multibooted!!\n" ); + } + } + } + } + else + { + MSL_Create( argv, argc, str_output, str_header, v_flag ); + } + return 0; +} diff --git a/tools/mmutil/mas.c b/tools/mmutil/mas.c new file mode 100644 index 0000000..b739a0e --- /dev/null +++ b/tools/mmutil/mas.c @@ -0,0 +1,620 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include "defs.h" +#include "files.h" +#include "mas.h" +#include "simple.h" +#include "systems.h" +#include "version.h" + +u32 MAS_OFFSET; +u32 MAS_FILESIZE; + +static int CalcEnvelopeSize( Instrument_Envelope* env ) +{ + return (env->node_count*4) + 8; +} + +static int CalcInstrumentSize( Instrument* instr ) +{ + int size; + size = 12; + if( instr->env_flags & 1 ) // volume envelope exists + size += CalcEnvelopeSize( &instr->envelope_volume ); + if( instr->env_flags & 2 ) // panning envelope exists + size += CalcEnvelopeSize( &instr->envelope_pan ); + if( instr->env_flags & 4 ) // pitch envelope exists + size += CalcEnvelopeSize( &instr->envelope_pitch ); + return size; +} + +void Write_Instrument_Envelope( Instrument_Envelope* env ) +{ + int x; + write8( (u8)(env->node_count*4 + 8) ); // maximum is 6+75 + write8( env->loop_start ); + write8( env->loop_end ); + write8( env->sus_start ); + write8( env->sus_end ); + write8( env->node_count ); + write8( env->env_filter ); + write8( BYTESMASHER ); + if( env->node_count > 1 ) + { + int delta; + int base; + int range; + for( x = 0; x < env->node_count; x++ ) + { + base = env->node_y[x]; + if( x != env->node_count-1 ) + { + + range = env->node_x[x+1] - env->node_x[x]; + if( range > 511 ) range = 511; + if( range < 1 ) range = 1; + delta = (((env->node_y[x+1] - base) * 512) + (range/2)) / range; + if( delta > 32767 ) delta = 32767; + if( delta < -32768 ) delta = -32768; + while( (base+ ((delta*range)>>9)) > 64 ) delta--; + while( (base+ ((delta*range)>>9)) < 0 ) delta++; + } + else + { + range = 0; + delta=0; + } + write16( (u16)delta ); + write16( (u16)(base | (range<<7)) ); + } + } +} + +void Write_Instrument( Instrument* inst ) +{ + int y; + int full_notemap; + int first_notemap_samp; + align32(); + inst->parapointer = file_tell_write()-MAS_OFFSET; + /*write8( inst->global_volume ); + write8( (u8)inst->fadeout ); + write8( inst->random_volume ); + write8( inst->nna ); + write8( inst->dct ); + write8( inst->dca ); + write8( inst->env_flags ); + write8( inst->setpan );*/ + + write8( inst->global_volume ); + write8( (u8)inst->fadeout ); + write8( inst->random_volume ); + write8( inst->dct ); + write8( inst->nna ); + write8( inst->env_flags ); + write8( inst->setpan ); + write8( inst->dca ); + + full_notemap = 0; + first_notemap_samp = (inst->notemap[0] >> 8); + for( y = 0; y < 120; y++ ) + { + if( ((inst->notemap[y] & 0xFF) != y) || + ((inst->notemap[y] >> 8) != first_notemap_samp) ) + { + full_notemap = 1; + break; + } + } + + if( full_notemap ) + { + // full notemap + // write offset here + write16( (u16)CalcInstrumentSize( inst ) ); + } + else + { + // single notemap entry + write16( (u16)(0x8000 | first_notemap_samp) ); + } + + write16( 0 ); // reserved space + + if( inst->env_flags & 1 ) // write volume envelope + Write_Instrument_Envelope( &inst->envelope_volume ); + if( inst->env_flags & 2 ) // write panning envelope + Write_Instrument_Envelope( &inst->envelope_pan ); + if( inst->env_flags & 4 ) // write pitch envelope + Write_Instrument_Envelope( &inst->envelope_pitch ); + + if( full_notemap ) + { + for( y = 0; y < 120; y++ ) + write16( inst->notemap[y] ); + } +} + +void Write_SampleData( Sample* samp ) +{ + u32 x; + u32 sample_length = samp->sample_length; + u32 sample_looplen = samp->loop_end - samp->loop_start; + + if( target_system == SYSTEM_GBA ) + { + write32( sample_length ); + write32( samp->loop_type ? sample_looplen : 0xFFFFFFFF ); + write8( SAMP_FORMAT_U8 ); + write8( BYTESMASHER ); + write16( (u16) ((samp->frequency * 1024 + (15768/2)) / 15768) ); + // write32( 0); + } + else + { + if( samp->format & SAMPF_16BIT ) + { + if( samp->loop_type ) + { + write32( samp->loop_start / 2 ); + write32( (samp->loop_end-samp->loop_start) / 2 ); + } + else + { + write32( 0 ); + write32( sample_length/2 ); + } + } + else + { + if( samp->loop_type ) + { + write32( samp->loop_start / 4 ); + write32( (samp->loop_end-samp->loop_start) / 4 ); + } + else + { + write32( 0 ); + write32( sample_length/4 ); + } + } + write8( sample_dsformat( samp ) ); + write8( sample_dsreptype( samp ) ); + write16( (u16) ((samp->frequency * 1024 + (32768/2)) / 32768) ); + write32( 0); + } + + // write sample data + if( samp->format & SAMPF_16BIT ) + { + for( x = 0; x < sample_length; x++ ) + write16( ((u16*)samp->data)[x] ); + + // add padding data + if( samp->loop_type ) + { + write16( ((u16*)samp->data)[samp->loop_start] ); + write16( ((u16*)samp->data)[samp->loop_start+1] ); + } + else + { + write16( 0 ); + write16( 0 ); + } + } + else + { + for( x = 0; x < sample_length; x++ ) + write8( ((u8*)samp->data)[x] ); + + // add padding data + if( samp->loop_type ) + { + write8( ((u8*)samp->data)[samp->loop_start] ); + write8( ((u8*)samp->data)[samp->loop_start+1] ); + write8( ((u8*)samp->data)[samp->loop_start+2] ); + write8( ((u8*)samp->data)[samp->loop_start+3] ); + } + else + { + for ( x = 0; x < 4; x++ ) + write8( (target_system == SYSTEM_GBA) ? 128 : 0 ); + } + } +} + +void Write_Sample( Sample* samp ) +{ + align32(); // align data by 32 bits + samp->parapointer = file_tell_write()-MAS_OFFSET; + + write8( samp->default_volume ); + write8( samp->default_panning ); + write16( (u16)(samp->frequency/4) ); + write8( samp->vibtype ); + write8( samp->vibdepth ); + write8( samp->vibspeed ); + write8( samp->global_volume ); + write16( samp->vibrate ); + + write16( samp->msl_index ); + + if( samp->msl_index == 0xFFFF ) + Write_SampleData(samp); +} + +void Write_Pattern( Pattern* patt, bool xm_vol ) +{ + int row; + int col; + + u16 last_mask[MAX_CHANNELS]; + u16 last_note[MAX_CHANNELS]; + u16 last_inst[MAX_CHANNELS]; + u16 last_vol[MAX_CHANNELS]; + u16 last_fx[MAX_CHANNELS]; + u16 last_param[MAX_CHANNELS]; + + u8 chanvar; + u8 maskvar; + + u8 emptyvol; + + PatternEntry* pe; + + patt->parapointer = file_tell_write()-MAS_OFFSET; + write8( (u8)(patt->nrows-1) ); + + patt->cmarks[0] = true; + emptyvol = xm_vol ? 0 : 255; + + // using IT pattern compression + + for( row = 0; row < patt->nrows; row++ ) + { + if( patt->cmarks[row] ) + { + for( col=0;coldata[row*MAX_CHANNELS+col]; + if( ((pe->note != 250) || (pe->inst != 0) || (pe->vol != emptyvol) || (pe->fx != 0) || (pe->param != 0)) ) + { + maskvar = 0; + chanvar = col+1; + if( pe->note != 250 ) + maskvar |= 1|16; + + if( pe->inst != 0 ) + maskvar |= 2|32; + + if( pe->note > 250 ) // noteoff/cut disabled start+reset + maskvar &= ~(16|32); + + if( pe->vol != emptyvol ) + maskvar |= 4|64; + + if( pe->fx != 0 || pe->param != 0 ) + maskvar |= 8|128; + + if( maskvar & 1 ) + { + if( pe->note == last_note[col] ) + { + maskvar &= ~1; + } + else + { + last_note[col] = pe->note; + if( last_note[col] == 254 || last_note[col] == 255 ) // DONT LET NOTEOFF/NOTECUT USE PREVIOUS PARAMETERS! + last_note[col] = 256; + } + } + + if( maskvar & 2 ) + { + if( pe->inst == last_inst[col] ) + { + maskvar &= ~2; + } + else + { + last_inst[col] = pe->inst; + } + } + + if( maskvar & 4 ) + { + if( pe->vol == last_vol[col] ) + { + maskvar &= ~4; + } + else + { + last_vol[col] = pe->vol; + } + } + + if( maskvar & 8 ) + { + if( (pe->fx == last_fx[col]) && (pe->param == last_param[col]) ) + { + maskvar &= ~8; + } + else + { + last_fx[col] = pe->fx; + last_param[col] = pe->param; + } + } + + if( maskvar != last_mask[col] ) + { + chanvar |= 128; + last_mask[col] = maskvar; + } + + write8( chanvar ); + if( chanvar & 128 ) + write8( maskvar ); + if( maskvar & 1 ) + write8( pe->note ); + if( maskvar & 2 ) + write8( pe->inst ); + if( maskvar & 4 ) + write8( pe->vol ); + if( maskvar & 8 ) + { + write8( pe->fx ); + write8( pe->param ); + } + } + else + { + continue; + } + } + write8( 0 ); + } + +} + +void Mark_Pattern_Row( MAS_Module* mod, int order, int row ) +{ + Pattern* p; + + if( row >= 256 ) + return; + if( mod->orders[order] == 255 ) + order = 0; + while( mod->orders[order] >= 254 ) + { + if( mod->orders[order] == 255 ) + return; + if( mod->orders[order] == 254 ) + order++; + } + p = &(mod->patterns[mod->orders[order]]); + p->cmarks[row] = true; +} + +void Mark_Patterns( MAS_Module* mod ) +{ + + int o; + int p; + int row; + int col; + + PatternEntry* pe; + + for( o = 0; o < mod->order_count; o++ ) + { + p = mod->orders[o]; + if( p == 255 ) + break; + if( p == 254 ) + continue; + if( p >= mod->patt_count ) + continue; + for( row = 0; row < mod->patterns[p].nrows; row++ ) + { + for( col = 0; col < MAX_CHANNELS; col++ ) + { + pe = &(mod->patterns[p].data[row*MAX_CHANNELS+col]); + if( pe->fx == 3 ) // PATTERN BREAK + { + if( pe->param != 0 ) // if param != 0 then mark next pattern + { + Mark_Pattern_Row( mod, o+1, pe->param ); + } + } + else if( pe->fx == 19 ) + { + if( pe->param == 0xB0 ) + { + Mark_Pattern_Row( mod, o, row ); + } + } + } + } + } +} + +int Write_MAS( MAS_Module* mod, bool verbose, bool msl_dep ) +{ + // SEE MAS_FORM.TXT + int x; //,y; + int fpos_pointer; +// u8 rsamp=0; +// u16 rsamps[200]; +// bool unique=false; + + file_get_byte_count(); + + write32( BYTESMASHER ); + write8( MAS_TYPE_SONG ); + write8( MAS_VERSION ); + write8( BYTESMASHER ); + write8( BYTESMASHER ); + + MAS_OFFSET = file_tell_write(); + + write8( (u8)mod->order_count ); + write8( mod->inst_count ); + write8( mod->samp_count ); + write8( mod->patt_count ); + write8( (u8)((mod->link_gxx ? 1 : 0) | (mod->old_effects ? 2 : 0) | (mod->freq_mode ? 4 : 0) | (mod->xm_mode ? 8 : 0) | (msl_dep ? 16 : 0) | (mod->old_mode ? 32 : 0)) ); + write8( mod->global_volume ); + write8( mod->initial_speed ); + write8( mod->initial_tempo ); + write8( mod->restart_pos ); + +/* for( x = 0; x < mod->samp_count; x++ ) + { + unique=true; + for( y = x-1; y >= 0; y-- ) + { + if( mod->samples[x].msl_index == mod->samples[y].msl_index ) + { + mod->samples[x].rsamp_index = mod->samples[y].rsamp_index; + unique=false; + break; + } + } + if( unique ) + { + rsamps[rsamp]=mod->samples[x].msl_index; + mod->samples[x].rsamp_index = rsamp; + rsamp++; + } + } + write8( rsamp );*/ + write8( BYTESMASHER ); + write8( BYTESMASHER );write8( BYTESMASHER ); + for( x = 0; x < MAX_CHANNELS; x++ ) + write8( mod->channel_volume[x] ); + for( x = 0; x < MAX_CHANNELS; x++ ) + write8( mod->channel_panning[x] ); + for( x = 0; x < mod->order_count; x++ ) + { + if( mod->orders[x] < 254 ) + { + if( mod->orders[x] < mod->patt_count ) + write8( mod->orders[x] ); + else + write8( 254 ); + } + else + { + write8( mod->orders[x] ); + } + } + for( ; x < 200; x++ ) + write8( 255 ); + // reserve space for offsets + fpos_pointer = file_tell_write(); + for( x = 0; x < mod->inst_count*4+mod->samp_count*4+mod->patt_count*4; x++ ) + write8( BYTESMASHER ); // BA BA BLACK SHEEP +/* if( msl_dep && target_system == SYSTEM_NDS ) + { + for( x = 0; x < rsamp; x++ ) // write sample indeces + write16( rsamps[x] ); + }*/ + // WRITE INSTRUMENTS + + if( verbose ) + printf("Header: %i bytes\n", file_get_byte_count() ); + + for( x = 0; x < mod->inst_count; x++ ) + Write_Instrument( &mod->instruments[x] ); + + + + for( x = 0; x < mod->samp_count; x++ ) + Write_Sample( &mod->samples[x] ); + + if( verbose ) + printf("Instruments: %i bytes\n", file_get_byte_count() ); + + Mark_Patterns( mod ); + for( x = 0; x < mod->patt_count; x++ ) + { +// for( y = 0; y < mod->order_count; y++ ) +// { +// if( mod->orders[y] == x ) + Write_Pattern( &mod->patterns[x], mod->xm_mode ); +// } + } + align32(); + + if( verbose ) + printf("Patterns: %i bytes\n", file_get_byte_count() ); + MAS_FILESIZE = file_tell_write() - MAS_OFFSET; + file_seek_write( MAS_OFFSET-8, SEEK_SET ); + write32( MAS_FILESIZE ); + file_seek_write( fpos_pointer, SEEK_SET ); + for( x = 0; x < mod->inst_count; x++ ) + write32( mod->instruments[x].parapointer ); + for( x = 0; x < mod->samp_count; x++ ) + { + printf("sample %s is at %d/%d of %d\n", mod->samples[x].name, mod->samples[x].parapointer, + file_tell_write(), mod->samples[x].sample_length); + write32( mod->samples[x].parapointer ); + } + for( x = 0; x < mod->patt_count; x++ ) + write32( mod->patterns[x].parapointer ); + return MAS_FILESIZE; +} + +void Delete_Module( MAS_Module* mod ) +{ + int x; + if( mod->instruments ) + free( mod->instruments ); + if( mod->samples ) + { + for( x = 0; x < mod->samp_count; x++ ) + { + if( mod->samples[x].data ) + free( mod->samples[x].data ); + } + free( mod->samples ); + } + if( mod->patterns ) + { + free( mod->patterns ); + } +} diff --git a/tools/mmutil/mas.h b/tools/mmutil/mas.h new file mode 100644 index 0000000..c85f5a9 --- /dev/null +++ b/tools/mmutil/mas.h @@ -0,0 +1,167 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include +#include +#include "defs.h" +#include "mas.h" +#include "mod.h" +#include "xm.h" +#include "files.h" +#include "simple.h" +#include "errors.h" +#include "samplefix.h" + +#ifdef SUPER_ASCII +#define vstr_mod_div "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n" +#define vstr_mod_samp_top "ÚÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\n" +#define vstr_mod_samp_header "³INDEX³LENGTH³LOOP ³VOLUME³ MID-C ³ NAME ³\n" +#define vstr_mod_samp_slice "ÃÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n" +#define vstr_mod_samp "³ %2i ³%5i ³ %3s ³ %3i%% ³ %ihz³ %-22s³\n" +#define vstr_mod_samp_bottom "ÀÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\n" +#define vstr_mod_pattern " \x0e %2i%s" +#else +#define vstr_mod_div "--------------------------------------------\n" +#define vstr_mod_samp_top vstr_mod_div +#define vstr_mod_samp_header " INDEX LENGTH LOOP VOLUME MID-C NAME \n" +//#define vstr_mod_samp_slice "" +#define vstr_mod_samp " %-2i %-5i %-3s %3i%% %ihz %-22s \n" +#define vstr_mod_samp_bottom vstr_mod_div +#define vstr_mod_pattern " * %2i%s" +#endif + +#ifdef _MSC_VER +double round( double value ) +{ + return floor(value+0.5); +} +#endif + +int Create_MOD_Instrument( Instrument* inst, u8 sample ) +{ + int x; + memset( inst, 0, sizeof( Instrument ) ); + inst->global_volume = 128; + // setup notemap + for( x = 0; x < 120; x++ ) + { + inst->notemap[x] = x | ((sample+1)<<8); + } + return ERR_NONE; +} + +int Load_MOD_SampleData( Sample* samp ) +{ + u32 t; + if( samp->sample_length > 0 ) + { + samp->data = (u8*)malloc( samp->sample_length ); // allocate a SAMPLE_LENGTH sized pointer to buffer in memory and load the sample into it + for( t = 0; t < samp->sample_length; t++ ) + { + ((u8*)samp->data)[t] = read8() + 128; // unsign data + } + } + FixSample( samp ); + return ERR_NONE; +} + +int Load_MOD_Pattern( Pattern* patt, u8 nchannels, u8* inst_count ) +{ + u8 data1; + u8 data2; + u8 data3; + u8 data4; + + u16 period; + u8 inst; + u8 effect; + u8 param; + + u32 row; + u32 col; + + PatternEntry* p; + + memset( patt, 0, sizeof( Pattern ) ); + patt->nrows = 64; // MODs have fixed 64 rows per pattern + + for( row = 0; row < 64*MAX_CHANNELS; row++ ) + { + patt->data[row].note = 250; + } + + for( row = 0; row < 64; row++ ) + { + for( col = 0; col < nchannels; col++ ) + { + data1 = read8(); // +-------------------------------------+ + data2 = read8(); // | Byte 0 Byte 1 Byte 2 Byte 3 | + data3 = read8(); // |-------------------------------------| + data4 = read8(); // |aaaaBBBB CCCCCCCCC DDDDeeee FFFFFFFFF| + // +-------------------------------------+ + + period = (data1&0xf)*256 + (data2); // BBBBCCCCCCCC = sample period value + inst = (data1&0xF0)+(data3>>4); // aaaaDDDD = sample number + effect = data3&0xF; // eeee = effect number + param = data4; // FFFFFFFF = effect parameters + + // fix parameter for certain MOD effects + switch( effect ) + { + case 5: // 5xy glis+slide + case 6: // 6xy vib+slide + if( param & 0xF0 ) // clear Y if X + param &= 0xF0; + } + + p = &patt->data[row*MAX_CHANNELS+col]; // copy data to pattern entry + p->inst = inst; // ... + CONV_XM_EFFECT( &effect, ¶m ); // ... + p->fx = effect; // ... + p->param = param; // ... + + if( period != 0 ) // 0 = no note, otherwise calculate note value from the amiga period + p->note = (int)round(12.0*log( (856.0)/(double)period )/log(2)) + 37 + 11; + if( *inst_count < (inst + 1) ) + { + *inst_count = (inst + 1); + if( *inst_count > 31 ) + *inst_count = 31; + } + } + } + return ERR_NONE; +} + +int Load_MOD_Sample( Sample* samp, bool verbose, int index ) +{ + int finetune; + int x; + + memset( samp, 0, sizeof( Sample ) ); + samp->msl_index = 0xFFFF; + for( x = 0; x < 22; x++ ) + samp->name[x] = read8(); // read in 22 bytes, store as SAMPLE_NAME + for( x = 0; x < 12; x++ ) // copy to filename + samp->filename[x] = samp->name[x]; + samp->sample_length = (read8()*256 + read8()) * 2; // read in 2 bytes (word), store as SAMPLE_LENGTH + finetune = read8(); // read in 1 byte, store as FINE_TUNE + if( finetune >= 8 ) finetune -= 16; + + samp->default_volume = read8(); // read in 1 byte, store as VOLUME + samp->loop_start = (read8()*256 + read8()) * 2; // read in 2 bytes (word), store as LOOP_START + samp->loop_end = samp->loop_start + (read8()*256+read8())*2; // read in 2 bytes (word), store as LOOP_LENGTH + + // IS THIS WRONG?? : + samp->frequency = (int)(8363.0 * pow( 2.0, ((double)finetune) * (1.0/192.0) ) ); // calculate frequency... + + samp->global_volume=64; // max global volume + if( (samp->loop_end - samp->loop_start) <= 2 ) // if loop length <= 2 then disabled loop + { + samp->loop_type = samp->loop_start = samp->loop_end = 0; + } + else + { + samp->loop_type = 1; // otherwise enable + } + if( verbose ) + { + if( samp->sample_length != 0 ) + { + //printf( "%i %s %i%% %ihz\n", samp->sample_length, samp->loop_type != 0 ? "Yes" : "No", (samp->default_volume*100)/64, samp->frequency ); + printf( vstr_mod_samp, index, samp->sample_length, samp->loop_type != 0 ? "Yes" : "No", (samp->default_volume*100)/64, samp->frequency, samp->name ); + /* + printf( " Length......%i\n", samp->sample_length ); + if( samp->loop_type != 0 ) + { + printf( " Loop........%i->%i\n", samp->loop_start, samp->loop_end ); + } + else + { + printf( " Loop........None\n" ); + } + printf( " Volume......%i\n", samp->default_volume ); + printf( " Middle C....%ihz\n", samp->frequency );*/ + } + else + { + //printf( "---\n" ); + } + } + return ERR_NONE; +} + +int Load_MOD( MAS_Module* mod, bool verbose ) +{ + u32 file_start; + u32 mod_channels; + int x; + + int npatterns; + + u32 sig; + char sigs[5]; + + if( verbose ) + printf( "Loading MOD, " ); + + memset( mod, 0, sizeof( MAS_Module ) ); + file_start = file_tell_read(); + file_seek_read( 0x438, SEEK_SET ); // Seek to offset 1080 (438h) in the file + sig = read32(); // read in 4 bytes + sigs[0]=sig&0xFF; + sigs[1]=(sig>>8)&0xFF; + sigs[2]=(sig>>16)&0xFF; + sigs[3]=(sig>>24); + sigs[4]=0; + switch( sig ) + { + case 'NHC1': + mod_channels=1; + break; + case 'NHC2': + mod_channels=2; + break; + case 'NHC3': + mod_channels=3; + break; + case '.K.M': // compare them to "M.K." - if true we have a 4 channel mod + case 'NHC4': + mod_channels=4; + break; + case 'NHC5': + mod_channels=5; + break; + case 'NHC6': + mod_channels=6; // compare them to "6CHN" - if true we have a 6 channel mod + break; + case 'NHC7': + mod_channels=7; + break; + case 'NHC8': // compare them to "8CHN" - if true we have an 8 channel mod + mod_channels=8; + break; + case 'NHC9': + mod_channels=9; + break; + default: + if( sig>>16 == 'HC' ) // There are also rare tunes that use **CH where ** = 10-32 channels + { + char chn_number[3]; + chn_number[0] = (char)(sig&0xFF); + chn_number[1] = (char)((sig>>8)&0xFF); + chn_number[2] = 0; + mod_channels = atoi( chn_number ); + if( mod_channels > MAX_CHANNELS ) + return ERR_MANYCHANNELS; + } + else + { + return ERR_INVALID_MODULE; // otherwise exit and display error message. + } + } + + file_seek_read( file_start, SEEK_SET ); // - Seek back to position 0, the start of the file + for( x = 0; x < 20; x++ ) + mod->title[x] = read8(); // - read in 20 bytes, store as MODULE_NAME. + + if( verbose ) + { + printf( "\"%s\"\n", mod->title ); + printf( "%i channels (%s)\n", mod_channels, sigs ); + } + + for( x = 0; x < MAX_CHANNELS; x++ ) + { + if( (x&3)!=1 && (x&3) != 2 ) + mod->channel_panning[x] = clamp_u8( 128 - (PANNING_SEP/2) ); + else + mod->channel_panning[x] = clamp_u8( 128 + (PANNING_SEP/2) ); + mod->channel_volume[x] = 64; + } + + // set MOD settings + mod->freq_mode = 0; + mod->global_volume = 64; + mod->initial_speed = 6; + mod->initial_tempo = 125; + mod->inst_count = 0; // filled in by Load_MOD_Pattern + mod->inst_mode = false; + mod->instruments = (Instrument*)malloc( 31 * sizeof( Instrument ) ); + mod->link_gxx = false; + mod->old_effects = true; + mod->restart_pos = 0; + mod->samp_count = 0; // filled in before Load_MOD_SampleData + mod->samples = (Sample*)malloc( 31 * sizeof( Sample ) ); + mod->stereo = true; + mod->xm_mode = true; + mod->old_mode=true; + + if( verbose ) + { + printf( vstr_mod_div ); + printf( "Loading Samples...\n" ); + printf( vstr_mod_samp_top ); + printf( vstr_mod_samp_header ); +#ifdef vstr_mod_samp_slice + printf( vstr_mod_samp_slice ); +#endif + } + // Load Sample Information + for( x = 0; x < 31; x++ ) + { + // if( verbose ) + //printf( "Loading Sample %i...\n", x+1 ); + Create_MOD_Instrument( &mod->instruments[x], (u8)x ); + Load_MOD_Sample( &mod->samples[x], verbose, x ); + } + + // read sequence + mod->order_count = read8(); // read a byte, store as SONG_LENGTH (this is the number of orders in a song) + mod->restart_pos = read8(); // read a byte, discard it (this is the UNUSED byte - used to be used in PT as the restart position, but not now since jump to pattern was introduced) + if( mod->restart_pos >= 127 ) + mod->restart_pos=0; + npatterns=0; // set NUMBER_OF_PATTERNS to equal 0......... or -1 :) + for( x = 0; x < 128; x++ ) // from this point, loop 128 times + { + mod->orders[x] = read8(); // read 1 byte, store it as ORDER + if( mod->orders[x] >= npatterns ) // if this value was bigger than NUMBER_OF_PATTERNS then set it to that value. + npatterns=mod->orders[x]+1; + } + + read32(); // read 4 bytes, discard them (we are at position 1080 again, this is M.K. etc!) + mod->patt_count = npatterns; + mod->patterns = (Pattern*)malloc( mod->patt_count * sizeof( Pattern ) ); // allocate patterns + + if( verbose ) + { + printf( vstr_mod_samp_bottom ); + printf( "Sequence has %i entries.\n", mod->order_count ); + printf( "Module has %i pattern%s.\n", mod->patt_count, mod->patt_count==1?"":"s" ); + printf( vstr_mod_div ); + printf( "Loading Patterns...\n" ); + printf( vstr_mod_div ); + } + + // Load Patterns + for( x = 0; x < mod->patt_count; x++ ) + { + if( verbose ) + { + printf( vstr_mod_pattern, x+1, ((x+1)%15)?"":"\n" ); + } + Load_MOD_Pattern( &mod->patterns[x], (u8)mod_channels, &(mod->inst_count) ); + } + if( verbose ) + { + printf( "\n" ); + printf( vstr_mod_div ); + } + // Load Sample Data + if( verbose ) + printf( "Loading Sample Data...\n" ); + mod->samp_count = mod->inst_count; + for( x = 0; x < 31; x++ ) + { + Load_MOD_SampleData( &mod->samples[x] ); + } + if( verbose ) + printf( vstr_mod_div ); + return ERR_NONE; +} diff --git a/tools/mmutil/mod.h b/tools/mmutil/mod.h new file mode 100644 index 0000000..83ad330 --- /dev/null +++ b/tools/mmutil/mod.h @@ -0,0 +1,28 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include +#include + +#include "errors.h" +#include "defs.h" +#include "files.h" +#include "mas.h" +#include "mod.h" +#include "s3m.h" +#include "xm.h" +#include "it.h" +#include "wav.h" +#include "simple.h" +#include "version.h" +#include "systems.h" +#include "samplefix.h" + +FILE* F_SCRIPT=NULL; + +FILE* F_SAMP=NULL; +FILE* F_SONG=NULL; + +FILE* F_HEADER=NULL; + +u16 MSL_NSAMPS; +u16 MSL_NSONGS; + +char str_msl[256]; + +#define TMP_SAMP "sampJ328G54AU3.tmp" +#define TMP_SONG "songDJ34957FAI.tmp" + +void MSL_PrintDefinition( char* filename, u16 id, char* prefix ); + +#define SAMPLE_HEADER_SIZE (12 + (( target_system == SYSTEM_NDS ) ? 4:0)) + +void MSL_Erase( void ) +{ + MSL_NSAMPS = 0; + MSL_NSONGS = 0; + file_delete( TMP_SAMP ); + file_delete( TMP_SONG ); +} + +u16 MSL_AddSample( Sample* samp ) +{ + u32 sample_length; + u32 x; + file_open_write_end( TMP_SAMP ); + + sample_length = samp->sample_length; + + write32( ((samp->format & SAMPF_16BIT) ? sample_length*2 : sample_length ) + SAMPLE_HEADER_SIZE +4); // +4 for sample padding + write8 ( (target_system == SYSTEM_GBA) ? MAS_TYPE_SAMPLE_GBA : MAS_TYPE_SAMPLE_NDS ); + write8( MAS_VERSION ); + write8( samp->filename[0] == '#' ? 1 : 0); + write8( BYTESMASHER ); + + Write_SampleData(samp); + + file_close_write(); + MSL_NSAMPS++; + return MSL_NSAMPS-1; +} + +u16 MSL_AddSampleC( Sample* samp ) +{ + u32 st; + u32 samp_len; + u32 samp_llen; + u8 sformat; + + u32 h_filesize; + int samp_id; + bool samp_match; + + int fsize=file_size( TMP_SAMP ); + if( fsize == 0 ) + { + return MSL_AddSample( samp ); + } + F_SAMP = fopen( TMP_SAMP, "rb" ); + fseek( F_SAMP, 0, SEEK_SET ); + samp_id = 0; + while( ftell( F_SAMP ) < fsize ) + { + h_filesize = read32f( F_SAMP ); + read32f( F_SAMP ); + samp_len = read32f( F_SAMP ); + samp_llen = read32f( F_SAMP ); + sformat = read8f( F_SAMP ); /////// BUG! GBA DOESNLT WRITE FORMAT!? + skip8f( 3, F_SAMP ); + if( target_system == SYSTEM_NDS ) + { + skip8f(4,F_SAMP); + } + + samp_match=true; + if( samp->sample_length == samp_len && ( samp->loop_type ? samp->loop_end-samp->loop_start : 0xFFFFFFFF ) == samp_llen && sformat == sample_dsformat( samp ) ) + { + // verify sample data + if( samp->format & SAMPF_16BIT ) + { + for( st=0; stdata)[st] ) + { + samp_match = false; + break; + } + } + } + else + { + for( st=0; stdata)[st] ) + { + samp_match = false; + break; + } + } + } + if( samp_match ) + { + fclose( F_SAMP ); + return samp_id; + } + else + { + skip8f( (h_filesize-SAMPLE_HEADER_SIZE ) - (st+1) , F_SAMP ); // +4 to skip padding + } + } + else + { + skip8f( h_filesize- SAMPLE_HEADER_SIZE , F_SAMP ); // +4 to skip padding + } + samp_id++; + } + fclose( F_SAMP ); + return MSL_AddSample( samp ); +} + +u16 MSL_AddModule( MAS_Module* mod ) +{ + int x; + int samp_id; + // ADD SAMPLES + for( x = 0; x < mod->samp_count; x++ ) + { + samp_id = MSL_AddSampleC( &mod->samples[x] ); + if( mod->samples[x].filename[0] == '#' ) + MSL_PrintDefinition( mod->samples[x].filename+1, (u16)samp_id, "SFX_" ); + mod->samples[x].msl_index = samp_id; + } + + file_open_write_end( TMP_SONG ); + Write_MAS( mod, false, true ); + file_close_write(); + MSL_NSONGS++; + return MSL_NSONGS-1; +} + +void MSL_Export( char* filename ) +{ + u32 x; + u32 y; + u32 file_size; + + u32* parap_samp; + u32* parap_song; + + file_open_write( filename ); + write16( MSL_NSAMPS ); + write16( MSL_NSONGS ); + write8( '*' ); + write8( 'm' ); + write8( 'a' ); + write8( 'x' ); + write8( 'm' ); + write8( 'o' ); + write8( 'd' ); + write8( '*' ); + + parap_samp = (u32*)malloc( MSL_NSAMPS * sizeof( u32 ) ); + parap_song = (u32*)malloc( MSL_NSONGS * sizeof( u32 ) ); + + // reserve space for parapointers + for( x = 0; x < MSL_NSAMPS; x++ ) + write32( 0xAAAAAAAA ); + for( x = 0; x < MSL_NSONGS; x++ ) + write32( 0xAAAAAAAA ); + // copy samples + file_open_read( TMP_SAMP ); + for( x = 0; x < MSL_NSAMPS; x++ ) + { + align32(); + parap_samp[x] = file_tell_write(); + file_size = read32(); + write32( file_size ); + for( y = 0; y < file_size+4; y++ ) + write8( read8() ); + } + file_close_read(); + + file_open_read( TMP_SONG ); + for( x = 0; x < MSL_NSONGS; x++ ) + { + align32(); + parap_song[x] = file_tell_write(); + file_size = read32(); + write32( file_size ); + for( y = 0; y < file_size+4; y++ ) + write8( read8() ); + } + file_close_read(); + + file_seek_write( 0x0C, SEEK_SET ); + for( x = 0; x < MSL_NSAMPS; x++ ) + write32( parap_samp[x] ); + for( x= 0; x < MSL_NSONGS; x++ ) + write32( parap_song[x] ); + + file_close_write(); + + if( parap_samp ) + free( parap_samp ); + if( parap_song ) + free( parap_song ); +} + +void MSL_PrintDefinition( char* filename, u16 id, char* prefix ) +{ + char newtitle[64]; + int x,s=0; + if( filename[0] == 0 ) // empty string + return; + for( x = 0; x < (int)strlen( filename ); x++ ) + { + if( filename[x] == '\\' || filename[x] == '/' ) s = x+1; + } + for( x = s; x < (int)strlen( filename ); x++ ) + { + if( filename[x] != '.' ) + { + newtitle[x-s] = toupper(filename[x]); + if( newtitle[x-s] >= ' ' && newtitle[x-s] <= '/' ) + newtitle[x-s] = '_'; + if( newtitle[x-s] >= ':' && newtitle[x-s] <= '@' ) + newtitle[x-s] = '_'; + if( newtitle[x-s] >= '[' && newtitle[x-s] <= '`' ) + newtitle[x-s] = '_'; + if( newtitle[x-s] >= '{' ) + newtitle[x-s] = '_'; + } + else + { + break; + } + } + newtitle[x-s] = 0; + if( F_HEADER ) + { + fprintf( F_HEADER, "#define %s%s %i\r\n", prefix, newtitle, id ); + } +} + +void MSL_LoadFile( char* filename, bool verbose ) +{ + Sample wav; + MAS_Module mod; + int f_ext; + if( file_open_read( filename ) ) + { + printf( "Cannot open %s for reading! Skipping.\n", filename ); + return; + } + f_ext = get_ext( filename ); + switch( f_ext ) + { + case INPUT_TYPE_MOD: + Load_MOD( &mod, verbose ); + MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" ); + Delete_Module( &mod ); + break; + case INPUT_TYPE_S3M: + Load_S3M( &mod, verbose ); + MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" ); + Delete_Module( &mod ); + break; + case INPUT_TYPE_XM: + Load_XM( &mod, verbose ); + MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" ); + Delete_Module( &mod ); + break; + case INPUT_TYPE_IT: + Load_IT( &mod, verbose ); + MSL_PrintDefinition( filename, MSL_AddModule( &mod ), "MOD_" ); + Delete_Module( &mod ); + break; + case INPUT_TYPE_WAV: + Load_WAV( &wav, verbose, true ); + wav.filename[0] = '#'; // set SFX flag (for demo) + MSL_PrintDefinition( filename, MSL_AddSample( &wav ), "SFX_" ); + free( wav.data ); + break; + default: + // print error/warning + printf( "Unknown file %s...\n", filename ); + } + file_close_read(); + +} + +int MSL_Create( char* argv[], int argc, char* output, char* header, bool verbose ) +{ +// int str_w=0; +// u8 pmode=0; +// bool comment=false; + + int x; + + MSL_Erase(); + str_msl[0] = 0; + F_HEADER=NULL; + if( header ) + { + F_HEADER = fopen( header, "wb" ); + } + +// if( !F_HEADER ) +// return -1; // needs header file! + + file_open_write( TMP_SAMP ); + file_close_write(); + file_open_write( TMP_SONG ); + file_close_write(); + + for( x = 1; x < argc; x++ ) + { + if( argv[x][0] == '-' ) + { + + } + else + { + MSL_LoadFile( argv[x], verbose ); + } + } + + MSL_Export( output ); + + if( F_HEADER ) + { + fprintf( F_HEADER, "#define MSL_NSONGS %i\r\n", MSL_NSONGS ); + fprintf( F_HEADER, "#define MSL_NSAMPS %i\r\n", MSL_NSAMPS ); + fprintf( F_HEADER, "#define MSL_BANKSIZE %i\r\n", (MSL_NSAMPS+MSL_NSONGS) ); + fclose( F_HEADER ); + F_HEADER=NULL; + } + + file_delete( TMP_SAMP ); + file_delete( TMP_SONG ); + return ERR_NONE; +} diff --git a/tools/mmutil/msl.h b/tools/mmutil/msl.h new file mode 100644 index 0000000..d697e4b --- /dev/null +++ b/tools/mmutil/msl.h @@ -0,0 +1,28 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include "defs.h" +#include "files.h" +#include "mas.h" + +#include "arm7_st.inc" +#include "arm9_st.inc" + +const u8 nds_logo[]; + +#define ARM7_SIZE sizeof(arm7_bin) +#define ARM9_SIZE sizeof(arm9_bin) + +const unsigned short crc16tab[] = +{ + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 +}; + +void Write_NDS( void ) +{ + int x; + const char game_title[] = "SOUND TEST "; + + for( x = 0; x < 12; x++ ) + write8( game_title[x] ); + + write32( '####' ); // gamecode + write16( 0 ); // makercode + write8( 0 ); // unit code (Nintendo DS) + write8( 0 ); // encryption seed + write8( 0 ); // device capability + for( x= 0; x < 9; x++ ) + write8( 0 ); // reserved + write8( 0 ); // rom version + write8( 4 ); // autostart + +//----------------------------------------------------------- + write32( 512+32768 ); // arm9 ROM offset + write32( 0x2000000 ); // arm9 entry point + write32( 0x2000000 ); // arm9 ram address + write32( 65536 ); // arm9 binary size (modify later) +//----------------------------------------------------------- + write32( 512 ); // arm7 ROM offset + write32( 0x37f8000 ); // arm7 entry point + write32( 0x37f8000 ); // arm7 ram address + write32( 32768 ); // arm7 binary size +//----------------------------------------------------------- + + write32( 0 ); // fnt address + write32( 0 ); // fnt size + write32( 0 ); // fat address + write32( 0 ); // fat size + + write32( 0 ); // file arm9 overlay address + write32( 0 ); // file arm9 overlay size + write32( 0 ); // file arm7 overlay address + write32( 0 ); // file arm7 overlay size + + write32( 0x7f7fff ); // port 40001a4 setting for normal commands + write32( 0x203f1fff ); // port 40001a4 setting for KEY1 commands + + write32( 0 ); // icon (no icon) + + write16( 0 ); // secure area checksum + write16( 0x51e ); // secure area loading timeout + write32( 0 ); // arm9 auto load list RAM address (?) + write32( 0 ); // arm7 auto load list RAM address (?) + write32( 0 ); // secure area disable + write32( 0 ); // secure area disable + + write32( 0x14400 ); // total used ROM size + write32( 0x200 ); // rom header size + + write32( 0 ); + write32( 0 ); + write32( 0 ); + write32( 0 ); + write32( 0 ); + write32( 0 ); + write32( 'MARS' ); + write32( '11V_' ); + write8( '0' ); + write8( 0 );write8( 0 );write8( 0 ); + write32( 'SSAP' ); + write8( '0' );write8( '1' );write8( 0x96 );write8( 0 ); + + write32( 0 ); + write32( 0 ); + write32( 0 ); + + for( x = 0; x < 0x9c; x++ ) + write8( nds_logo[x] ); // NINTENDO LOGO + + write16( 0x9e1a ); // nintendo logo checksum + write16( 0 ); // header checksum (modify later) + write32( 0 ); // debug rom offset + write32( 0 ); // debug rom size + write32( 0 ); // debug ram address + + write32( 0 ); // reserved + + for( x = 0; x < 0x90; x++ ) + write8( 0 ); + + // write binaries + for( x = 0; x < ARM7_SIZE; x++ ) + write8( arm7_bin[x] ); + for( x = 0; x < 32768-ARM7_SIZE; x++ ) // pad to 32k + write8( (u8)x ); + for( x = 0; x < ARM9_SIZE; x++ ) + write8( arm9_bin[x] ); + for( x = 0; x < 65536-ARM9_SIZE; x++ ) // pad to 64k + write8( (u8)x ); +} + +unsigned short calculate_crc( void ) +{ + int i; + unsigned short crc = 0xFFFF; + for ( i=0; i<0x15E; i++) + { + unsigned char data = read8(); + crc = (crc >> 8) ^ crc16tab[(crc ^ data) & 0xFF]; + } + return crc; +} + +void Validate_NDS( char* filename, int output_size ) +{ + int arm9_size; + int header_crc; + arm9_size = 65536 + output_size; + file_open_write_end( filename ); + file_seek_write( 0x2c, SEEK_SET ); + write32( arm9_size ); + file_seek_write( 0x80, SEEK_SET ); + write32( arm9_size+32768 ); // total used rom size + file_close_write(); + + file_open_read( filename ); + header_crc=calculate_crc(); + file_close_read(); + header_crc &= 0xFFFF; + + file_open_write_end( filename ); + file_seek_write( 0x15e, SEEK_SET ); + write16( (u16)header_crc ); + file_close_write(); + /* + // write arm7 rom_offset + file_seek_write( 0x30, SEEK_SET ); + write32( 512 ); + + // write arm9 rom_offset + file_seek_write( 0x20, SEEK_SET ); + write32( 512 + 0x4000 ); + + // write arm9 size + file_seek_write( 0x2C, SEEK_SET ); + write32( 0x10000 + output_size ); + */ +} + +const u8 nds_logo[] = { + 0xC8, 0x60, 0x4F, 0xE2, 0x1, 0x70, 0x8F, 0xE2, 0x17, 0xFF, 0x2F, 0xE1, 0x12, 0x4F, 0x11, 0x48, 0x12, 0x4C, 0x20, 0x60, 0x64, 0x60, 0x7C, 0x62, 0x30, 0x1C, 0x39, 0x1C, 0x10, 0x4A, 0x0, 0xF0, 0x14, 0xF8, +0x30, 0x6A, 0x80, 0x19, 0xB1, 0x6A, 0xF2, 0x6A, 0x0, 0xF0, 0xB, 0xF8, 0x30, 0x6B, 0x80, 0x19, 0xB1, 0x6B, 0xF2, 0x6B, 0x0, 0xF0, 0x8, 0xF8, 0x70, 0x6A, 0x77, 0x6B, 0x7, 0x4C, 0x60, 0x60, 0x38, 0x47, 0x7, +0x4B, 0xD2, 0x18, 0x9A, 0x43, 0x7, 0x4B, 0x92, 0x8, 0xD2, 0x18, 0xC, 0xDF, 0xF7, 0x46, 0x4, 0xF0, 0x1F, 0xE5, 0x0, 0xFE, 0x7F, 0x2, 0xF0, 0xFF, 0x7F, 0x2, 0xF0, 0x1, 0x0, 0x0, 0xFF, 0x1, 0x0, 0x0, 0x0, +0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }; diff --git a/tools/mmutil/nds.h b/tools/mmutil/nds.h new file mode 100644 index 0000000..dd7b63f --- /dev/null +++ b/tools/mmutil/nds.h @@ -0,0 +1,29 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include +#include "defs.h" +#include "mas.h" +#include "s3m.h" +#include "files.h" +#include "simple.h" +#include "errors.h" +#include "samplefix.h" + +#define S3M_NOTE(a) (((a&15)+(a>>4)*12)+12) + +#ifdef SUPER_ASCII +#define vstr_s3m_samp " %5i ³ %-4s³ %3i%% ³%5ihz³ %-28s³\n" +#define vstr_s3m_sampe " ----- ³ --- ³ ---- ³ ----- ³ %-28s³\n" +#define vstr_s3m_div "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n" +#define vstr_s3m_sampt_top "ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\n" +#define vstr_s3m_sampt_mid "³INDEX³LENGTH ³LOOP ³VOLUME³ MID-C ³ NAME ³\n" +#define vstr_s3m_sampt_slice "ÃÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n" +#define vstr_s3m_sampt_index "³ %2i ³" +#define vstr_s3m_sampt_bottom "ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\n" +#define vstr_s3m_pattern " \x0e %2i%s" +#else +#define vstr_s3m_samp "%-5i %-3s %3i%% %5ihz %-28s \n" +#define vstr_s3m_sampe "----- --- ---- ------- %-28s\n" +#define vstr_s3m_div "--------------------------------------------\n" +#define vstr_s3m_sampt_top vstr_s3m_div +#define vstr_s3m_sampt_mid " INDEX LENGTH LOOP VOLUME MID-C NAME\n" +//#define vstr_s3m_sampt_slice "" +#define vstr_s3m_sampt_index " %-2i " +#define vstr_s3m_sampt_bottom vstr_s3m_div +#define vstr_s3m_pattern " * %2i%s" +#endif + +int Load_S3M_SampleData( Sample* samp, u8 ffi ) +{ + u32 x; + int a; + if( samp->sample_length == 0 ) + return ERR_NONE; + if( samp->format & SAMPF_16BIT ) + samp->data = (u16*)malloc( samp->sample_length*2 ); + else + samp->data = (u8*)malloc( samp->sample_length ); + if( ffi == 1 ) + { + // signed samples [VERY OLD] + for( x = 0; x < samp->sample_length; x++ ) + { + if( samp->format & SAMPF_16BIT ) + { + a = read16(); + a += 32768; + ((u16*)samp->data)[x] = (u16)a; + } + else + { + a = read8(); + a += 128; + ((u8*)samp->data)[x] = (u8)a; + } + } + } + else if( ffi == 2 ) + { + // unsigned samples + for( x = 0; x < samp->sample_length; x++ ) + { + if( samp->format & SAMPF_16BIT ) + { + a = read16(); + ((u16*)samp->data)[x] = (u16)a; + } + else + { + a = read8(); + ((u8*)samp->data)[x] = (u8)a; + } + } + } + else + { + return ERR_UNKNOWNSAMPLE; + } + FixSample( samp ); + return ERR_NONE; +} + +int Load_S3M_Sample( Sample* samp, bool verbose ) +{ + u8 flags; + u32 x; + memset( samp, 0, sizeof( Sample ) ); + samp->msl_index = 0xFFFF; + if( read8() == 1 ) // type, 1 = sample + { + for( x = 0; x < 12; x++ ) + samp->filename[x] = read8(); + samp->datapointer = (read8()*65536+read16())*16;//read24(); + samp->sample_length = read32(); + samp->loop_start = read32(); + samp->loop_end = read32(); + samp->default_volume = read8(); + samp->global_volume = 64; + read8(); // reserved + if( read8() != 0 ) // packing, 0 = unpacked + return ERR_UNKNOWNSAMPLE; + flags = read8(); + samp->loop_type = flags&1 ? 1 : 0; + if( flags & 2 ) + return ERR_UNKNOWNSAMPLE; + //samp->bit16 = flags&4 ? true : false; + samp->format = flags&4 ? SAMP_FORMAT_U16 : SAMP_FORMAT_U8; + samp->frequency = read32(); + read32(); // reserved + skip8( 8 ); // internal variables + for( x =0 ; x < 28; x++ ) + samp->name[x] = read8(); + if( read32() != 'SRCS' ) + return ERR_UNKNOWNSAMPLE; + + if( verbose ) + { + // printf( "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n" ); + // printf( "Loading Samples...\n" ); + // printf( "ÚÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\n" ); + // printf( "³LENGTH³LOOP³VOLUME³ MID-C ³ NAME ³\n"); + // printf( "ÅÄÄÄÄÄÄÅÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n" ); + printf( vstr_s3m_samp, samp->sample_length, samp->loop_type ? "Yes" : "No", (samp->default_volume*100) / 64, samp->frequency, samp->name ); + /*printf( " Name......%s\n", samp->name ); + printf( " Length....%i\n", samp->sample_length ); + if( samp->loop_type ) + printf( " Loop......%i->%i\n", samp->loop_start, samp->loop_end ); + else + printf( " Loop......Disabled\n" ); + printf( " Volume....%i\n", samp->default_volume ); + printf( " Middle C..%ihz\n", samp->frequency ); + if( samp->bit16 ) + printf( " 16 bit....yes\n" );*/ + } + } + else + { + if( verbose ) + { + printf( vstr_s3m_sampe, samp->name ); + } + } + return ERR_NONE; +} + +int Load_S3M_Pattern( Pattern* patt ) +{ + int clength; + int row, col; + u8 what; + int z; + + clength = read16(); + // unpack s3m data + + memset( patt, 0, sizeof( Pattern ) ); + + patt->clength = clength; + patt->nrows = 64; + + for( row = 0; row < 64*MAX_CHANNELS; row++ ) + { + patt->data[row].note = 250; + patt->data[row].vol = 255; + } + + for( row = 0; row < 64; row++ ) + { + while( (what = read8()) != 0 ) // BYTE:what / 0=end of row + { + col = what & 31; // &31=channel + + z = row*MAX_CHANNELS+col; + + if( what & 32 ) // &32=follows; BYTE:note, BYTE:instrument + { + patt->data[z].note = read8(); + if( patt->data[z].note == 255 ) + patt->data[z].note = 250; + else if( patt->data[z].note == 254 ) + patt->data[z].note = 254; + else + patt->data[z].note = S3M_NOTE( patt->data[z].note ); + patt->data[z].inst = read8(); + } + + if( what & 64 ) // &64=follows; BYTE:volume + { + patt->data[z].vol = read8(); + } + + if( what & 128 ) // &128=follows; BYTE:command, BYTE:info + { + patt->data[z].fx = read8(); + patt->data[z].param = read8(); + if( patt->data[z].fx == 3 ) // convert pattern break to hexadecimal + { + patt->data[z].param = (patt->data[z].param&0xF) + (patt->data[z].param/16)*10; + } + if( patt->data[z].fx == 'X'-64 ) + { + patt->data[z].param *= 2; // multiply volume scale by 2 + } + if( patt->data[z].fx == 'V'-64 ) + { + patt->data[z].param *= 2; // multiply volume scale by 2 + } + } + if( patt->data[z].fx == 255 ) + { + patt->data[z].fx = 0; + patt->data[z].param = 0; + } + } + } + return ERR_NONE; +} + +int Load_S3M( MAS_Module* mod, bool verbose ) +{ + u16 s3m_flags; + u16 cwt; + u16 ffi; + u8 dp; + + bool stereo; + + u8 a; + bool chan_enabled[32]; + + int x,y; + + u16* parap_inst; + u16* parap_patt; + + + + memset( mod, 0, sizeof( MAS_Module ) ); + for( x = 0; x < 28; x++ ) + mod->title[x] = read8(); // read song name + + if( read8() != 0x1A ); +// return ERR_INVALID_MODULE; + if( read8() != 16 ) + return ERR_INVALID_MODULE; + if( verbose ) + { + printf( vstr_s3m_div ); + } + if( verbose ) + printf( "Loading S3M, \"%s\"\n", mod->title ); + + skip8( 2 ); // reserved space + mod->order_count = (u8)read16(); + mod->inst_count = (u8)read16(); + mod->samp_count = mod->inst_count; + mod->patt_count = (u8)read16(); + + for( x = 0; x < 32; x++ ) + mod->channel_volume[x] = 64; + + mod->freq_mode = 0; // amiga frequencies + mod->old_effects=true; // old effects (maybe not?) + mod->link_gxx=false; // dont link gxx memory + mod->restart_pos = 0; // restart from beginning + mod->old_mode=true; + + s3m_flags = read16(); + cwt = read16(); + ffi = read16(); + if( read32() != 'MRCS' ) // "SCRM" mark + return ERR_INVALID_MODULE; + mod->global_volume = read8()*2; + mod->initial_speed = read8(); + mod->initial_tempo = read8(); + stereo = read8() >> 7; // master volume + read8(); // ultra click removal + dp = read8(); // default pan positions (when 252) + skip8( 8+2 ); // reserved space + special pointer + for( x = 0; x < 32; x++ ) + { + u8 chn = read8(); + chan_enabled[x] = chn >> 7; + if( stereo ) + { + if( (chn&127) < 8 ) // left channel + mod->channel_panning[x] = clamp_u8( 128 - (PANNING_SEP/2) ); + else // right channel + mod->channel_panning[x] = clamp_u8( 128 + (PANNING_SEP/2) ); + } + else + { + mod->channel_panning[x] = 128; + } + } + for( x = 0; x < mod->order_count; x++ ) + { + mod->orders[x] = read8(); + } + parap_inst = (u16*)malloc( mod->inst_count * sizeof( u16 ) ); + parap_patt = (u16*)malloc( mod->patt_count * sizeof( u16 ) ); + + for( x = 0; x < mod->inst_count; x++ ) + parap_inst[x] = read16(); + for( x = 0; x < mod->patt_count; x++ ) + parap_patt[x] = read16(); + + if( dp == 252 ) + { + for( x = 0; x < 32; x++ ) + { + a = read8(); + if( a & 32 ) + { + mod->channel_panning[x] = (a&15)*16 > 255 ? 255 : (a&15)*16; + } + else + {/* + if( stereo ) + { + switch( x & 3 ) { + case 0: + case 3: + mod->channel_panning[x] = clamp_u8( 128 - (PANNING_SEP/2) ); + break; + case 1: + case 2: + mod->channel_panning[x] = clamp_u8( 128 + (PANNING_SEP/2) ); + } + } + else + { + mod->channel_panning[x] = 128; + }*/ + } + } + } + else + { + for( x = 0; x < 32; x++ ) + { + if( stereo ) + mod->channel_panning[x] = x & 1 ? clamp_u8( 128 - (PANNING_SEP/2) ) : clamp_u8( 128 + (PANNING_SEP/2) ); + else + mod->channel_panning[x] = 128; + } + } + + mod->instruments = (Instrument*)malloc( mod->inst_count * sizeof( Instrument ) ); + mod->samples = (Sample*)malloc( mod->samp_count * sizeof( Sample ) ); + mod->patterns = (Pattern*)malloc( mod->patt_count * sizeof( Pattern ) ); + + if( verbose ) + { + printf( vstr_s3m_div ); + printf( "Loading Samples...\n" ); + printf( vstr_s3m_sampt_top ); + printf( vstr_s3m_sampt_mid ); +#ifdef vstr_s3m_sampt_slice + printf( vstr_s3m_sampt_slice ); +#endif + } + // load instruments + for( x = 0; x < mod->inst_count; x++ ) + { + if( verbose ) + { + printf( vstr_s3m_sampt_index, x+1 ); + //printf( "Sample %i\n", x+1 ); + } + // create instrument for sample + memset( &mod->instruments[x], 0, sizeof( Instrument ) ); + mod->instruments[x].global_volume = 128; + // make notemap + for( y = 0; y < 120; y++ ) + mod->instruments[x].notemap[y] = y | ((x+1) << 8); + + // load sample + file_seek_read( parap_inst[x]*16, SEEK_SET ); + if( Load_S3M_Sample( &mod->samples[x], verbose ) ) + { + printf( "Error loading sample!\n" ); + return ERR_UNKNOWNSAMPLE; + } + } + + // load patterns + if( verbose ) + { + printf( vstr_s3m_sampt_bottom ); + printf( "Loading Patterns...\n" ); + printf( vstr_s3m_div ); + } + for( x = 0; x < mod->patt_count; x++ ) + { + if( verbose ) + { + printf( vstr_s3m_pattern, x+1, ((x+1)%15)?"":"\n" ); + } + //printf( "%i...", x+1 ); + file_seek_read( parap_patt[x]*16, SEEK_SET ); + Load_S3M_Pattern( &mod->patterns[x] ); + } + + if( verbose ) + { + printf( "\n" ); + printf( vstr_s3m_div ); + printf( "Loading Sample Data...\n" ); + } + for( x = 0; x < mod->samp_count; x++ ) + { + file_seek_read( mod->samples[x].datapointer, SEEK_SET ); + Load_S3M_SampleData( &mod->samples[x], (u8)ffi ); + } + if( verbose ) + { + printf( vstr_s3m_div ); + } + return ERR_NONE; +} diff --git a/tools/mmutil/s3m.h b/tools/mmutil/s3m.h new file mode 100644 index 0000000..b89c8f4 --- /dev/null +++ b/tools/mmutil/s3m.h @@ -0,0 +1,28 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include +#include +#include "defs.h" +#include "mas.h" +#include "errors.h" +#include "systems.h" +#include "adpcm.h" + +extern int ignore_sflags; + +void Sample_PadStart( Sample* samp, u32 count ) +{ + // Pad beginning of sample with zero + u8* newdata8; + u16* newdata16; + u32 x; + if( count == 0 ) + return; // nothing to do + if( samp->format & SAMPF_16BIT ) + { + newdata16 = (u16*)malloc( (samp->sample_length+count)*2 ); + for( x = 0; x < count; x++ ) + newdata16[x]=32768; + for( x = 0; x < samp->sample_length; x++ ) + newdata16[count+x]=((u16*)samp->data)[x]; + free( samp->data ); + samp->data = (void*)newdata16; + } + else + { + newdata8 = (u8*)malloc( (samp->sample_length+count) ); + for( x = 0; x < count; x++ ) + newdata8[x]=128; + for( x = 0; x < samp->sample_length; x++ ) + newdata8[count+x] = ((u8*)samp->data)[x]; + free( samp->data ); + samp->data = (void*)newdata8; + } + samp->loop_start += count; + samp->loop_end += count; + samp->sample_length += count; +} + +void Sample_PadEnd( Sample* samp, u32 count ) +{ + // Pad end of sample with zero + u8* newdata8; + u16* newdata16; + u32 x; + if( count == 0 ) + return; // nothing to do + if( samp->format & SAMPF_16BIT ) + { + newdata16 = malloc( (samp->sample_length+count)*2 ); + for( x = 0; x < samp->sample_length; x++ ) + newdata16[x]= ((u16*)samp->data)[x]; + for( x = 0; x < count; x++ ) + newdata16[samp->sample_length+x]=32768; + free( samp->data ); + samp->data = (void*)newdata16; + } + else + { + newdata8 = malloc( (samp->sample_length+count) ); + for( x = 0; x < samp->sample_length; x++ ) + newdata8[x]= ((u8*)samp->data)[x]; + for( x = 0; x < count; x++ ) + newdata8[samp->sample_length+x]=128; + free( samp->data ); + samp->data = (void*)newdata8; + } + samp->loop_end += count; + samp->sample_length += count; +} + +void Unroll_Sample_Loop( Sample* samp, u32 count ) +{ + // unrolls sample loop (count) times + // loop end MUST equal sample length + u8* newdata8; + u16* newdata16; + u32 newlen; + u32 looplen; + u32 x; + looplen = samp->loop_end-samp->loop_start; + newlen = samp->sample_length + looplen*count; + if( samp->format & SAMPF_16BIT ) + { + newdata16 = (u16*)malloc( newlen *2 ); + for( x = 0; x < samp->sample_length; x++ ) + newdata16[x] = ((u16*)samp->data)[x]; + for( x = 0; x < looplen*count; x++ ) + newdata16[samp->sample_length+x] = ((u16*)samp->data)[samp->loop_start+ (x%looplen)]; + free( samp->data ); + samp->data = (void*)newdata16; + } + else + { + newdata8 = (u8*)malloc( newlen ); + for( x = 0; x < samp->sample_length; x++ ) + newdata8[x] = ((u8*)samp->data)[x]; + for( x = 0; x < looplen*count; x++ ) + newdata8[samp->sample_length+x] = ((u8*)samp->data)[samp->loop_start+ (x%looplen)]; + free( samp->data ); + samp->data = (void*)newdata8; + } + samp->loop_end += looplen*count; + samp->sample_length += looplen*count; +} + +void Unroll_BIDI_Sample( Sample* samp ) +{ + // sample length MUST equal sample loop end + // sample MUST have loop type 2 (BIDI) + u8* newdata8; + u16* newdata16; + u32 newlen; + u32 looplen; + u32 x; + + looplen = samp->loop_end-samp->loop_start; + newlen = (samp->sample_length + looplen); + + if( samp->format & SAMPF_16BIT ) + { + newdata16 = malloc( newlen *2 ); + for( x = 0; x < samp->sample_length; x++ ) + newdata16[x] = ((u16*)samp->data)[x]; + for( x = 0; x < looplen; x++ ) + newdata16[x+samp->sample_length] = ((u16*)samp->data)[samp->loop_end-1-x]; + free( samp->data ); + samp->data = (void*)newdata16; + } + else + { + newdata8 = malloc( newlen ); + for( x = 0; x < samp->sample_length; x++ ) + newdata8[x] = ((u8*)samp->data)[x]; + for( x = 0; x < looplen; x++ ) + newdata8[x+samp->sample_length] = ((u8*)samp->data)[samp->loop_end-1-x]; + free( samp->data ); + samp->data = (void*)newdata8; + } + samp->loop_type = 1; + samp->sample_length += looplen; + samp->loop_end += looplen; +} + +/* NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE + The following resample routine was stolen from CHIBITRACKER (http://chibitracker.berlios.de), thanks reduz! + NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE */ + +void Resample( Sample* samp, u32 newsize ) +{ + // output pointers + u8 *dst8 =0; + u16 *dst16=0; + u8 *src8 = (u8*)samp->data; + u16 *src16 = (u16*)samp->data; + + int oldlength = samp->sample_length; + int lpoint = samp->loop_start; + int i; + + bool bit16 = samp->format & SAMPF_16BIT; + double sign_diff; + + // allocate memory + if( bit16 ) + { + dst16 = (u16*)malloc(newsize*2); + sign_diff = 32768.0; + } + else + { + dst8 = (u8*)malloc(newsize); + sign_diff = 128.0; + } + + double tscale = (double)oldlength / (double)newsize; + double posf; + + for( i = 0; i < newsize; i++ ) + { + posf = (double)i * tscale; + int posi = (int)floor(posf); + + double mu = posf - (double)posi; + double s0, s1, s2, s3; + double mu2, a0, a1, a2, a3, res; + + // get previous, current, next, and after next samples + if( bit16 ) + { + s0 = (posi-1) < 0 ? 0 : ((double)(src16[posi-1])); + s1 = ((double)(src16[posi ])); + s2 = (posi+1) >= oldlength ? + (samp->loop_type ? + ((double)(src16[lpoint + (posi + 1 - oldlength)])) : 0) : + ((double)(src16[posi+1])); + s3 = (posi+1) >= oldlength ? + (samp->loop_type ? + ((double)(src16[lpoint + (posi + 2 - oldlength)])) : 0) : + ((double)(src16[posi+2])); + } + else + { + s0 = (posi-1) < 0 ? 0 : ((double)(src8[posi-1])); + s1 = ((double)(src8[posi ])); + s2 = (posi+1) >= oldlength ? + (samp->loop_type ? + ((double)(src8[lpoint + (posi + 1 - oldlength)])) : 0) : + ((double)(src8[posi+1])); + s3 = (posi+1) >= oldlength ? + (samp->loop_type ? + ((double)(src8[lpoint + (posi + 2 - oldlength)])) : 0) : + ((double)(src8[posi+2])); + } + + // sign data + s0 -= sign_diff; + s1 -= sign_diff; + s2 -= sign_diff; + s3 -= sign_diff; + + mu2 = mu * mu; + a0 = s3 - s2 - s0 + s1; + a1 = s0 - s1 - a0; + a2 = s2 - s0; + a3 = s1; + + res = a0*mu*mu2 + a1*mu2 + a2*mu + a3; + int resi = ((int)floor(res+0.5)); + + if( bit16 ) + { + if( resi < -32768 ) resi = -32768; + if( resi > 32767 ) resi = 32767; + dst16[i] = resi + 32768; + } + else + { + if( resi < -128 ) resi = -128; + if( resi > 127 ) resi = 127; + dst8[i] = resi + 128; + } + + } + + free( samp->data ); + if( bit16 ) + samp->data = (void*)dst16; + else + samp->data = (void*)dst8; + + samp->sample_length = newsize; + samp->loop_end = newsize; + samp->loop_start = (int)(((double)samp->loop_start * (double)newsize+((double)oldlength/2))/(double)oldlength); + samp->frequency = (int)(((double)samp->frequency * (double)newsize+((double)oldlength/2))/(double)oldlength); +} + +void Sample_8bit( Sample* samp ) +{ + if( samp->format & SAMPF_16BIT ) + { + u8* newdata; + u32 t; + newdata = (u8*)malloc( samp->sample_length ); + for( t = 0; t < samp->sample_length; t++ ) + newdata[t] = ((u16*)samp->data)[t] / 256; + free( samp->data ); + samp->data = newdata; +// samp->bit16=false; + samp->format &= ~SAMPF_16BIT; + } +} + +void Sample_Sign( Sample* samp ) +{ + // sample must be unsigned + u32 x; + if( samp->format & SAMPF_16BIT ) + { + for( x =0 ; x < samp->sample_length; x++ ) + { + int a = (( (int) ((u16*)samp->data)[x] ) - 32768); + if(a < -32767) a = -32767; // clamp LOW to -32767 (leave space for interpolation error) +// if(a > 32765) a = 32765; // clamp HIGH to 32766 + ((u16*)samp->data)[x] = (u16)a ; + } + } + else + { + for( x =0 ; x < samp->sample_length; x++ ) + { + int a = (( (int) ((u8*)samp->data)[x] ) - 128); + if( a == -128 ) a = -127; + ((u8*)samp->data)[x] = (u8) a; + } + + } + samp->format |= SAMPF_SIGNED; +} + +void FixSample_GBA( Sample* samp ) +{ + // convert to 8-bit if neccesary + Sample_8bit( samp ); + + // delete data after loop_end if loop exists + if( samp->loop_type != 0 ) + samp->sample_length = samp->loop_end; + + // unroll BIDI loop + if( samp->loop_type == 2 ) + Unroll_BIDI_Sample( samp ); + + if( samp->loop_type ) + { + if( samp->loop_end-samp->loop_start < GBA_MIN_LOOP_SIZE ) + { + Unroll_Sample_Loop( samp, (GBA_MIN_LOOP_SIZE / (samp->loop_end-samp->loop_start))+1 ); + } + } +} + +int strcmpshit( char* str1, char* str2 ) +{ + int x=0; + int f=0; + while( str1[x] != 0 ) + { + if( str1[x] == str2[f] )f++; + else f=0; + if( str2[f] == 0 ) return 1; + x++; + } + return 0; +} + +void FixSample_NDS( Sample* samp ) +{ + if( samp->sample_length == 0 ) + { + // sample has no data + samp->loop_end=samp->loop_start=0; + return; + } + // delete data after loop_end if loop exists + if( samp->loop_type != 0 ) + samp->sample_length = samp->loop_end; + + // unroll BIDI loop + if( samp->loop_type == 2 ) + Unroll_BIDI_Sample( samp ); + + // %o option + if( samp->loop_type ) + { + if( !ignore_sflags ) + { + if( ((strcmpshit( samp->name, "%o" )) > 0) ) + { + Unroll_Sample_Loop( samp, 1 ); + samp->loop_start += (samp->loop_end-samp->loop_start) / 2; + } + } + } + + if( !ignore_sflags ) + { + if( ((strcmpshit( samp->name, "%c" )) > 0) ) + { + samp->format |= SAMPF_COMP; + } + } + + // Resize loop + if( samp->loop_type ) + { + int looplen = samp->loop_end-samp->loop_start; + if( !(samp->format & SAMPF_COMP) ) + { + if( samp->format & SAMPF_16BIT ) + { + if( looplen & 1 ) + { + int addition = (samp->loop_end - samp->loop_start); + if( addition > MAX_UNROLL_THRESHOLD ) + Resample( samp, samp->sample_length +1 ); + else + Unroll_Sample_Loop( samp, 1 ); + } + } + else + { + if( looplen & 3 ) + { + int count; + int addition; + count = looplen & 3; + switch( count ) { + case 0: + count=0; break; + case 1: + count=3; break; + case 2: + count=1; break; + case 3: + count=3; break; + } + addition = looplen*count; + if( addition > MAX_UNROLL_THRESHOLD ) + Resample( samp, samp->sample_length + (4-(looplen & 3)) ); + else + Unroll_Sample_Loop( samp, count ); + } + } + } + else + { + int a = looplen; + int count=0, addition; + while( looplen & 7 ) + { + count++; + looplen += a; + } + addition = looplen*count; + if( addition > MAX_UNROLL_THRESHOLD ) + Resample( samp, samp->sample_length + (4-(looplen & 7)) ); + else + Unroll_Sample_Loop( samp, count ); + } + } + + // Align loop_start + if( samp->loop_type ) + { + int padsize; + if( !(samp->format & SAMPF_COMP) ) + { + if( samp->format & SAMPF_16BIT ) { + padsize = ( (2 - (samp->loop_start & 1)) & 1 ); + } else { + padsize = ( (4 - (samp->loop_start & 3)) & 3 ); + } + } + else + { + padsize = ( (8 - (samp->loop_start & 7)) & 7 ); + } + Sample_PadStart( samp, padsize ); + } + + // Pad end, only happens when loop is disabled + if( !(samp->format & SAMPF_COMP) ) + { + if( samp->format & SAMPF_16BIT ) + { + if( samp->sample_length & 1 ) + { + Sample_PadEnd( samp, 2-(samp->sample_length&1) ); + } + } + else + { + if( samp->sample_length & 3 ) + { + Sample_PadEnd( samp, 4-(samp->sample_length&3) ); + } + } + } + else + { + if( samp->sample_length & 7 ) + { + Sample_PadEnd( samp, 8-(samp->sample_length&7) ); + } + } + + Sample_Sign( samp ); // DS hardware takes signed samples + + if( samp->format & SAMPF_COMP ) + { + // compress with IMA-ADPCM hunger owned + adpcm_compress_sample( samp ); + } + else + { + + } +} + +void FixSample( Sample* samp ) +{ + // Clamp loop_start and loop_end (f.e. FR_TOWER.MOD) + samp->loop_start = CLAMP(samp->loop_start, 0, samp->sample_length); + samp->loop_end = CLAMP(samp->loop_end, 0, samp->sample_length); + + if( target_system == SYSTEM_GBA ) + FixSample_GBA( samp ); + else if( target_system == SYSTEM_NDS ) + FixSample_NDS( samp ); +} + diff --git a/tools/mmutil/samplefix.h b/tools/mmutil/samplefix.h new file mode 100644 index 0000000..fb5cd6f --- /dev/null +++ b/tools/mmutil/samplefix.h @@ -0,0 +1,28 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include +#include +#include + +#include "defs.h" +#include "mas.h" +#include "simple.h" +#include "files.h" +#include "samplefix.h" + +// cREDITS TO CODA, LOOK AT THIS AWESOME CODES +u32 readbits(u8* buffer, unsigned int pos, unsigned int size) { + u32 result=0; + u32 i; + + for(i=0;i>3; + bit_pos = (pos+i)&7; + result |= ( (buffer[byte_pos] >> bit_pos) & 1 ) << i; + } + return result; +} + +int get_ext( char* filename ) +{ + int strl = strlen(filename); + int x; + u32 a=0; + if( strl < 4 ) + return INPUT_TYPE_UNK; + for( x = 0; x < 4; x++ ) + { + if( filename[strl-x-1] != '.' ) + { + a |= tolower(filename[strl-x-1]) << (x*8); + } + else + break; + } + //a = tolower( filename[strl-1] ) | (tolower( filename[strl-1] )<<8) | tolower( filename[strl-2]<<16 ) | tolower( filename[strl-3]<<24 ); + + switch( a ) + { + case 'mod': + return INPUT_TYPE_MOD; + case 's3m': + return INPUT_TYPE_S3M; + case 'txt': + return INPUT_TYPE_TXT; + case 'wav': + return INPUT_TYPE_WAV; + case 'msl': + return INPUT_TYPE_MSL; + case 'xm': + return INPUT_TYPE_XM; + case 'it': + return INPUT_TYPE_IT; + case 'h': + return INPUT_TYPE_H; + } + return INPUT_TYPE_UNK; +} + +u32 calc_samplen_ex2( Sample* s ) +{ + if( s->loop_type == 0 ) + { + return s->sample_length; + } + else + { + return s->loop_end; + } +} + +u32 calc_samplooplen( Sample* s ) +{ + u32 a; + if( s->loop_type == 1 ) + { + a = s->loop_end - s->loop_start; + return a; + } + else if( s->loop_type == 2 ) + { + a = (s->loop_end-s->loop_start) *2; + return a; + } + else + { + return 0xFFFFFFFF; + } +} + +u32 calc_samplen( Sample* s ) +{ + if( s->loop_type == 1 ) + { + return s->loop_end; + } + else if( s->loop_type == 2 ) + { + return (s->loop_end-s->loop_start)+s->loop_end; + } + else + { + return s->sample_length; + } +} + +u8 sample_dsformat( Sample* samp ) +{ + if( samp->format & SAMPF_COMP ) + { + return 2; + } + else + { + if( samp->format & SAMPF_SIGNED ) + { + if( samp->format & SAMPF_16BIT ) + return 1; + else + return 0; + } + else + { + if( !(samp->format & SAMPF_16BIT) ) + return 3; + else + return 3; // error + } + } +} + +u8 sample_dsreptype( Sample* samp ) +{ + if( samp->loop_type ) + return 1; + else + return 2; +} + +int clamp_s8( int value ) +{ + if( value < -128 ) value = -128; + if( value > 127 ) value = 127; + return value; +} + +int clamp_u8( int value ) +{ + if( value < 0 ) value = 0; + if( value > 255 ) value = 255; + return value; +} + diff --git a/tools/mmutil/simple.h b/tools/mmutil/simple.h new file mode 100644 index 0000000..512466c --- /dev/null +++ b/tools/mmutil/simple.h @@ -0,0 +1,47 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include +#include "defs.h" +#include "files.h" +#include "mas.h" +#include "wav.h" +#include "simple.h" +#include "samplefix.h" + +int Load_WAV( Sample* samp, bool verbose, bool fix ) +{ + unsigned int file_size; + unsigned int bit_depth = 8; + unsigned int hasformat = 0; + unsigned int hasdata = 0; + unsigned int chunk_code; + unsigned int chunk_size; + unsigned int num_channels = 0; + + if( verbose ) + printf( "Loading WAV file...\n" ); + + // initialize data + memset( samp, 0, sizeof( Sample ) ); + + file_size = file_tell_size(); + + read32(); // "RIFF" + read32(); // filesize-8 + read32(); // "WAVE" + + while( 1 ) + { + // break on end of file + if( file_tell_read() >= file_size ) break; + + // read chunk code and length + chunk_code = read32(); + chunk_size = read32(); + + // parse chunk code + switch( chunk_code ) + { + //--------------------------------------------------------------------- + case ' tmf': // format chunk + //--------------------------------------------------------------------- + + // check compression code (1 = PCM) + if( read16() != 1 ) + { + if( verbose ) + printf( "Unsupported WAV format.\n" ); + return LOADWAV_UNKNOWN_COMP; + } + + // read # of channels + num_channels = read16(); + + // read sampling frequency + samp->frequency = read32(); + + // skip average something, wBlockAlign + read32(); + read16(); + + // get bit depth, catch unsupported values + bit_depth = read16(); + if( bit_depth != 8 && bit_depth != 16 ) + { + if( verbose ) + printf( "Unsupported bit-depth.\n" ); + return LOADWAV_UNSUPPORTED_BD; + } + + if( bit_depth == 16 ) + samp->format |= SAMPF_16BIT; + + // print verbose data + if( verbose ) + { + printf( "Sample Rate...%i\n", samp->frequency ); + printf( "Bit Depth.....%i-bit\n", bit_depth ); + } + + // skip the rest of the chunk (if any) + if( (chunk_size - 0x10) > 0 ) + skip8( (chunk_size - 0x10) ); + + hasformat = 1; + break; + + //--------------------------------------------------------------------- + case 'atad': // data chunk + //--------------------------------------------------------------------- + { + int t, c, dat; + + if( !hasformat ) + { + return LOADWAV_CORRUPT; + } + + if( verbose ) + printf( "Loading Sample Data...\n" ); + + // clip chunk size against end of file (for some borked wavs...) + { + int br = file_size - file_tell_read(); + chunk_size = chunk_size > br ? br : chunk_size; + } + + samp->sample_length = chunk_size / (bit_depth/8) / num_channels; + samp->data = malloc( chunk_size ); + + // read sample data + for( t = 0; t < samp->sample_length; t++ ) + { + dat = 0; + + // for multi-channel samples, get average value + for( c = 0; c < num_channels; c++ ) + { + dat += bit_depth == 8 ? ((int)read8()) - 128 : ((short)read16()); + } + dat /= num_channels; + + if( bit_depth == 8 ) + { + ((u8*)samp->data)[t] = dat + 128; + } + else + { + ((u16*)samp->data)[t] = dat + 32768; + } + } + + hasdata = 1; + + break; + } + //------------------------------------------------------------------------------ + case 'lpms': // sampler chunk + //------------------------------------------------------------------------------ + { + int pos; + skip8( 4 // manufacturer + +4 // product + +4 // sample period + +4 // midi unity note + +4 // midi pitch fraction + +4 // smpte format + +4 // smpte offset + ); + int num_sample_loops = read32(); + + read32(); // sample data + + pos = 36; + + // check for sample looping data + if( num_sample_loops ) + { + read32(); // cue point ID + int loop_type = read32(); + pos += 8; + + if( loop_type < 2 ) + { + // sample | internal + // 0=forward | 1 + // 1=bidi | 2 + samp->loop_type = loop_type + 1; + samp->loop_start = read32(); + samp->loop_end = read32(); + + // clip loop start against sample length + if( samp->loop_end > samp->sample_length ) { + samp->loop_end = samp->sample_length; + } + + // disable tiny loop + // catch invalid loop + if( (samp->loop_start > samp->sample_length) || + (samp->loop_end - samp->loop_start < 16) ) { + + samp->loop_type = 0; + samp->loop_start = 0; + samp->loop_end = 0; + } + + // ignore fractional + // ignore play count + pos += 8; + } + } + + skip8( chunk_size - pos ); + break; + } + default: + skip8( chunk_size ); + } + } + + if( hasformat && hasdata ) + { + if( fix ) FixSample( samp ); + return LOADWAV_OK; + } + else + { + return LOADWAV_CORRUPT; + } +} diff --git a/tools/mmutil/wav.h b/tools/mmutil/wav.h new file mode 100644 index 0000000..e4b726e --- /dev/null +++ b/tools/mmutil/wav.h @@ -0,0 +1,35 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ /> +#include +#include "defs.h" +#include "mas.h" +#include "xm.h" +#include "files.h" +#include "simple.h" +#include "errors.h" +#include "math.h" +#include "samplefix.h" + +#define cho 64 + +#ifdef SUPER_ASCII +#define vstr_xm_samp " %2i ³ %s%s ³ %-22s ³\n" +#define vstr_xm_nosamp " -- ³ -- ³ %-22s ³\n" +#define vstr_xm_div "ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n" +#define vstr_xm_patt " \x0e %2i " +#define vstr_xm_samp_top "ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\n" +#define vstr_xm_samp_header "³INDEX³SAMPLES³ENVELOPE³ NAME ³\n" +#define vstr_xm_samp_prefix "³%3i ³" +#define vstr_xm_samp_slice "ÃÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´\n" +#define vstr_xm_samp_bottom "ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\n" +#else +#define vstr_xm_samp " %2i | %s%s | %-22s |\n" +#define vstr_xm_nosamp " -- | -- | %-22s |\n" +#define vstr_xm_div "--------------------------------------------\n" +#define vstr_xm_patt " Pattern %2i " +#define vstr_xm_samp_top ".-----------------------------------------------.\n" +#define vstr_xm_samp_header "|INDEX|SAMPLES|ENVELOPE| NAME |\n" +#define vstr_xm_samp_prefix "|%3i |" +#define vstr_xm_samp_slice "|-----+-------+--------+------------------------|\n" +#define vstr_xm_samp_bottom "`-----------------------------------------------'\n" +#endif + +int Get_XM_Frequency( s8 relnote, s8 finetune ) +{ + double rn=relnote; + double ft=finetune; + double middle_c; + double freq; + middle_c = 8363.0f; + freq = middle_c * pow( 2.0, (1.0/12.0)*rn + (1.0/(12.0*128.0))*ft ); + return (int)freq; +} + +int Load_XM_Instrument( Instrument* inst, MAS_Module* mas, u8* p_nextsample, bool verbose ) +{ + + int inst_size; + int nsamples; + + int ns; + + int samp_headstart; + int samp_headsize; + int inst_headstart; + + int sample_old; + + int x,y; + u32 t; + + u8 vibtype; + u8 vibsweep; + u8 vibdepth; + u8 vibrate; + + s8 finetune; + s8 relnote; + u8 loopbits; + + u8 volbits; + u8 panbits; + + Sample* samp; + + ns = *p_nextsample; + + memset( inst, 0, sizeof( Instrument ) ); + + inst_headstart = file_tell_read(); + inst_size = read32(); + + for( x = 0; x < 22; x++ ) + inst->name[x] = read8(); // instrument name +// if( verbose ) +// printf( " Name=\"%s\"\n", inst->name ); +// if( read8() != 0 ) +// return ERR_UNKNOWNINST; + read8(); // instrument type, SUPPOSED TO ALWAYS BE 0... + nsamples = read16(); + if( nsamples > 0 ) + { + samp_headsize = read32(); + // read sample map + for( x = 0; x < 96; x++ ) + { + inst->notemap[x+12] = ((read8()+ns+1)*256) | (x+12); + } + for( x=0; x < 12; x++ ) + inst->notemap[x] =( inst->notemap[12]&0xFF00) | x; + for( x=96;x<120;x++) + inst->notemap[x] =( inst->notemap[12]&0xFF00) | x; + for( x = 0; x < 12; x++ ) + { + inst->envelope_volume.node_x[x] = read16(); + inst->envelope_volume.node_y[x] = (u8)read16(); + } + for( x = 0; x < 12; x++ ) + { + inst->envelope_pan.node_x[x] = read16(); + inst->envelope_pan.node_y[x] = (u8)read16(); + } + inst->global_volume = 128; + inst->envelope_volume.node_count = read8(); + inst->envelope_pan.node_count = read8(); + inst->envelope_volume.sus_start = inst->envelope_volume.sus_end = read8(); + inst->envelope_volume.loop_start = read8(); + inst->envelope_volume.loop_end = read8(); + inst->envelope_pan.sus_start = inst->envelope_pan.sus_end = read8(); + inst->envelope_pan.loop_start = read8(); + inst->envelope_pan.loop_end = read8(); + volbits = read8(); + panbits = read8(); + inst->env_flags = 0; + if( volbits & 1 ) + inst->env_flags |= 1|8; + if( panbits & 1 ) + inst->env_flags |= 2; + + if( !(volbits & 2) ) + inst->envelope_volume.sus_start=inst->envelope_volume.sus_end=255; + if( !(panbits & 2) ) + inst->envelope_pan.sus_start=inst->envelope_pan.sus_end=255; + + if( !(volbits & 4) ) + inst->envelope_volume.loop_start=inst->envelope_volume.loop_end=255; + if( !(panbits & 4) ) + inst->envelope_pan.loop_start=inst->envelope_pan.loop_end=255; + + vibtype=read8(); + vibsweep=32768/(read8()+1); + vibdepth=read8(); + vibrate=read8(); + inst->fadeout = read16()/32; // apply scalar!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + file_seek_read( inst_headstart+inst_size, SEEK_SET ); + +/* if( verbose ) + { + if( volbits & 1 ) + printf( " Has Volume Envelope\n" ); + if( panbits & 1 ) + printf( " Has Panning Envelope\n" ); + if( nsamples != 1 ) + printf( " Contains %i samples...\n", nsamples ); + else + printf( " Loading sample\n" ); + } +*/ + // read sample headers + for( x = 0; x < nsamples; x++ ) + { + if( ns+x >= 256 ) + return ERR_TOOMANYSAMPLES; + samp_headstart = file_tell_read(); + samp = &mas->samples[ns+x]; +// if( verbose && nsamples != 1 ) +// printf( " Loading sample %i...\n", x+1 ); + memset( samp, 0, sizeof( Sample ) ); + samp->msl_index = 0xFFFF; + samp->sample_length = read32(); + samp->loop_start = read32(); + samp->loop_end = read32()+samp->loop_start; + samp->default_volume = read8(); + samp->global_volume = 64; + + samp->vibtype = vibtype; + samp->vibdepth = vibdepth; + samp->vibspeed = vibrate; + samp->vibrate = vibsweep; + + finetune = (s8)read8(); + loopbits = read8(); + samp->default_panning = (read8()>>1) | 128; + relnote = (s8)read8(); + read8(); // reserved + + for( y =0; y <22; y ++) + { + samp->name[y] = read8(); + if( y < 12 ) + samp->filename[y] = samp->name[y]; + } + + samp->frequency = Get_XM_Frequency( relnote, finetune ); + +// samp->bit16 = loopbits & 16 ? true : false; + samp->format = loopbits & 16 ? SAMP_FORMAT_U16 : SAMP_FORMAT_U8; + if( samp->format & SAMPF_16BIT ) + { + samp->sample_length /= 2; + samp->loop_start /= 2; + samp->loop_end /= 2; + } + samp->loop_type = loopbits & 3; + file_seek_read( samp_headstart + samp_headsize, SEEK_SET ); +/* + if( verbose ) + { + printf( " Length........%i\n", samp->sample_length ); + if( samp->loop_type == 0 ) + printf( " Loop..........Disabled\n" ); + else if( samp->loop_type == 1 ) + printf( " Loop..........Forward %i->%i\n", samp->loop_start, samp->loop_end ); + else if( samp->loop_type == 2 ) + printf( " Loop..........BIDI %i->%i\n", samp->loop_start, samp->loop_end ); + printf( " Volume........%i\n", samp->default_volume ); + printf( " Panning.......%i\n", samp->default_panning & 127 ); + printf( " Middle C......%ihz\n", samp->frequency ); + printf( " 16 bit........%s\n", (samp->format & SAMPF_16BIT) ? "yes (will be converted)" : "no" ); + }*/ + } + + // read sample + for( x = 0; x < nsamples; x++ ) + { + samp = &mas->samples[ns+x]; + if( samp->sample_length == 0 ) + continue; + + sample_old = 0; + if( samp->format & SAMPF_16BIT ) + { + samp->data = (u16*)malloc( samp->sample_length*2 ); + for( t = 0; t < samp->sample_length; t++ ) + { + sample_old = (s16)((s16)read16() + sample_old); + ((u16*)samp->data)[t] = sample_old + 32768; + } + } + else + { + samp->data = (u8*)malloc( samp->sample_length ); + for( t = 0; t < samp->sample_length; t++ ) + { + sample_old = (s8)((s8)read8() + sample_old); + ((u8*)samp->data)[t] = sample_old + 128; + } + } + FixSample( samp ); + } + *p_nextsample = ns+nsamples; + + + if( verbose ) + { + printf( vstr_xm_samp, nsamples, (volbits&1)?"V":"-", (panbits&1)?"P":"-", inst->name ); + } + } + else + { + file_seek_read( inst_headstart+inst_size, SEEK_SET ); + if( verbose ) + printf( vstr_xm_nosamp, inst->name ); + } + + return ERR_NONE; +} + +void CONV_XM_EFFECT( u8* fx, u8* param ) +{ + int wfx, wpm; + wfx=*fx; + wpm=*param; + + switch( wfx ) + { + case 0: // 0xy arpeggio + if( wpm != 0) + wfx = 'J'-cho; + else + wfx=wpm=0; + break; + + case 1: // 1xx porta up + wfx = 'F'-cho; + if( wpm >= 0xE0 ) + wpm = 0xDF; + break; + + case 2: // 2xx porta down + wfx = 'E'-cho; + if( wpm >= 0xE0 ) + wpm = 0xDF; + break; + + case 3: // 3xx porta to note + wfx = 'G'-cho; + break; + + case 4: // 4xy vibrato + wfx = 'H'-cho; + break; + + case 5: // 5xy volslide+glissando + wfx = 'L'-cho; + break; + + case 6: // 6xy volslide+vibrato + wfx = 'K'-cho; + break; + + case 7: // 7xy tremolo + wfx = 'R'-cho; + break; + + case 8: // 8xx set panning + wfx = 'X'-cho; + break; + + case 9: // 9xx set offset + wfx = 'O'-cho; + break; + + case 0xA: // Axy volume slide + wfx = 'D'-cho; + break; + + case 0xB: // Bxx position jump + wfx = 'B'-cho; + break; + + case 0xC: // Cxx set volume + wfx = 27; // compatibility effect + break; + + case 0xD: // Dxx pattern break + wfx = 'C'-cho; + wpm = (wpm&0xF) + (wpm>>4) * 10; + /*if( wpm >= 0xF0 ) what the fuck is this + { + wpm = 0xE0 | (wpm&0xF); + } + if( wpm & 0xF == 0xF ) + { + wpm = 0x0F | (wpm&0xF0); + }*/ + break; + + case 0xE: // Exy extended +// if( (wpm & 0xF0) != 0xC0 ) +// {int foo = 1;} + switch( wpm >> 4 ) + { + case 1: // fine porta up + wfx = 'F'-cho; + wpm = 0xF0 | (wpm&0xF); + break; + + case 2: // fine porta down + wfx = 'E'-cho; + wpm = 0xF0 | (wpm&0xF); + break; + + case 3: // glissando control + case 5: // set finetune + // UNSUPPORTED :( + wfx=0; + wpm=0; + break; + + case 4: // vibrato control + wfx = 'S'-cho; + wpm = 0x30 | (wpm&0xF); + break; + + case 6: // pattern loop + wfx = 'S'-cho; + wpm = 0xB0 | (wpm&0xF); + break; + + case 7: // tremolo control + wfx = 'S'-cho; + wpm = 0x40 | (wpm&0xF); + break; + + case 8: // set panning + wfx = 'X'-cho; + wpm = (wpm&0xF) * 16; + break; + + case 9: // old retrig + wfx = 'S'-cho; + wpm = 0x20 | (wpm&0xF); + break; + + case 10: // fine volslide up + wfx = 'S'-cho; + wpm = 0x00 | (wpm&0xF); + break; + + case 11: // fine volslide down + wfx = 'S'-cho; + wpm = 0x10 | (wpm&0xF); + break; + + case 12: // note cut + wfx = 'S'-cho; + wpm = 0xC0 | (wpm&0xF); + break; + + case 13: // note delay + wfx = 'S'-cho; + wpm = 0xD0 | (wpm&0xF); + break; + + case 14: // pattern delay + wfx = 'S'-cho; + wpm = 0xE0 | (wpm&0xF); + break; + case 15: // event + wfx = 'S'-cho; + wpm = wpm; + break; + case 0: // set filter + wfx=0; + wpm=0; + + } + break; + + case 0xF: // Fxx set speed + if( wpm >= 32 ) + wfx = 'T'-cho; + else + wfx = 'A'-cho; + break; + + case 16: // Gxx set global volume + wfx = 'V'-cho; + wpm=wpm; + break; + + case 17: // Hxx global volume slide + wfx = 'W'-cho; + break; + + case 18: // Ixx unused + case 19: // Jxx unused + case 22: // Mxx unused + case 23: // Nxx unused + case 24: // Oxx unused + case 26: // Qxx unused + case 28: // Sxx unused + case 30: // Uxx unused + case 31: // Vxx unused + case 32: // Wxx unused + case 34: // Yxx unused + case 35: // Zxx unused + wfx = 0; + wpm = 0; + break; + + case 20: // Kxx key off + wfx = 28; + break; + + case 21: // Lxx set envelope position + wfx = 29; + break; + + case 25: // Pxx panning slide + wfx = 'P'-cho; + break; + + + + case 27: // Rxx retrigger note + wfx = 'Q'-cho; + break; + + case 29: // Txx tremor + wfx = 30; + break; + + case 33: // Xxx extra fine slide + if( (wpm>>4) == 1 ) + { + wfx = 'F'-cho; + wpm = 0xE0 | (wpm & 0xF); + } + else if( (wpm>>4) == 2 ) + { + wfx = 'E'-cho; + wpm = 0xE0 | (wpm & 0xF); + } + else + { + wfx=0; + wpm=0; + } + break; + } + *fx = wfx; + *param = wpm; +} + +int Load_XM_Pattern( Pattern* patt, u32 nchannels, bool verbose ) +{ + u32 headsize; + u32 headstart; + u16 clength; + u16 row, col; + u8 b; + u32 e; + u8 fx,param; + + headstart = file_tell_read(); + headsize = read32(); + + if( read8() != 0 ) + return ERR_UNKNOWNPATTERN; + + memset( patt, 0, sizeof( Pattern ) ); + + patt->nrows = read16(); + clength = read16(); + + if( verbose ) + printf( "- %i rows, %.2f KB\n", patt->nrows, (float)(clength)/1000 ); + + + for( row = 0; row < patt->nrows*MAX_CHANNELS; row++ ) + { + patt->data[row].note = 250; + patt->data[row].vol = 0; + } + + file_seek_read( headstart+headsize, SEEK_SET ); + + if( clength == 0 ) + { + // pattern is empty + return ERR_NONE; + } + + // read pattern data + for( row = 0; row < patt->nrows; row++ ) + { + for( col = 0; col < nchannels; col++ ) + { + e = row*MAX_CHANNELS+col; + b = read8(); + if( b & 128 ) // packed + { + if( b & 1 ) // bit 0 set: Note follows + { + patt->data[e].note = read8(); // (byte) Note (1-96, 1 = C-0) + if( patt->data[e].note == 97 ) + patt->data[e].note = 255; + else + patt->data[e].note += 12-1; + } + if( b & 2 ) // 1 set: Instrument follows + { + patt->data[e].inst = read8(); // (byte) Instrument (1-128) + } + if( b & 4 ) // 2 set: Volume column byte follows + { + patt->data[e].vol = read8(); // (byte) Volume column byte + } + if( b & 8 ) // 3 set: Effect type follows + fx = read8(); // (byte) Effect type + else + fx=0; + if( b & 16 ) // 4 set: Guess what! + param=read8(); // (byte) Effect parameter + else + param=0; + + if( fx != 0 || param != 0 ) + { + CONV_XM_EFFECT( &fx, ¶m ); // convert effect + patt->data[e].fx = fx; + patt->data[e].param = param; + } + } + else // unpacked + { + patt->data[e].note = b; // (byte) Note (1-96, 1 = C-0) + if( patt->data[e].note == 97 ) + patt->data[e].note = 255; + else + patt->data[e].note += 12-1; + patt->data[e].inst = read8(); // (byte) Instrument (1-128) + patt->data[e].vol = read8(); // (byte) Volume column byte (see below) + fx = read8(); // (byte) Effect type + param=read8(); // (byte) Effect parameter + CONV_XM_EFFECT( &fx, ¶m ); // convert effect + patt->data[e].fx = fx; + patt->data[e].param = param; + } + } + } + return ERR_NONE; +} + +int Load_XM( MAS_Module* mod, bool verbose ) +{ + int x; + u16 xm_version; + u32 xm_headsize; + u16 xm_nchannels; + u8 next_sample; + + memset( mod, 0, sizeof( MAS_Module ) ); + + mod->old_effects=true; + mod->xm_mode=true; + mod->global_volume=64; + mod->old_mode=false; + + if( read32() != 'etxE' || read32() != 'dedn' || read32() != 'doM ' || read32() != ':elu' || read8() != ' ' ) + return ERR_INVALID_MODULE; + for( x = 0; x < 20; x++ ) + mod->title[x] = read8(); + if( verbose ) + { + printf( vstr_xm_div ); + printf( "Loading XM, \"%s\"\n", mod->title ); + } + if( read8() != 0x1a ) + return ERR_INVALID_MODULE; + skip8( 20 ); // tracker name + xm_version = read16(); + xm_headsize = read32(); + mod->order_count = (u8)read16(); + mod->restart_pos = (u8)read16(); + xm_nchannels = read16(); + mod->patt_count = (u8)read16(); + mod->inst_count = (u8)read16(); + mod->freq_mode = read16() & 1 ? true : false; // flags + mod->initial_speed = (u8)read16(); + mod->initial_tempo = (u8)read16(); + + if( verbose ) + { + printf( "Version....%i.%i\n", xm_version>>8 & 0xFF, xm_version & 0xFF ); + printf( "Length.....%i\n", mod->order_count ); + printf( "Restart....%i\n", mod->restart_pos ); + printf( "Channels...%i\n", xm_nchannels ); + printf( "#Patterns..%i\n", mod->patt_count ); + printf( "#Instr.....%i\n", mod->inst_count ); + printf( "Freq Mode..%s\n", mod->freq_mode ? "Linear" : "Amiga" ); + printf( "Speed......%i\n", mod->initial_speed ); + printf( "Tempo......%i\n", mod->initial_tempo ); + } + + for( x = 0; x < 32; x++ ) + { + mod->channel_volume[x] = 64; + mod->channel_panning[x] = 128; + } + if( verbose ) + { + printf( vstr_xm_div ); + printf( "Reading sequence...\n" ); + } + for( x = 0; x < 200; x++ ) // read order table + { + if( x < mod->order_count ) + mod->orders[x] = read8(); + else + { + read8(); + mod->orders[x] = 255; + } + } + + for( ; x < 256; x++ ) // skip 200->255 + read8(); + file_seek_read( 60+xm_headsize, SEEK_SET ); // or maybe 60.. + + if( verbose ) + { + printf( vstr_xm_div ); + printf( "Loading patterns...\n" ); + printf( vstr_xm_div ); + } + + mod->patterns = (Pattern*)malloc( mod->patt_count * sizeof( Pattern ) ); + for( x = 0; x < mod->patt_count; x++ ) + { + if( verbose ) + printf( vstr_xm_patt, x+1 ); + Load_XM_Pattern( &mod->patterns[x], xm_nchannels, verbose ); + } + + mod->instruments = (Instrument*)malloc( mod->inst_count * sizeof( Instrument ) ); + mod->samples = (Sample*)malloc( 256 * sizeof( Sample ) ); + next_sample=0; + + + if( verbose ) + { + printf( vstr_xm_div ); + printf( "Loading instruments...\n" ); + printf( vstr_xm_samp_top ); + printf( vstr_xm_samp_header ); + printf( vstr_xm_samp_slice ); + } + + for( x = 0; x < mod->inst_count; x++ ) + { + // if( verbose ) + // printf( "Reading Instrument %i...\n", x+1 ); + if( verbose ) + printf( vstr_xm_samp_prefix, x+1 ); + Load_XM_Instrument( &mod->instruments[x], mod, &next_sample, verbose ); + } + + if( verbose ) + { + printf( vstr_xm_samp_bottom ); + } + + mod->samp_count = next_sample; + return ERR_NONE; +} diff --git a/tools/mmutil/xm.h b/tools/mmutil/xm.h new file mode 100644 index 0000000..539bb61 --- /dev/null +++ b/tools/mmutil/xm.h @@ -0,0 +1,29 @@ +/**************************************************************************** + * __ * + * ____ ___ ____ __ ______ ___ ____ ____/ / * + * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / * + * / / / / / / /_/ />