--- /dev/null
+*.o
+*.d
+*.swp
+cfg.mk
+*.gba
+*.elf
+*.a
+pngdump
+mmutil
+lutgen
+*.ppm
+*.png
+*.sav
+disasm
+data
+*.tar.gz
+*.zip
+pushdata
+link.map
--- /dev/null
+src = $(wildcard src/*.c)
+ssrc = $(wildcard src/*.s) data/lut.s
+obj = $(src:.c=.o) $(ssrc:.s=.o)
+dep = $(src:.c=.d)
+name = gbajam22
+elf = $(name).elf
+bin = $(name).gba
+
+libs = libs/maxmod/libmm.a
+
+TCPREFIX = arm-none-eabi-
+
+CPP = $(TCPREFIX)cpp
+CC = $(TCPREFIX)gcc
+AS = $(TCPREFIX)as
+OBJCOPY = $(TCPREFIX)objcopy
+OBJDUMP = $(TCPREFIX)objdump
+
+opt = -O3 -fomit-frame-pointer -mcpu=arm7tdmi -mtune=arm7tdmi -mthumb -mthumb-interwork
+dbg = -g
+inc = -I. -Ilibs/maxmod
+
+CFLAGS = $(opt) $(dbg) -pedantic -Wall -MMD $(def) $(inc)
+ASFLAGS = -mthumb-interwork
+LDFLAGS = -mthumb -mthumb-interwork $(libs)
+
+-include cfg.mk
+
+.PHONY: all
+all: $(bin) $(bin_mb)
+
+$(bin): $(elf)
+ $(OBJCOPY) -O binary $(elf) $(bin)
+ gbafix -r0 $(bin)
+
+$(elf): $(obj) $(libs)
+ $(CC) -o $(elf) $(obj) -specs=gba.specs -Wl,-Map,link.map $(LDFLAGS)
+
+-include $(dep)
+
+src/data.o: src/data.s $(data)
+
+tools/pngdump/pngdump:
+ $(MAKE) -C tools/pngdump
+
+tools/lutgen: tools/lutgen.c
+ cc -o $@ $< -lm
+
+tools/mmutil/mmutil:
+ $(MAKE) -C tools/mmutil
+
+%.sraw: %.png tools/pngdump/pngdump
+ tools/pngdump/pngdump -o $@ -oc $(subst .sraw,.spal,$@) -os $(subst .sraw,.shade,$@) -s 8 $<
+
+%.raw: %.png tools/pngdump/pngdump
+ tools/pngdump/pngdump -o $@ -n $<
+
+%.pal: %.png tools/pngdump/pngdump
+ tools/pngdump/pngdump -o $@ -c $<
+
+data/lut.s: tools/lutgen
+ tools/lutgen >$@
+
+data/snd.bin: $(audata) tools/mmutil/mmutil
+ tools/mmutil/mmutil -o$@ -hdata/snd.h $(audata)
+
+data/snd.h: data/snd.bin
+
+.PHONY: clean
+clean:
+ rm -f $(obj) $(bin) $(bin_mb) $(elf) $(elf_mb)
+
+.PHONY: cleandep
+cleandep:
+ rm -f $(dep)
+
+.PHONY: cleanlibs
+cleanlibs:
+ $(MAKE) -C libs/maxmod clean
+
+.PHONY: install
+install: $(bin)
+ if2a -n -f -W $<
+
+.PHONY: run
+run: $(bin)
+ mgba -2 $(bin)
+
+.PHONY: debug
+debug: $(elf)
+ mgba -2 -g $(bin) &
+ $(TCPREFIX)gdb $<
+
+.PHONY: disasm
+disasm: $(elf)
+ $(OBJDUMP) -d $< >$@
+
+.PHONY: libs
+libs: $(libs)
+
+libs/maxmod/libmm.a:
+ $(MAKE) -C libs/maxmod
--- /dev/null
+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)
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Nintendo DS & Gameboy Advance Sound System *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * GBA Definitions *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#ifndef MAXMOD_H
+#define MAXMOD_H
+
+#include <mm_types.h>
+
+#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
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * ARM7 Definitions *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#ifdef ARM9
+#error "maxmod7.h is for ARM7!"
+#endif
+
+//----------------------------------------------------------------
+#ifndef MAXMOD_H
+//----------------------------------------------------------------
+
+#define MAXMOD_H
+
+#include <mm_types.h>
+
+//----------------------------------------------------------------
+#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
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Sound Effect System *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#include "mp_defs.inc"
+#include "mp_mas.inc"
+#include "mp_mas_structs.inc"
+#include "mp_format_mas.inc"
+#include "mp_macros.inc"
+
+#ifdef SYS_GBA
+#include "mp_mixer_gba.inc"
+#endif
+
+#ifdef SYS_NDS
+#include "mp_mixer_ds.inc"
+#endif
+
+/***********************************************************************
+ *
+ * Definitions
+ *
+ ***********************************************************************/
+
+.struct 0 // mm_sound_effect
+MM_SFX_SOURCE: .space 4 // word: source
+MM_SFX_RATE: .space 2 // hword: rate
+MM_SFX_HANDLE: .space 2 // byte: handle
+MM_SFX_VOLUME: .space 1 // byte: volume
+MM_SFX_PANNING: .space 1 // byte: panning
+MM_SFX_SIZE: // 8 bytes total
+
+.equ channelCount, 16
+.equ releaseLevel, 200
+
+/***********************************************************************
+ *
+ * Memory
+ *
+ ***********************************************************************/
+
+ .BSS
+ .ALIGN 2
+ .GLOBAL mm_sfx_bitmask, mm_sfx_clearmask
+
+mm_sfx_mastervolume: .space 4
+mm_sfx_channels: .space 2*channelCount
+mm_sfx_bitmask: .space 4
+mm_sfx_clearmask: .space 4
+
+mm_sfx_counter: .space 1
+
+/***********************************************************************
+ *
+ * Program
+ *
+ ***********************************************************************/
+
+ .TEXT
+ .THUMB
+ .ALIGN 2
+
+/***********************************************************************
+ * mmResetEffects
+ ***********************************************************************/
+ .global mmResetEffects
+ .thumb_func
+mmResetEffects:
+
+ mov r0, #0
+ mov r1, #channelCount
+ ldr r2,=mm_sfx_channels
+
+1: strh r0, [r2]
+ add r2, #2
+ sub r1, #1
+ bne 1b
+
+ ldr r2,=mm_sfx_bitmask
+ str r0, [r2]
+
+ bx lr
+
+/***********************************************************************
+ * mmGetFreeEffectChannel()
+ *
+ * Return index to free effect channel
+ ***********************************************************************/
+ .thumb_func
+mmGetFreeEffectChannel:
+
+ ldr r0,=mm_sfx_bitmask // r0 = bitmask
+ ldr r0, [r0] //
+ mov r1, #1 // r1 = channel counter
+
+.channel_search: // shift out bits until we find a cleared one
+ lsr r0, #1 //
+ bcc .found_channel //
+ add r1, #1 // r1 = index value
+ b .channel_search //
+
+.found_channel:
+
+ cmp r1, #channelCount+1 // if r1 == cc+1 then r1 = 0 (no handles avail.)
+ bne .found_valid_channel //
+ mov r1, #0 //
+.found_valid_channel: //
+
+ mov r0, r1 // return value
+ bx lr //
+
+/***********************************************************************
+ * mmEffect( id )
+ *
+ * Play sound effect with default parameters
+ ***********************************************************************/
+ .global mmEffect
+ .thumb_func
+mmEffect:
+ push {lr}
+ // r0 = ssssssss
+ mov r1, #1 // r1 = hhhhrrrr
+ lsl r1, #10 //
+ ldr r2,=0x000080FF // r2 = ----ppvv
+
+ push {r0-r2} // mmEffectEx( sound )
+ mov r0, sp //
+ bl mmEffectEx //
+ add sp, #12 //
+ pop {r3} //
+ bx r3 //
+
+/***********************************************************************
+ * mmEffectEx( sound )
+ *
+ * Play sound effect with specified parameters
+ ***********************************************************************/
+ .global mmEffectEx
+ .thumb_func
+mmEffectEx:
+
+ push {r4-r6, lr}
+
+ mov r4, r0
+ ldrh r5, [r4, #MM_SFX_HANDLE] // test if handle was given
+
+ cmp r5, #255
+ bne 1f
+ mov r5, #0
+ b .got_handle
+
+1: cmp r5, #0 //
+ beq .generate_new_handle //
+
+ lsl r1, r5, #24 // check if channel is in use
+ lsr r1, #23 //
+ sub r1, #2 //
+ ldr r0,=mm_sfx_channels //
+ ldrb r0, [r0, r1] //
+ cmp r0, #0 //
+ beq .got_handle // [valid handle otherwise]
+
+ mov r0, r5
+ bl mmEffectCancel // attempt to stop active channel
+ cmp r0, #0 //
+ bne .got_handle //
+ // failure: generate new handle
+.generate_new_handle:
+
+ bl mmGetFreeEffectChannel // generate handle
+ mov r5, r0 //
+ beq .got_handle //-(no available channels)
+ //
+ ldr r0,=mm_sfx_counter // (counter = ((counter+1) & 255))
+ ldrb r1, [r0] //
+ add r1, #1 //
+ strb r1, [r0] //
+ lsl r1, #8
+ orr r5, r1
+ lsl r5, #16
+ lsr r5, #16
+
+.got_handle:
+
+ ldr r1,=mmAllocChannel // allocate new channel
+ bl mpp_call_r1 //
+ cmp r0, #255 //
+ bge .no_available_channels //
+
+ mov r6, r0
+
+ cmp r5, #0
+ beq 1f
+
+ ldr r1,=mm_sfx_channels // register data
+ sub r2, r5, #1 // r3 = bit
+ lsl r2, #24 //
+ lsr r2, #24 //
+ mov r3, #1 //
+ lsl r3, r2 //
+ lsl r2, #1 //
+ add r1, r2 //
+ add r2, r0, #1 //
+ strb r2, [r1, #0] //
+ lsr r2, r5, #8 //
+ strb r2, [r1, #1] //
+
+ ldr r1,=mm_sfx_bitmask // set bit
+ ldr r2, [r1] //
+ orr r2, r3 //
+ str r2, [r1] //
+
+1:
+
+ ldr r1,=mm_achannels // setup channel
+ ldr r1, [r1] //
+ mov r2, #MCA_SIZE //
+ mul r2, r0 //
+ add r1, r2 //
+ //
+ mov r2, #releaseLevel //
+ strb r2, [r1, #MCA_FVOL] //
+
+ cmp r5, #0 //
+ bne 1f //
+ mov r2, #ACHN_BACKGROUND //
+ b 2f //
+1: mov r2, #ACHN_CUSTOM //
+2: //
+ strb r2, [r1, #MCA_TYPE] //
+ mov r2, #MCAF_EFFECT //
+ strb r2, [r1, #MCA_FLAGS] //
+
+ GET_MIXCH r1 // setup voice
+ mov r2, #MIXER_CHN_SIZE //
+ mul r2, r0 //
+ add r3, r1, r2 //
+
+#ifdef SYS_GBA
+
+ ldr r0,=mp_solution // set sample data address
+ ldr r0, [r0] //
+ ldrh r1, [r4, #MM_SFX_SOURCE] //
+ lsl r1, #2 //
+ add r1, #12 //
+ ldr r1, [r0, r1] //
+ add r1, r0 //
+ ldrh r2, [r1, #8+C_SAMPLEC_DFREQ] //
+ add r1, #8+C_SAMPLE_DATA //
+ str r1, [r3, #MIXER_CHN_SRC] //
+
+ ldrh r0, [r4, #MM_SFX_RATE] // set pitch to original * pitch
+ mul r2, r0 //
+ lsr r2, #10-2 //
+ str r2, [r3, #MIXER_CHN_FREQ] //
+
+ mov r1, #0 // reset read position
+ str r1, [r3, #MIXER_CHN_READ] //
+
+ ldrb r0, [r4, #MM_SFX_VOLUME] // set volume
+
+ ldr r1,=mm_sfx_mastervolume
+ ldr r1, [r1]
+ mul r0, r1
+ lsr r0, #10
+
+ strb r0, [r3, #MIXER_CHN_VOL] //
+
+ ldrb r0, [r4, #MM_SFX_PANNING] // set panning
+ strb r0, [r3, #MIXER_CHN_PAN] //
+
+#else
+ ldr r1, [r4, #MM_SFX_SOURCE] // set sample address
+ lsr r0, r1, #16 // > 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
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Nintendo DS & Gameboy Advance Sound System *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+.global mmInitDefault
+
+@----------------------------------------------------------------------------
+
+#include "mp_defs.inc"
+
+.equ mixlen, 1056 // 16khz
+
+ .bss
+ .align 2
+
+__mixbuffer:
+ .space mixlen
+
+ .text
+ .thumb
+ .align 2
+
+#define MM_SIZEOF_MODCH 40
+#define MM_SIZEOF_ACTCH 28
+#define MM_SIZEOF_MIXCH 24
+
+/****************************************************************************
+ * mmInitDefault( soundbank, #channels )
+ *
+ * Init maxmod with default settings.
+ ****************************************************************************/
+ .thumb_func
+mmInitDefault:
+
+ push {r0,r4,r5,r6,r7,lr} // preserve regs, push soundbank
+
+ //0 mode (3)
+ //1 mchcount (#channels)
+ //2 achcount (#channels)
+ //3 modch
+ //4 actch
+ //5 mixch
+ //6 mixmem (__mixbuffer)
+ //7 wavemem
+
+ mov r6, r1 // r6=#channels
+ ldr r0,=MM_SIZEOF_MODCH+MM_SIZEOF_ACTCH+MM_SIZEOF_MIXCH
+ mul r0, r6
+ ldr r4,=mixlen
+ add r0, r4
+ bl malloc
+
+ mov r7, r0 // wavemem = beginning of buffer
+ add r3, r0, r4 // split up buffer into addresses [r3,r4,r5]
+ mov r0, #MM_SIZEOF_MODCH //
+ mul r0, r6 //
+ add r4, r3, r0 //
+ mov r0, #MM_SIZEOF_ACTCH //
+ mul r0, r6 //
+ add r5, r4, r0 //
+ mov r0, #3 //
+ mov r1, r6 //
+ mov r2, r6 //
+ ldr r6,=__mixbuffer // r6 = mixbuffer (iwram)
+
+ push {r0-r7}
+
+ mov r0, sp // init maxmod, pass init struct
+ bl mmInit //
+
+ add sp, #MM_GBA_SYSTEM_SIZE // restore stack
+
+ pop {r4-r7} // return
+ pop {r0} //
+ bx r0 //
+
+.pool
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ * Definitions
+ *
+ ******************************************************************************/
+
+#include "mp_defs.inc"
+#include "mp_mas.inc"
+#include "mp_mas_structs.inc"
+#include "mp_macros.inc"
+
+#ifdef SYS_GBA
+#include "mp_mixer_gba.inc"
+#endif
+
+#ifdef SYS_NDS
+#include "mp_mixer_ds.inc"
+#endif
+
+/******************************************************************************
+ *
+ * Memory
+ *
+ ******************************************************************************/
+
+ .BSS
+ .ALIGN 2
+
+/******************************************************************************
+ * mmCallback
+ *
+ * Function pointer to user event handler
+ ******************************************************************************/
+ .global mmCallback
+mmCallback: .space 4
+
+/******************************************************************************
+ * mmModuleCount
+ *
+ * Number of modules in soundbank
+ ******************************************************************************/
+ .global mmModuleCount
+mmModuleCount: .space 4
+
+/******************************************************************************
+ * mmModuleBank
+ *
+ * Address of module bank
+ ******************************************************************************/
+ .global mmModuleBank
+mmModuleBank: .space 4
+
+/******************************************************************************
+ * mmSampleBank
+ *
+ * Address of sample bank
+ ******************************************************************************/
+ .global mmSampleBank
+mmSampleBank: .space 4
+
+/******************************************************************************
+ * mm_ch_mask
+ *
+ * Bitmask to select which hardware/software channels can be used
+ ******************************************************************************/
+ .global mm_ch_mask
+mm_ch_mask: .space 4
+
+/******************************************************************************
+ * mm_vblank_function
+ *
+ * Pointer to a user function to be called during the vblank irq
+ ******************************************************************************/
+ .global mm_vblank_function
+mm_vblank_function: .space 4
+
+/******************************************************************************
+ * mm_rds_pchannels, mm_rds_achannels
+ *
+ * Memory for module/active channels for NDS system
+ ******************************************************************************/
+#ifdef SYS_NDS
+mm_rds_pchannels: .space MCH_SIZE*32
+mm_rds_achannels: .space MCA_SIZE*32
+#endif
+
+/******************************************************************************
+ * mmInitialized
+ *
+ * Variable that will be 'true' if we are ready for playback
+ ******************************************************************************/
+ .global mmInitialized
+mmInitialized: .space 1
+
+
+
+
+/******************************************************************************
+ *
+ * Program
+ *
+ ******************************************************************************/
+
+
+
+
+/******************************************************************************
+ * mpp_call_*
+ *
+ * Functions to branch to a register
+ ******************************************************************************/
+
+#ifdef SYS_GBA
+.section ".iwram", "ax", %progbits
+.thumb
+.align 2
+
+.global mpp_call_r7i, mpp_call_r2i, mpp_call_r1i
+
+ .thumb_func
+//-----------------------------------------------------------------------------
+mpp_call_r7i: bx r7
+//-----------------------------------------------------------------------------
+
+ .thumb_func
+//-----------------------------------------------------------------------------
+mpp_call_r2i: bx r2
+//-----------------------------------------------------------------------------
+
+ .thumb_func
+//-----------------------------------------------------------------------------
+mpp_call_r1i: bx r1
+//-----------------------------------------------------------------------------
+
+#endif
+
+//-----------------------------------------------------------------------------
+ .TEXT
+ .THUMB
+ .ALIGN 2
+//-----------------------------------------------------------------------------
+
+.global mpp_call_r7, mpp_call_r1, mpp_call_r2, mpp_call_r3
+
+ .thumb_func
+@------------------------------------------------------------------------------
+mpp_call_r7: bx r7
+@------------------------------------------------------------------------------
+
+ .thumb_func
+@------------------------------------------------------------------------------
+mpp_call_r1: bx r1
+@------------------------------------------------------------------------------
+
+ .thumb_func
+@------------------------------------------------------------------------------
+mpp_call_r2: bx r2
+@------------------------------------------------------------------------------
+
+ .thumb_func
+@------------------------------------------------------------------------------
+mpp_call_r3: bx r3
+@------------------------------------------------------------------------------
+
+/******************************************************************************
+ * mmSetEventHandler
+ *
+ * Set function for handling playback events
+ ******************************************************************************/
+ .global mmSetEventHandler
+ .thumb_func
+mmSetEventHandler:
+
+ ldr r1,=mmCallback
+ str r0, [r1]
+ bx lr
+
+#ifdef SYS_NDS
+/******************************************************************************
+ * mmLockChannels( mask )
+ *
+ * Lock audio channels to prevent the sequencer from using them.
+ ******************************************************************************/
+ .global mmLockChannels
+ .thumb_func
+mmLockChannels:
+ push {r4, r5, lr}
+ ldr r1,=mm_ch_mask // clear bits
+ ldr r2, [r1] //
+ bic r2, r0 //
+ str r2, [r1] //
+
+ mov r4, r0
+ mov r5, #0
+
+2: lsr r4, #1
+ bcc 1f
+ mov r0, r5
+ bl StopActiveChannel
+1: add r5, #1
+ cmp r4, #0
+ bne 2b
+
+ pop {r4,r5}
+ pop {r3}
+ bx r3
+
+/******************************************************************************
+ * StopActiveChannel( index )
+ *
+ * Stop active channel
+ ******************************************************************************/
+ .thumb_func
+StopActiveChannel:
+ push {r4}
+
+ GET_MIXCH r1 // stop mixing channel
+ mov r2, #MIXER_CHN_SIZE //
+ mul r2, r0 //
+ add r1, r2 //
+ //
+ //
+ #ifdef SYS_GBA //
+ //
+ mov r2, #0 //
+ sub r2, #1 //
+ str r2, [r1, #MIXER_CHN_SRC] //
+ //
+ #endif //
+ //
+ #ifdef SYS_NDS //
+ //
+ mov r2, #0 //
+ str r2, [r1, #MIXER_CHN_SAMP] //
+ strh r2, [r1, #MIXER_CHN_CVOL] //
+ strh r2, [r1, #MIXER_CHN_VOL] //
+ //
+ #endif //
+
+ ldr r1,=0x4000400 // stop hardware channel
+ lsl r2, r0, #4 //
+ mov r3, #0 //
+ str r3, [r1, r2] //
+
+ ldr r1,=mm_achannels // disable achn
+ ldr r1, [r1] //
+ mov r2, #MCA_SIZE //
+ mul r2, r0 //
+ add r1, r2 //
+ mov r2, #0 //
+ ldrb r4, [r1, #MCA_FLAGS] //
+ strb r2, [r1, #MCA_FLAGS] //
+ strb r2, [r1, #MCA_TYPE] //
+
+ lsr r1, r4, #8
+ bcs .iseffect
+
+ lsr r4, #7
+ bcs .issub
+
+ ldr r1,=mm_pchannels // stop hooked pchannel
+ ldr r1, [r1] //
+ ldr r2,=mm_num_mch //
+ ldr r2, [r2] //
+ //
+2: ldrb r3, [r1, #MCH_ALLOC] //
+ cmp r3, r0 //
+ bne 1f //
+ mov r3, #255 //
+ strb r3, [r1, #MCH_ALLOC] //
+ b .iseffect //
+1: sub r2, #1 //
+ bne 2b //
+
+ b .iseffect //
+
+.issub:
+ // stop sub pchannel
+ ldr r1,=mm_schannels
+ mov r2, #4
+
+2: ldrb r3, [r1, #MCH_ALLOC] //
+ cmp r3, r0 //
+ bne 1f //
+ mov r3, #255 //
+ strb r3, [r1, #MCH_ALLOC] //
+ b .iseffect //
+1: sub r2, #1 //
+ bne 2b //
+
+.iseffect:
+
+ // hope it works out for effects...
+
+ pop {r4}
+ bx lr
+
+
+/******************************************************************************
+ * mmUnlockChannels( mask )
+ *
+ * Unlock audio channels so they can be used by the sequencer.
+ ******************************************************************************/
+ .global mmUnlockChannels
+ .thumb_func
+mmUnlockChannels:
+
+#ifdef SYS_NDS
+ ldr r1,=mm_mixing_mode // can NOT unlock channels in mode b
+ ldrb r1, [r1] //
+ cmp r1, #1 //
+ beq 1f //
+#endif
+
+ ldr r1,=mm_ch_mask
+ ldr r2, [r1]
+ orr r2, r0
+ str r2, [r1]
+1: bx lr
+#endif
+
+
+
+/******************************************************************************
+ *
+ * GBA
+ *
+ ******************************************************************************/
+
+
+
+
+//-----------------------------------------------------------------------------
+#ifdef SYS_GBA
+//-----------------------------------------------------------------------------
+
+ .BSS
+ .ALIGN 2
+
+/******************************************************************************
+ * mp_solution
+ *
+ * Address of soundbank in memory/rom
+ ******************************************************************************/
+ .global mp_solution
+mp_solution: .space 4
+
+ .TEXT
+ .THUMB
+ .ALIGN 2
+
+/******************************************************************************
+ * mmInit(system)
+ *
+ * Initialize maxmod
+ ******************************************************************************/
+ .global mmInit
+ .thumb_func
+mmInit:
+ push {lr}
+
+ ldr r2,=mp_solution
+ mov r1, #MM_GBA_SYSTEM_SOUNDBANK
+ ldr r1, [r0,r1]
+ str r1, [r2]
+
+ ldr r2,=mm_achannels
+ ldr r1, [r0,#MM_GBA_SYSTEM_ACTCH]
+ str r1, [r2]
+ ldr r1, [r0,#MM_GBA_SYSTEM_MODCH]
+ str r1, [r2,#4]
+ ldr r1, [r0,#MM_GBA_SYSTEM_MCH_COUNT]
+ str r1, [r2,#8]
+ ldr r1, [r0,#MM_GBA_SYSTEM_ACH_COUNT]
+ str r1, [r2,#12]
+
+ bl mmMixerInit @ initialize software/hardware mixer
+
+ ldr r1,=mm_num_ach
+ ldr r1,[r1]
+ mov r0,#1
+ lsl r0, r1
+ sub r0,#1
+
+ ldr r1,=mm_ch_mask
+ str r0, [r1]
+
+ ldr r0,=0x400 //
+ bl mmSetModuleVolume
+ ldr r0,=0x400 //
+ bl mmSetJingleVolume
+ ldr r0,=0x400 //
+ bl mmSetEffectsVolume //
+
+
+ ldr r0,=0x400
+ bl mmSetModuleTempo
+
+ ldr r0,=0x400
+ bl mmSetModulePitch
+
+ bl mmResetEffects
+
+ ret0
+
+/******************************************************************************
+ * mmSetVBlankHandler
+ *
+ * Set function to be called during the vblank IRQ
+ ******************************************************************************/
+ .global mmSetVBlankHandler
+ .thumb_func
+mmSetVBlankHandler:
+
+ ldr r1,=mm_vblank_function
+ str r0, [r1]
+ bx lr
+
+/******************************************************************************
+ * mmFrame()
+ *
+ * Work routine, user _must_ call this every frame.
+ ******************************************************************************/
+ .global mmFrame
+ .thumb_func
+mmFrame:
+
+ push {lr}
+ push {r4-r7}
+
+@ update effects
+
+ ldr r7,=mmUpdateEffects
+ bl _call_via_r7
+
+@ update sub layer
+@ sub layer has 60hz accuracy
+
+ ldr r7,=mppUpdateSub
+ bl _call_via_r7
+
+@ update main layer and mix samples.
+@ main layer is sample-accurate.
+
+ ldr r0,=mpp_channels @ copy channels
+ ldr r1,=mm_pchannels
+ ldr r1,[r1]
+ str r1, [r0]
+ ldr r0,=mpp_nchannels @ copy #channels
+ ldr r1,=mm_num_mch
+ ldr r1,[r1]
+ strb r1, [r0]
+ ldr r0,=mpp_clayer @ layer=0 (main)
+ mov r1, #0
+ strb r1, [r0]
+
+ ldr r0,=mmLayerMain @mpp_layerA @ copy layer pointer
+ ldr r1,=mpp_layerp
+ str r0, [r1]
+
+ ldr r4,=mm_mixlen
+ ldr r4,[r4]
+ @ mixlen is divisible by 2
+
+ ldrb r1, [r0, #MPL_ISPLAYING] @ check if main layer is active
+ cmp r1, #0
+ beq .mpf_no_mainlayer @ skip processing if disabled (and just mix samples)
+
+.mpf_mix_advr:
+
+ ldr r0,=mpp_layerp @ get layer
+ ldr r0, [r0]
+
+ mov r1, #MPL_TICKRATE @ get samples/tick
+ ldrh r5, [r0, r1]
+
+ mov r1, #MPL_SAMPCOUNT @ get sample count
+ ldrh r6, [r0,r1]
+
+ sub r5, r6 @ calc tickrate-counter
+ cmp r5, #0
+ bge 1f
+ mov r5, #0
+1: cmp r5, r4 @ > 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
+//-----------------------------------------------------------------------------
+
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Module Processing *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#include "mp_format_mas.inc"
+#include "mp_mas_structs.inc"
+#include "mp_defs.inc"
+#include "mp_macros.inc"
+
+//-----------------------------------------------------------------------------
+#ifdef SYS_GBA
+//-----------------------------------------------------------------------------
+
+#include "mp_mixer_gba.inc"
+#include "swi_gba.inc"
+
+//-----------------------------------------------------------------------------
+#endif
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+#ifdef SYS_NDS
+//-----------------------------------------------------------------------------
+#include "mp_mixer_ds.inc"
+#include "swi_nds.inc"
+//-----------------------------------------------------------------------------
+#endif
+//-----------------------------------------------------------------------------
+
+
+.equ S3M_FREQ_DIVIDER ,57268224 // (s3m,xm,it)
+.equ MOD_FREQ_DIVIDER_PAL ,56750314 // (mod)
+.equ MOD_FREQ_DIVIDER_NTSC ,57272724 // (---)
+
+
+
+/******************************************************************************
+ *
+ * Memory
+ *
+ ******************************************************************************/
+
+
+
+ .BSS
+ .ALIGN 2
+
+/******************************************************************************
+ * mmLayerMain
+ *
+ * Layer data for module playback.
+ ******************************************************************************/
+ .global mmLayerMain
+mmLayerMain: .space MPL_SIZE
+
+/******************************************************************************
+ * mmLayerSub
+ *
+ * Layer data for jingle playback.
+ ******************************************************************************/
+ .global mmLayerSub
+mmLayerSub: .space MPL_SIZE
+
+/******************************************************************************
+ * mpp_vars
+ *
+ * Holds intermediate data during the module processing.
+ ******************************************************************************/
+ .global mpp_vars
+mpp_vars: .space MPV_SIZE
+
+ .ALIGN 2
+
+/******************************************************************************
+ * mpp_layerp
+ *
+ * Pointer to layer data during processing.
+ ******************************************************************************/
+ .global mpp_layerp
+mpp_layerp: .space 4
+
+/******************************************************************************
+ * mpp_channels
+ *
+ * Pointer to channel array during processing
+ ******************************************************************************/
+ .global mpp_channels
+mpp_channels: .space 4
+
+/******************************************************************************
+ * mpp_resolution
+ *
+ * Speed divider for DS timing.
+ ******************************************************************************/
+
+mpp_resolution: .space 4
+
+/******************************************************************************
+ * mm_mastertempo
+ *
+ * Master tempo scaler.
+ ******************************************************************************/
+
+mm_mastertempo: .space 4
+
+/******************************************************************************
+ * mm_masterpitch
+ *
+ * Master pitch scaler.
+ ******************************************************************************/
+
+mm_masterpitch: .space 4
+
+/******************************************************************************
+ * mpp_nchannels
+ *
+ * Number of channels in layer
+ ******************************************************************************/
+ .global mpp_nchannels
+mpp_nchannels: .space 1
+
+/******************************************************************************
+ * mpp_clayer
+ *
+ * Layer selection, 0 = main, 1 = sub
+ ******************************************************************************/
+ .global mpp_clayer
+mpp_clayer: .space 1
+
+/******************************************************************************
+ * mm_achannels, mm_pchannels, mm_num_mch, mm_num_ach, mm_schannels
+ *
+ * Channel data/sizes, don't move these around--see mmInit first
+ ******************************************************************************/
+ .ALIGN 2
+
+.global mm_achannels, mm_pchannels, mm_num_mch, mm_num_ach, mm_schannels
+
+mm_achannels: .space 4
+mm_pchannels: .space 4
+mm_num_mch: .space 4
+mm_num_ach: .space 4
+mm_schannels: .space MP_SCHANNELS*MCH_SIZE
+
+
+
+/******************************************************************************
+ *
+ * Macros
+ *
+ ******************************************************************************/
+
+
+/******************************************************************************
+ * mpp_InstrumentPointer
+ *
+ * Calculate instrument address.
+ * Requires r8 = layer
+ * Returns in r0
+ * Trashes r1, r2
+ ******************************************************************************/
+.macro mpp_InstrumentPointer
+ mov r1, r8
+ ldr r2,[r1,#MPL_SONGADR]
+ ldr r1,[r1,#MPL_INSTTABLE]
+ lsl r0, #2
+ ldr r0,[r1,r0]
+ add r0, r2
+.endm
+
+/******************************************************************************
+ * mpp_SamplePointer
+ *
+ * Calculate sample address.
+ * Requires r8 = layer
+ * Returns in r0
+ * Trashes r1, r2
+ ******************************************************************************/
+.macro mpp_SamplePointer
+ mov r1, r8
+ ldr r2,[r1,#MPL_SONGADR]
+ ldr r1,[r1,#MPL_SAMPTABLE]
+ lsl r0, #2
+ ldr r0,[r1,r0]
+ add r0, r2
+.endm
+
+
+
+/******************************************************************************
+ *
+ * Program
+ *
+ ******************************************************************************/
+
+
+
+ .TEXT
+ .ALIGN 2
+
+/******************************************************************************
+ * mpp_resetchannels(...)
+ *
+ * Reset channel data, and any active channels linked to the layer.
+ * Requires r5 = layer, r6 = channels, r7 = #channels
+ ******************************************************************************/
+ .thumb_func
+mpp_resetchannels:
+
+ push {r4-r6}
+
+ mov r0, r6 // clear channel data to 0
+ mov r1, #MCH_SIZE/4 //
+ mul r1, r7 //
+ mov r2, #0 //
+1: stmia r0!, {r2} //
+ sub r1, #1 //
+ bne 1b //
+
+ mov r0, r6 // reset channel indexes
+ sub r0, #MCH_SIZE-MCH_ALLOC //
+ mov r1, #MCH_SIZE //
+ mul r1, r7 //
+ mov r2, #255 //
+1: strb r2, [r0, r1] //
+ sub r1, #MCH_SIZE //
+ bne 1b //
+
+ GET_MIXCH r4 // reset active channels linked to this layer
+ ldr r6,=mpp_clayer //
+ ldrb r6, [r6] //
+
+#ifdef SYS_GBA // disabled status differs between systems
+ ldr r5,=1<<31 //
+#endif //
+#ifdef SYS_NDS //
+ mov r5, #0 //
+#endif //
+
+ ldr r0,=mm_achannels // r0 = achannels
+ ldr r0, [r0] //
+ ldr r1,=mm_num_ach // r1 = #achannels
+ ldr r1, [r1] //
+ mov r2, #0 // r2 = 0 (for clearing)
+
+.mpic_loop3:
+ ldrb r3, [r0, #MCA_FLAGS] // test if layer matches
+ lsr r3, #6 //
+ cmp r3, r6 //
+ bne .mpic_l3_skip //
+
+ mov r3, #MCA_SIZE-4 // clear achannel data to zero
+.mpic_loop4: //
+ str r2, [r0, r3] //
+ sub r3, r3, #4 //
+ bpl .mpic_loop4 //
+
+ str r5, [r4] // disable mixer channel
+
+.mpic_l3_skip:
+
+ add r0, #MCA_SIZE // increment stuff and loop
+ add r4, #MIXER_CHN_SIZE //
+ //
+ sub r1, #1 //
+ bne .mpic_loop3 //
+
+ pop {r4-r6}
+ bx lr
+
+#ifdef SYS_NDS
+
+/******************************************************************************
+ * mm_reset_channels()
+ *
+ * Reset all channels.
+ ******************************************************************************/
+ .global mm_reset_channels
+ .thumb_func
+mm_reset_channels:
+
+ push {lr}
+
+ ldr r0,=mm_achannels // clear active channel data
+ ldr r0, [r0] //
+ mov r1, #0 //
+ ldr r2,=MCA_SIZE*32/4 //
+ //
+1: stmia r0!, {r1} //
+ sub r2, #1 //
+ bne 1b //
+
+ ldr r0,=mm_pchannels // reset channel allocation
+ ldr r0, [r0] //
+ mov r1, #255 //
+ mov r2, #32 //
+ //
+1: strb r1, [r0, #MCH_ALLOC] //
+ add r0, #MCH_SIZE //
+ sub r2, #1 //
+ bne 1b //
+
+ ldr r0,=mm_schannels // reset channel allocation
+ mov r2, #4 //
+ //
+1: strb r1, [r0, #MCH_ALLOC] //
+ add r0, #MCH_SIZE //
+ sub r2, #1 //
+ bne 1b //
+
+ bl mmResetEffects
+
+ pop {r3}
+ bx r3
+
+#endif
+
+/******************************************************************************
+ * mpp_suspend()
+ *
+ * Suspend main module and associated channels.
+ ******************************************************************************/
+ .thumb_func
+mpp_suspend:
+
+ push {r4,lr}
+ ldr r0,=mm_achannels
+ ldr r0, [r0]
+ GET_MIXCH r1
+ ldr r2,=mm_num_ach
+ ldr r2, [r2]
+ mov r4, #0
+.mpps_loop:
+ ldrb r3, [r0, #MCA_FLAGS]
+ lsr r3, #6
+ bne .mpps_next
+#ifdef SYS_GBA
+ str r4, [r1, #MIXER_CHN_FREQ]
+#else
+ strh r4, [r1, #MIXER_CHN_FREQ]
+ strh r4, [r1, #MIXER_CHN_VOL]
+#endif
+
+.mpps_next:
+ add r0, #MCA_SIZE
+ add r1, #MIXER_CHN_SIZE
+ sub r2, #1
+ bne .mpps_loop
+
+ pop {r4, pc}
+
+/******************************************************************************
+ *
+ * NDS System
+ *
+ ******************************************************************************/
+
+//-----------------------------------------------------------------------------
+#ifdef SYS_NDS
+//-----------------------------------------------------------------------------
+
+/******************************************************************************
+ * mmStart( module_ID, mode )
+ *
+ * Start module playback.
+ *
+ * module_ID : Index of module.
+ * mode : Playback mode.
+ ******************************************************************************/
+ .global mmStart
+ .thumb_func
+mmStart:
+
+ mov r2, #0
+.mpps_backdoor:
+ lsl r0, #2
+ ldr r3,=mmModuleBank
+ ldr r3, [r3]
+ ldr r0, [r3, r0]
+
+ cmp r0, #0
+ beq 1f
+ add r0, #8
+ b mmPlayModule
+1: bx lr
+
+/******************************************************************************
+ * mmJingle( module_ID )
+ *
+ * Play module as jingle.
+ *
+ * module_ID : Index of module
+ ******************************************************************************/
+ .global mmJingle
+ .thumb_func
+mmJingle:
+
+ mov r2, #1
+ mov r1, #MPP_PLAY_ONCE
+ b .mpps_backdoor
+
+//-----------------------------------------------------------------------------
+#endif
+//-----------------------------------------------------------------------------
+
+/******************************************************************************
+ *
+ * GBA System
+ *
+ ******************************************************************************/
+
+//-----------------------------------------------------------------------------
+#ifdef SYS_GBA
+//-----------------------------------------------------------------------------
+
+/******************************************************************************
+ * mmStart( module_ID, mode )
+ *
+ * Start module playback
+ *
+ * module_ID : id of module
+ * mode : mode of playback
+ ******************************************************************************/
+ .global mmStart
+ .thumb_func
+mmStart:
+
+ mov r2, #0
+.mpps_backdoor:
+ push {r2}
+ ldr r2,=mp_solution @ resolve song address
+ ldr r2, [r2]
+ ldrh r3, [r2, #0]
+ lsl r3, #2
+ add r3, #12
+ add r3, r2
+ lsl r0, #2
+ add r0, r3
+ ldr r0, [r0]
+ add r0, r2
+
+ pop {r2}
+
+ add r0, #8
+
+ b mmPlayModule
+1: bx lr
+
+/******************************************************************************
+ * mmJingle( module_ID )
+ *
+ * Start jingle playback
+ *
+ * module_ID : index of module
+ ******************************************************************************/
+ .global mmJingle
+ .thumb_func
+mmJingle:
+
+ mov r2, #1
+ mov r1, #MPP_PLAY_ONCE
+ b .mpps_backdoor
+
+//-----------------------------------------------------------------------------
+#endif
+//-----------------------------------------------------------------------------
+
+/******************************************************************************
+ * mmPlayModule( address, mode, layer )
+ *
+ * Start playing module.
+ ******************************************************************************/
+ .global mmPlayModule
+ .thumb_func
+mmPlayModule:
+
+ push {lr}
+ push {r4-r7}
+
+ ldr r3,=mpp_clayer
+ strb r2, [r3]
+
+ cmp r2, #0
+ bne 1f
+ 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]
+ b 2f
+1: ldr r5,=mmLayerSub
+ ldr r6,=mm_schannels
+ mov r7, #MP_SCHANNELS
+2:
+// push {r2}
+
+ mov r2, #MPL_MODE
+ strb r1, [r5, r2]
+
+ mov r4, r0
+ str r4, [r5, #MPL_SONGADR]
+
+ bl mpp_resetchannels
+
+ ldrb r3, [r4, #C_MAS_INSTN]
+ ldrb r2, [r4, #C_MAS_SAMPN]
+ lsl r3, #2
+ lsl r2, #2
+
+ mov r0, r4
+ add r0, #255
+ add r0, #C_MAS_TABLES-255
+
+ str r0, [r5, #MPL_INSTTABLE] @ setup instrument table
+ add r0, r3
+ str r0, [r5, #MPL_SAMPTABLE] @ setup sample table
+ add r0, r2
+ str r0, [r5, #MPL_PATTTABLE] @ setup pattern table
+
+ mov r0, #0 @ set pattern to 0
+
+ @ldr r1,=mpp_setposition
+ @bl mpp_call_r1
+ bl mpp_setposition
+
+ ldrb r0, [r4, #C_MAS_TEMPO] @ load initial tempo
+
+ bl mpp_setbpm
+
+ ldrb r0, [r4, #C_MAS_GV] @ load initial global volume
+
+
+ strb r0, [r5, #MPL_GV]
+
+ ldrb r0, [r4, #C_MAS_FLAGS] @ read song flags
+ strb r0, [r5, #MPL_FLAGS] @ save
+
+ lsl r0, #32-2
+ lsr r0, #32-2+1
+ strb r0, [r5, #MPL_OLDEFFECTS]
+
+ ldrb r0, [r4, #C_MAS_SPEED] @ speed
+ strb r0, [r5, #MPL_SPEED] @ and set
+
+ mov r0, #1 // mpp_playing=true
+ strb r0, [r5, #MPL_ISPLAYING]
+
+ mov r1, #MPL_VALID // set valid flag
+ strb r0, [r5, r1] //
+
+ bl mpp_resetvars
+
+ @ setup channel volumes
+ mov r0, r6
+ add r0, #MCH_CVOLUME
+ mov r3, r7
+ add r4, #C_MAS_CHANVOL
+.cvol_setup:
+ ldrb r1, [r4]
+ strb r1, [r0]
+ add r0, #MCH_SIZE
+ add r4, #1
+ sub r3, #1
+ bne .cvol_setup
+
+ add r4, #32
+ sub r4, r7
+
+ mov r0, r6
+ add r0, #MCH_PANNING
+ mov r3, r7
+.cpan_setup:
+ ldrb r1, [r4]
+ strb r1, [r0]
+ add r0, #MCH_SIZE
+ add r4, #1
+ sub r3, #1
+ bne .cpan_setup
+
+// pop {r2} @ <-- FIX.2 WHY WAS THIS PRESERVED
+
+ pop {r4-r7}
+ pop {r0} @ return
+
+ bx r0 @
+.pool
+
+/******************************************************************************
+ * mmPause()
+ *
+ * Pause module playback.
+ ******************************************************************************/
+ .global mmPause
+ .thumb_func
+mmPause:
+
+ push {lr}
+ push {r5}
+
+ ldr r5,=mmLayerMain
+
+ mov r0, #MPL_VALID
+ ldrb r0, [r5, r0]
+ cmp r0, #0
+ beq 1f
+
+ mov r0, #0
+ strb r0, [r5, #MPL_ISPLAYING]
+
+ bl mpp_suspend
+
+1: pop {r5}
+ ret0
+
+/******************************************************************************
+ * mmResume()
+ *
+ * Resume module playback.
+ ******************************************************************************/
+ .global mmResume
+ .thumb_func
+mmResume:
+
+ ldr r1,=mmLayerMain
+ mov r0, #MPL_VALID
+ ldrb r0, [r1, r0]
+ cmp r0, #0
+ beq 1f
+
+ mov r0, #1
+ strb r0, [r1, #MPL_ISPLAYING]
+1: bx lr
+
+/******************************************************************************
+ * mmActive()
+ *
+ * Returns true if module is playing.
+ ******************************************************************************/
+ .global mmActive
+ .thumb_func
+mmActive:
+
+ ldr r0,=mmLayerMain
+ ldrb r0, [r0, #MPL_ISPLAYING]
+ bx lr
+
+/******************************************************************************
+ * mmActiveSub()
+ *
+ * Returns true if a jingle is playing.
+ ******************************************************************************/
+ .global mmActiveSub
+ .thumb_func
+mmActiveSub:
+
+ ldr r0,=mmLayerSub
+ ldrb r0, [r0, #MPL_ISPLAYING]
+ bx lr
+
+/******************************************************************************
+ * mmSetModuleVolume( volume )
+ *
+ * Set master module volume.
+ *
+ * volume : 0->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 <address>
+@ 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
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Module Processing (ARM segment) *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+@=============================================================
+@ DEFINITIONS
+@=============================================================
+
+#include "mp_format_mas.inc"
+#include "mp_mas_structs.inc"
+#include "mp_defs.inc"
+#include "mp_macros.inc"
+
+#ifdef SYS_GBA
+#include "mp_mixer_gba.inc"
+#include "swi_gba.inc"
+#endif
+
+#ifdef SYS_NDS
+#include "mp_mixer_ds.inc"
+#include "swi_nds.inc"
+#endif
+
+__SECTION_IWRAM
+
+.arm
+.align 2
+
+.global mmAllocChannel
+@********************************************************
+mmAllocChannel:
+@********************************************************
+// finds a channel to use
+// returns invalid channel [255] if none available
+ push {r4,r5,r6} // preserve regs
+ ldr r5,=mm_ch_mask // read channel mask
+ ldr r5, [r5]
+ ldr r1,=mm_achannels // pointer to active channels
+ ldr r1, [r1]
+ add r1, #MCA_FVOL
+ mov r0, #0 // r0 = counter
+ mov r2, #0x80000000 // r2 = min vol
+ mov r3, #255 // r3 = best channel [255=none]
+ mov r6, #ACHN_BACKGROUND
+ b .mppac_start
+.mppac_skip:
+ add r1, #MCA_SIZE
+.mppac_next_test:
+ cmp r5, #0
+.mppac_next_notest:
+ beq .mppac_finished
+ add r0, #1
+.mppac_start:
+ movs r5, r5, lsr#1 // 1 shift out channel bit
+ bcc .mppac_skip // 1/3 skip if cleared
+ ldrh r4, [r1], #MCA_SIZE // 5 read type setting & increment pointer
+ cmp r6, r4, lsr #8 // 1 compare background/disabled
+ blt .mppac_next_test // 1/3 if > 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
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * GBA Audio System *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+@ DEFINITIONS
+
+#include "mp_macros.inc"
+#include "mp_format_mas.inc"
+#include "mp_defs.inc"
+
+@ timer freq = 2^24 / mixfreq
+@ mixlen ~= mixfreq * 0.01673
+@ recommended mixing frequencies: 5734,7884,10512,13379,15768,18157,21024,26758,31536,36314,40137,42048
+@ other mixing frequencies may cause clicks
+@ mixlen must be divisible by 2
+
+@==================================================================
+@ GLOBAL SYMBOLS
+@==================================================================
+
+
+ .global mmVBlank
+ .type mmVBlank STT_FUNC
+ .global mmMixerMix
+ .type mmMixerMix STT_FUNC
+
+ .global mmMixerSetSource
+ .type mmMixerSetSource STT_FUNC
+ .global mmMixerSetRead
+ .type mmMixerSetRead STT_FUNC
+ .global mmMixerSetFreq
+ .type mmMixerSetFreq STT_FUNC
+ .global mmMixerStopChannel
+ .type mmMixerStopChannel STT_FUNC
+ .global mmMixerInit
+ .type mmMixerInit STT_FUNC
+ .global mmMixerChannelActive
+ .type mmMixerChannelActive STT_FUNC
+ .global mmMixerMulFreq
+ .type mmMixerMulFreq STT_FUNC
+ .global mmMixerSetVolume
+ .type mmMixerSetVolume STT_FUNC
+ .global mmMixerSetPan
+ .type mmMixerSetPan STT_FUNC
+
+// .global mm_freqscalar
+ .global mm_mixlen
+ .global mm_bpmdv
+ .global mp_mix_seg
+ .global mp_writepos
+ .global mm_mixchannels
+
+@===============================================
+@ more definitions
+@===============================================
+
+.EQU REG_SOUNDCNT_L, 0x4000080
+.EQU REG_SOUNDCNT_H, 0x4000082
+.EQU REG_SOUNDCNT_X, 0x4000084
+
+.EQU REG_TM0CNT, 0x4000100
+
+.EQU REG_DMA1SAD, 0x40000BC
+.EQU REG_DMA1DAD, 0x40000C0
+.EQU REG_DMA1CNT, 0x40000C4
+
+.EQU REG_DMA2SAD, 0x40000C8
+.EQU REG_DMA2DAD, 0x40000CC
+.EQU REG_DMA2CNT, 0x40000D0
+
+.EQU REG_DMA3SAD, 0x40000D4
+.EQU REG_DMA3DAD, 0x40000D8
+.EQU REG_DMA3CNT, 0x40000DC
+
+.EQU REG_SGFIFOA, 0x40000A0
+.EQU REG_SGFIFOB, 0x40000A4
+.EQU REG_VCOUNT, 0x4000006
+
+@ MIXER CHANNEL FORMAT
+
+.equ CHN_SIZE, 24
+
+.equ CHN_SRC,0
+.equ CHN_READ,4
+.equ CHN_VOL,8
+.equ CHN_PAN,9
+// 10
+// 11
+.equ CHN_FREQ,12
+.equ CHN_SIZE,16
+
+/////////////////////.equ CHN_LOOP,8
+/////////////////////.equ CHN_LEN,16
+
+@-------------------------------------
+
+.equ FETCH_SIZE, 384
+.equ FETCH_THRESHOLD, (6016)//7040 // frequency threshold (dont use fetch for high freqs!)
+
+@======================================================================
+@ MEMORY
+@======================================================================
+
+.section .bss
+.align 2
+
+mp_writepos: .space 4 @ wavebuffer write position
+
+mm_mixbuffer: .space 4 @ dont move (see init)
+mm_mixchannels: .space 4 @ dont move
+mm_wavebuffer: .space 4 @ dont move
+mm_mixlen: .space 4 @ dont move
+mm_mixch_count: .space 4 @ dont move
+mm_mixch_end: .space 4 @ dont move
+mm_ratescale: .space 4 @ dont move
+mm_timerfreq: .space 4 @ dont move
+
+mm_bpmdv: .space 4
+
+mp_mix_seg: .space 1 @ mixing segment select
+
+.align 2
+
+mm_fetch: .space FETCH_SIZE+16
+
+@ 11-bit mixed sample buffer
+@ data is interleaved
+@ left,left,right,right,left,left,etc...
+
+@===========================================================================
+@ PROGRAM
+@===========================================================================
+
+.section .iwram, "ax", %progbits
+
+.ARM
+.ALIGN 2
+
+mpm_nullsample:
+.byte 128
+
+.align 2
+@-----------------------------------------------------------------------------------------------------
+mmVBlank: @ vblank wrapper, used to reset dma...HIGH PRIORITY PLEASE!
+@-----------------------------------------------------------------------------------------------------
+
+ b .mpvb_disabled @ disable until ready.. (overwrite this area with NOP)
+
+ ldr r0,=mp_mix_seg @ swap mixing segmentl
+ ldrsb r1, [r0]
+ mvns r1, r1
+ strb r1, [r0]
+ beq .mpvb_exit
+
+ ldr r1,=0x040000c6 @ dma control RESTART DMA
+ ldr r0,=0x0440 @ disable dma
+ strh r0, [r1]
+ strh r0, [r1,#12]
+ ldr r0,=0xB600 @ restart dma
+ strh r0, [r1]
+ strh r0, [r1,#12]
+
+ b .mpvb_dontreset
+.mpvb_exit:
+ ldr r0,=mp_writepos @ restart write position
+@ ldr r1,=mp_playbuffer_l @ ...
+ ldr r1,=mm_wavebuffer
+ ldr r1, [r1]
+ str r1, [r0] @ ...
+.mpvb_dontreset:
+
+.mpvb_disabled:
+ ldr r0,=0x3007FF8 @ acknowledge interrupt
+ ldrh r2, [r0]
+ orr r2, r2, #0x1
+ strh r2, [r0]
+
+ ldr r0,=mm_vblank_function
+ ldr r0, [r0]
+ cmp r0, #0
+ bxeq lr
+ bx r0
+.pool
+
+.align 2
+@-------------------------------------------------------------------------
+mmMixerMix: @ params={ samples_count }
+@-------------------------------------------------------------------------
+
+@ exit function if samples == 0
+@ it will malfunction.
+
+ cmp r0, #0
+ bne .mp_zerocheck
+ bx lr
+
+.mp_zerocheck:
+
+@ preserve registers
+
+ stmfd sp!, {r4-r11,lr}
+
+ stmfd sp!, {r0} @ preserve mixing count
+
+@------------------------------------------------------------------------
+@ SECTOR 0, INITIALIZATION
+@------------------------------------------------------------------------
+
+@ clear mixing buffers
+
+ and r10, r0, #7
+ mov r2, r0, lsr#3 @ clearing samps*2*2 bytes (hword*stereo) 32 bytes at a time
+ ldr r0,=mm_mixbuffer
+ ldr r0,[r0]
+ mov r1, #0 @ zero variable
+ mov r3, r1
+ mov r4, r1
+ mov r5, r1
+ mov r6, r1
+ mov r7, r1
+ mov r8, r1
+ mov r9, r1
+
+ cmp r2, #0
+ beq 2f
+
+@ clear 32 bytes/write
+
+1: stmia r0!, {r1,r3-r9}
+ subs r2, r2, #1
+ bne 1b
+2:
+
+@ clear remainder
+ cmp r10, #0
+ beq 2f
+
+1: str r1, [r0], #4
+ subs r10, r10, #1
+ bne 1b
+2:
+
+@----------------------------------------------------------------------------------
+@ BEGIN MIXING ROUTINE
+@----------------------------------------------------------------------------------
+
+ ldr r12,=mm_mixchannels
+ ldr r12,[r12]
+ mov r11, #0 @ volume addition
+
+@--------------------
+.mpm_cloop:
+@--------------------
+
+@----------------------------------------------------------------------
+@ SECTOR 1, CALCULATIONS
+@----------------------------------------------------------------------
+
+@ aliases
+#define rchan r12
+#define rvolA r11
+#define rsrc r10
+#define rfreq r9
+#define rmixb r8
+#define rread r7
+#define rvolL r5
+#define rvolR r6
+#define rmixc r4
+#define rmixcc r3
+
+@ read source address
+
+ ldr rsrc, [rchan, #CHN_SRC]
+ cmp rsrc, #0
+ bmi .mpm_next @ EXIT if MSB is set ------------>
+
+@ 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 (<<SAMPFRAC) from position
+
+ cmp rmixc, #0 // mix more samples?
+ ble .mpm_channelfinished // no ->
+ 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
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+// TYPE DEFINITIONS
+
+#ifndef MM_TYPES_H
+#define MM_TYPES_H
+
+typedef unsigned int mm_word; // 32 bits
+typedef unsigned short mm_hword; // 16 bits
+typedef unsigned char mm_byte; // 8 bits
+
+typedef unsigned short mm_sfxhand; // sound effect handle
+
+typedef unsigned char mm_bool; // boolean value
+
+typedef void* mm_addr; // pointer
+typedef void* mm_reg; // hardware register
+
+typedef enum
+{
+ MM_MODE_A,
+ MM_MODE_B,
+ MM_MODE_C
+} mm_mode_enum;
+
+typedef enum
+{
+ MM_STREAM_8BIT_MONO = 0x0, // 000b
+ MM_STREAM_8BIT_STEREO = 0x1, // 001b
+
+ MM_STREAM_16BIT_MONO = 0x2, // 010b
+ MM_STREAM_16BIT_STEREO = 0x3, // 011b
+
+// MM_STREAM_ADPCM_MONO = 0x4, // 100b
+// MM_STREAM_ADPCM_STEREO = 0x5, // 101b
+
+// adpcm streaming is not supported by the ds hardware
+// (the loop point data gets recorded so ring buffers are not possible)
+
+//-----------------------------------------------------------------------------
+} mm_stream_formats;
+//-----------------------------------------------------------------------------
+
+typedef mm_word (*mm_callback)( mm_word msg, mm_word param );
+typedef mm_word (*mm_stream_func)( mm_word length, mm_addr dest, mm_stream_formats format );
+
+typedef enum
+{
+ MMRF_MEMORY =0x01,
+ MMRF_DELAY =0x02,
+ MMRF_RATE =0x04,
+ MMRF_FEEDBACK =0x08,
+ MMRF_PANNING =0x10,
+ MMRF_LEFT =0x20,
+ MMRF_RIGHT =0x40,
+ MMRF_BOTH =0x60,
+
+ MMRF_INVERSEPAN =0x80,
+ MMRF_NODRYLEFT =0x100,
+ MMRF_NODRYRIGHT =0x200,
+ MMRF_8BITLEFT =0x400,
+ MMRF_16BITLEFT =0x800,
+ MMRF_8BITRIGHT =0x1000,
+ MMRF_16BITRIGHT =0x2000,
+ MMRF_DRYLEFT =0x4000,
+ MMRF_DRYRIGHT =0x8000
+//-----------------------------------------------------------------------------
+} mm_reverbflags;
+//-----------------------------------------------------------------------------
+
+typedef enum
+{
+ MMRC_LEFT = 1,
+ MMRC_RIGHT = 2,
+ MMRC_BOTH = 3
+//-----------------------------------------------------------------------------
+} mm_reverbch;
+//-----------------------------------------------------------------------------
+
+
+typedef struct mmreverbcfg
+{
+ mm_word flags;
+ mm_addr memory;
+ mm_hword delay;
+ mm_hword rate;
+ mm_hword feedback;
+ mm_byte panning;
+//-----------------------------------------------------------------------------
+} mm_reverb_cfg;
+//-----------------------------------------------------------------------------
+
+typedef enum
+{
+ MM_PLAY_LOOP,
+ MM_PLAY_ONCE
+//-----------------------------------------------------------------------------
+} mm_pmode;
+//-----------------------------------------------------------------------------
+
+typedef enum
+{
+ MM_MIX_8KHZ,
+ MM_MIX_10KHZ,
+ MM_MIX_13KHZ,
+ MM_MIX_16KHZ,
+ MM_MIX_18KHZ,
+ MM_MIX_21KHZ,
+ MM_MIX_27KHZ,
+ MM_MIX_31KHZ
+//-----------------------------------------------------------------------------
+} mm_mixmode;
+//-----------------------------------------------------------------------------
+
+typedef enum
+{
+ MM_TIMER0, // hardware timer 0
+ MM_TIMER1, // hardware timer 1
+ MM_TIMER2, // hardware timer 2
+ MM_TIMER3 // hardware timer 3
+
+//-----------------------------------------------------------------------------
+} mm_stream_timer;
+//-----------------------------------------------------------------------------
+
+typedef struct t_mmdssample
+{
+ mm_word loop_start;
+ union {
+ mm_word loop_length;
+ mm_word length;
+ };
+ mm_byte format;
+ mm_byte repeat_mode;
+ mm_hword base_rate;
+ mm_addr data;
+//-----------------------------------------------------------------------------
+} mm_ds_sample;
+//-----------------------------------------------------------------------------
+
+typedef struct t_mmsoundeffect
+{
+ union {
+// sample ID (defined in soundbank header)
+ mm_word id;
+
+// external sample address, not valid on GBA system
+ mm_ds_sample* sample;
+ };
+
+// playback rate
+ mm_hword rate;
+
+// sound handle
+ mm_sfxhand handle;
+
+// volume, 0..255
+ mm_byte volume;
+
+// panning, 0..255
+ mm_byte panning;
+
+//-----------------------------------------------------------------------------
+} mm_sound_effect;
+//-----------------------------------------------------------------------------
+
+typedef struct t_mmgbasystem
+{
+ mm_mixmode mixing_mode;
+ mm_word mod_channel_count;
+ mm_word mix_channel_count;
+ mm_addr module_channels;
+ mm_addr active_channels;
+ mm_addr mixing_channels;
+ mm_addr mixing_memory;
+ mm_addr wave_memory;
+ mm_addr soundbank;
+//-----------------------------------------------------------------------------
+} mm_gba_system;
+//-----------------------------------------------------------------------------
+
+typedef struct t_mmdssystem
+{
+
+// give MSL_NSONGS
+ mm_word mod_count;
+
+// pass MSL_NSAMPS
+ mm_word samp_count;
+
+// pass pointer to memory buffer
+// (mm_word mem_bank[MSL_BANKSIZE])
+ mm_word* mem_bank;
+
+// fifo channel to use (usually 7)
+ mm_word fifo_channel;
+
+//-----------------------------------------------------------------------------
+} mm_ds_system;
+//-----------------------------------------------------------------------------
+
+typedef struct t_mmstream
+{
+// sampling rate. 1024->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
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#ifndef MP_DEFS_INC
+#define MP_DEFS_INC
+
+@ song 'mode' can be one of the following:
+.equ MPP_PLAY_LOOP ,0
+.equ MPP_PLAY_ONCE ,1
+.equ MPP_PLAY_JINGLE ,2
+
+@ other definitions
+#ifdef SYS_GBA
+
+.struct 0
+MM_GBA_SYSTEM_MODE: .space 4
+MM_GBA_SYSTEM_MCH_COUNT: .space 4
+MM_GBA_SYSTEM_ACH_COUNT: .space 4
+MM_GBA_SYSTEM_MODCH: .space 4
+MM_GBA_SYSTEM_ACTCH: .space 4
+MM_GBA_SYSTEM_MIXCH: .space 4
+MM_GBA_SYSTEM_MIXMEM: .space 4
+MM_GBA_SYSTEM_WAVEMEM: .space 4
+MM_GBA_SYSTEM_SOUNDBANK: .space 4
+MM_GBA_SYSTEM_SIZE:
+
+.equ SAMPFRAC, 12 @ # of bits used in fractional part of sample reading
+#endif
+
+.equ MP_SCHANNELS ,4
+
+@ callback parameters
+
+.equ MMCB_SONGREQUEST ,0x1A @ nds9
+.equ MMCB_SAMPREQUEST ,0x1B @ nds9
+.equ MMCB_DELETESONG ,0x1C @ nds9
+.equ MMCB_DELETESAMPLE ,0x1D @ nds9
+
+@.equ MPCB_SAMPMEMORY ,0x1E @ ---
+@.equ MPCB_SONGMEMORY ,0x1F @ ---
+.equ MMCB_BANKMEMORY ,0x1E @ nds9
+
+.equ MPCB_SONGMESSAGE ,0x2A @ gba/nds7 song playback
+.equ MPCB_SONGFINISHED ,0x2B @ gba/nds7
+
+.struct 0
+mms_rate: .space 4
+mms_len: .space 4
+mms_function: .space 4
+mms_format: .space 4
+mms_timer: .space 4
+mms_manual: .space 1
+mms_size:
+
+.struct 0 // reverb cfg struct
+mmrc_flags: .space 4
+mmrc_memory: .space 4
+mmrc_delay: .space 2
+mmrc_rate: .space 2
+mmrc_feedback: .space 2
+mmrc_panning: .space 1
+
+.equ MMRFS_MEMORY, 0
+.equ MMRFS_DELAY, 1
+.equ MMRFS_RATE, 2
+.equ MMRFS_FEEDBACK, 3
+.equ MMRFS_PANNING, 4
+.equ MMRFS_LEFT, 5
+.equ MMRFS_RIGHT, 6
+.equ MMRFS_INVERSEPAN, 7
+.equ MMRFS_NODRYLEFT, 8
+.equ MMRFS_NODRYRIGHT, 9
+.equ MMRFS_8BITLEFT, 10
+.equ MMRFS_16BITLEFT, 11
+.equ MMRFS_8BITRIGHT, 12
+.equ MMRFS_16BITRIGHT, 13
+.equ MMRFS_DRYLEFT, 14
+.equ MMRFS_DRYRIGHT, 15
+
+// reverbcfg flags
+.equ MMRF_MEMORY, 1<<MMRFS_MEMORY
+.equ MMRF_DELAY, 1<<MMRFS_DELAY
+.equ MMRF_RATE, 1<<MMRFS_RATE
+.equ MMRF_FEEDBACK, 1<<MMRFS_FEEDBACK
+.equ MMRF_PANNING, 1<<MMRFS_PANNING
+.equ MMRF_LEFT, 1<<MMRFS_LEFT
+.equ MMRF_RIGHT, 1<<MMRFS_RIGHT
+.equ MMRF_INVERSEPAN,1<<MMRFS_INVERSEPAN
+.equ MMRF_NODRYLEFT, 1<<MMRFS_DRYLEFT
+.equ MMRF_NODRYRIGHT,1<<MMRFS_DRYRIGHT
+.equ MMRF_8BITLEFT, 1<<MMRFS_8BITLEFT
+.equ MMRF_16BITLEFT, 1<<MMRFS_16BITLEFT
+.equ MMRF_8BITRIGHT, 1<<MMRFS_8BITRIGHT
+.equ MMRF_16BITRIGHT,1<<MMRFS_16BITRIGHT
+.equ MMRF_DRYLEFT, 1<<MMRFS_DRYLEFT
+.equ MMRF_DRYRIGHT, 1<<MMRFS_DRYRIGHT
+
+#endif
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+.ifndef MP_FORMAT_MAS_INC
+.equ MP_FORMAT_MAS_INC, 1
+
+@ MAS header structure..................................
+.equ C_MAS_LEN ,0
+.equ C_MAS_INSTN ,1
+.equ C_MAS_SAMPN ,2
+.equ C_MAS_PATTN ,3
+.equ C_MAS_FLAGS ,4
+.equ C_MAS_GV ,5
+.equ C_MAS_SPEED ,6
+.equ C_MAS_TEMPO ,7
+.equ C_MAS_REP ,8
+
+.equ C_MAS_CHANVOL ,12
+.equ C_MAS_CHANPAN ,44
+.equ C_MAS_ORDER ,76
+.equ C_MAS_TABLES ,276
+
+.equ C_FLAGS_GS ,1
+.equ C_FLAGS_OS ,2
+.equ C_FLAGS_SS ,3
+.equ C_FLAGS_XS ,4
+.equ C_FLAGS_DS ,5
+///////.equ C_FLAGS_LS ,5 HUH???
+.equ C_FLAGS_LS ,6
+
+.equ C_FLAGS_X, (1<<3)
+
+@ instrument struct.....................................
+.equ C_MASI_GVOL ,0
+.equ C_MASI_FADE ,1
+.equ C_MASI_RANDVOL ,2
+.equ C_MASI_DCT ,3
+.equ C_MASI_NNA ,4
+.equ C_MASI_ENVFLAGS ,5
+.equ C_MASI_PAN ,6
+.equ C_MASI_DCA ,7
+.equ C_MASI_MAP ,8
+.equ C_MASI_ENVELOPES,12
+//.equ C_MASI_ENVELOPES,248
+
+.equ C_MASIE_SIZE ,0
+.equ C_MASIE_LSTART ,1
+.equ C_MASIE_LEND ,2
+.equ C_MASIE_SSTART ,3
+.equ C_MASIE_SEND ,4
+.equ C_MASIE_NODEC ,5
+.equ C_MASIE_FILTER ,6
+.equ C_MASIE_NODES ,8
+
+.EQU ENVFLAG_A, 0b1000
+
+@ sample structure......................................
+.equ C_MASS_DV ,0
+.equ C_MASS_PAN ,1
+.equ C_MASS_FREQ ,2
+.equ C_MASS_VIT ,4
+.equ C_MASS_VID ,5
+.equ C_MASS_VIS ,6
+.equ C_MASS_VIR ,8
+.equ C_MASS_GV ,7
+
+.equ C_MASS_MSLID ,10
+
+@ pattern structure.....................................
+.equ C_MASP_NROWS ,0
+.equ C_MASP_DATA ,1
+
+@ sample structure......................................
+.equ C_SAMPLE_LEN ,0
+.equ C_SAMPLE_LOOP ,4
+.equ C_SAMPLE_POINT ,12
+.equ C_SAMPLE_DATA ,16
+
+.equ C_SAMPLEN_LSTART,0
+.equ C_SAMPLEN_LEN ,4
+.equ C_SAMPLEN_FORMAT,8
+.equ C_SAMPLEN_REP ,9
+.equ C_SAMPLEN_POINT ,12
+.equ C_SAMPLEN_DATA ,16
+
+.equ C_SAMPLEC_DFREQ ,10
+
+
+.endif
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * MACROS TO MAKE LIFE EASY *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#ifdef SYS_NDS9
+
+.macro ret0 @ arm9 pop {pc} has mode change
+ pop {pc}
+.endm
+.macro ret1 @ arm9 pop {pc} has mode change
+ pop {pc}
+.endm
+.macro ret2 @ arm9 pop {pc} has mode change
+ pop {pc}
+.endm
+.macro ret3 @ arm9 pop {pc} has mode change
+ pop {pc}
+.endm
+
+.macro jump7
+ blx r7
+.endm
+
+
+.macro jump2
+ blx r2
+.endm
+
+.macro jump1
+ blx r1
+.endm
+
+.macro fjump2 function
+ ldr r2,=function
+ blx r2
+.endm
+
+#else
+
+.macro ret0 @ arm7 requires pop/bx combo
+ pop {r0}
+ bx r0
+.endm
+.macro ret1
+ pop {r1}
+ bx r1
+.endm
+.macro ret2
+ pop {r2}
+ bx r2
+.endm
+.macro ret3
+ pop {r3}
+ bx r3
+.endm
+
+
+.macro jump7
+#ifdef USE_IWRAM
+ bl mpp_call_r7i
+#else
+ bl mpp_call_r7
+#endif
+.endm
+
+.macro jump2
+#ifdef USE_IWRAM
+ bl mpp_call_r2i
+#else
+ bl mpp_call_r2
+#endif
+.endm
+
+.macro fjump2 function
+ ldr r2,=\function
+ jump2
+.endm
+
+.macro jump1
+#ifdef USE_IWRAM
+ bl mpp_call_r1i
+#else
+ bl mpp_call_r1
+#endif
+.endm
+
+#endif
+
+.macro break9
+9: b 9b
+.endm
+
+.macro breakp
+mov r11,r11
+.endm
+
+.macro GET_MIXCH reg
+#ifdef SYS_NDS
+ ldr \reg,=mm_mix_channels
+#endif
+#ifdef SYS_GBA
+ ldr \reg,=mm_mixchannels
+ ldr \reg, [\reg]
+#endif
+.endm
+
+//#define ENABLE_PROFILE
+
+.macro PROF_START mode
+
+#ifdef ENABLE_PROFILE
+
+ push {r0-r3}
+ push {lr}
+ ldr r1,=profile_start
+ mov r2, pc
+ add r2, #5
+ mov lr, r2
+ bx r1
+ pop {r0}
+ mov lr, r0
+ pop {r0-r3}
+#endif
+
+.endm
+
+.macro PROF_END mode
+
+#ifdef ENABLE_PROFILE
+ push {r0-r3}
+ push {lr}
+ mov r0, #\mode
+ ldr r1,=profile_take
+ mov r2, pc
+ add r2, #5
+ mov lr, r2
+ bx r1
+ pop {r0}
+ mov lr, r0
+ pop {r0-r3}
+
+#endif
+
+.endm
+
+.macro __SECTION_IWRAM
+#ifdef SYS_GBA
+ .section ".iwram", "ax", %progbits
+#else
+ .text
+#endif
+.endm
+
+//------------------------------
+.macro nocash_msg msg
+//------------------------------
+ mov r12,r12
+ b 9f
+ .hword 0x6464
+ .hword 0
+ .string "\msg"
+ .align 2
+9:
+.endm
+//------------------------------
+.macro nocash_reset_clks
+//------------------------------
+ nocash_msg %zeroclks%
+.endm
+//------------------------------
+.macro nocash_print_clks
+//------------------------------
+ nocash_msg %lastclks%
+.endm
+//------------------------------
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#ifndef MP_MAS_INC
+#define MP_MAS_INC
+
+@#ifdef SYS_NDS
+@.equ MP_MCHANNELS ,16
+@#else
+@.equ MP_MCHANNELS ,32
+@#endif
+
+.extern mpp_vars
+.extern mpp_pattread
+.extern mpp_sm_handle
+
+.extern mpp_resetchannels
+.extern mpp_PlaySong
+.extern mpp_processtick
+
+#endif
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+@ Layer Information
+@ -----------------
+
+.equ MPL_TICK ,0
+.equ MPL_ROW ,1
+.equ MPL_POSITION ,2
+.equ MPL_NROWS ,3
+.equ MPL_GV ,4
+.equ MPL_SPEED ,5
+.equ MPL_ISPLAYING ,6
+.equ MPL_BPM ,7
+.equ MPL_INSTTABLE ,8
+.equ MPL_SAMPTABLE ,12
+.equ MPL_PATTTABLE ,16
+.equ MPL_SONGADR ,20
+.equ MPL_FLAGS ,24
+.equ MPL_OLDEFFECTS ,25
+.equ MPL_PATTJUMP ,26
+.equ MPL_PATTJUMP_ROW,27
+.equ MPL_FPATTDELAY ,28
+.equ MPL_PATTDELAY ,29
+
+.equ MPL_PLOOP_ROW ,30
+.equ MPL_PLOOP_TIMES ,31
+.equ MPL_PLOOP_ADR ,32
+.equ MPL_PATTREAD ,36
+.equ MPL_PLOOP_JUMP ,40
+.equ MPL_VALID ,41
+
+.equ MPL_TICKRATE ,42 @ 1.15 fixed point OR sample count
+.equ MPL_SAMPCOUNT ,44 @ sample timing
+.equ MPL_TICKFRAC ,44 @ vsync timing 0.16 fixed point
+
+.equ MPL_MODE ,46
+.equ mpl_reserved2 ,47
+.equ MPL_MCH_UPDATE ,48
+.equ MPL_VOLUME ,52
+.equ mpl_reserved3 ,54
+.equ MPL_SIZE ,56
+
+@ active information
+@--------------------
+
+.equ MPV_PATTREAD_P ,4
+.equ MPV_AFVOL ,8
+.equ MPV_SAMPOFF ,9
+.equ MPV_VOLPLUS ,10
+.equ MPV_NOTEDELAY ,11
+.equ MPV_PANPLUS ,12
+.equ MPV_SIZE ,14
+
+@ Module Channel
+@ --------------
+
+.EQU MCH_ALLOC, 0 @ ALLOCATED ACTIVE CHANNEL#
+.EQU MCH_CFLAGS, 1 @ PATTERN COMRESSION FLAGS, called "maskvariable" in ITTECH.TXT
+.EQU MCH_PANNING, 2
+.EQU MCH_VOLCMD, 3 @ VOLUME COLUMN COMMAND
+.EQU MCH_EFFECT, 4 @ EFFECT# } COMBINED
+.EQU MCH_PARAM, 5 @ EFFECT PARAMETER }
+.EQU MCH_FXMEM, 6 @ EFFECT MEMORY
+.EQU MCH_NOTE, 7 @ TRANSLATED NOTE
+.EQU MCH_FLAGS, 8 @ CHANNEL FLAGS
+.EQU MCH_INST, 9 @ INSTRUMENT#
+//.EQU MCH_PFLAGS, 10 @ PLAYBACK FLAGS (???)
+.EQU MCH_VIBDEP, 11
+.EQU MCH_VIBSPD, 12
+.EQU MCH_VIBPOS, 13
+.EQU MCH_VOLUME, 14 //}combined
+.EQU MCH_CVOLUME, 15 //}
+.EQU MCH_PERIOD, 16
+.EQU MCH_BFLAGS, 20
+.EQU MCH_PNOTE, 22 @ PATTERN NOTE
+.EQU MCH_MEMORY, 23 @ 15 bytes
+.EQU MCH_SIZE, 40 @ sizeof( module_channel ) @ 2 extra bytes
+
+@ Active Channel
+@ --------------
+
+.EQU MCA_PERIOD, 0 @ internal period
+.EQU MCA_FADE, 4 // }
+.EQU MCA_ENVC_VOL, 6 // }
+.EQU MCA_ENVC_PAN, 8 // } COMBINED
+.EQU MCA_ENVC_PIC, 10 // } during volume reset
+.EQU MCA_AVIB_DEP, 12 // } AND NEWNOTE, CHECK NEWNOTE ON CHANGES
+.EQU MCA_AVIB_POS, 14 // }
+.EQU MCA_FVOL, 16 // } COMBINED for SPEED
+.EQU MCA_TYPE, 17 // }
+.EQU MCA_INST, 18
+.EQU MCA_PANNING, 19
+.EQU MCA_VOLUME, 20
+.EQU MCA_SAMPLE, 21
+.EQU MCA_PARENT, 22 // } COMBINED
+.EQU MCA_FLAGS, 23 // }
+.EQU MCA_ENVN_VOL, 24
+.EQU MCA_ENVN_PAN, 25
+.EQU MCA_ENVN_PIC, 26
+.EQU MCA_SFX, 27 @ can store this anywhere
+.EQU MCA_SIZE, 28
+
+@ Active Channel Flags
+@ --------------------
+
+.EQU MCAF_KEYON ,1 @ key is on... LOCKED
+.EQU MCAF_FADE ,2 @ note-fade is activated
+.EQU MCAF_START ,4 @ [re]start sample
+.EQU MCAF_UPDATED ,8 @ already updated by pchannel routine
+.EQU MCAF_ENVEND ,16 @ end of envelope
+.EQU MCAF_VOLENV ,32 @ volume envelope enabled
+.EQU MCAF_SUB ,64 @ sublayer.................locked..
+.EQU MCAF_EFFECT ,128 @ subsublayer.............................LOCKED (mpEffect)
+
+@ Active Channel Types
+@ --------------------
+
+.EQU ACHN_DISABLED ,0 @ LOCKED (multiple routines)
+.EQU ACHN_RESERVED ,1 @ (can't be used [alloc channel])
+.EQU ACHN_BACKGROUND ,2 @ LOCKED (alloc channel)
+.EQU ACHN_FOREGROUND ,3
+.EQU ACHN_CUSTOM ,4
+
+@ Module Channel Flags
+@ --------------------
+
+.equ MF_START ,1
+.equ MF_DVOL ,2
+.equ MF_HASVCMD ,4
+.equ MF_HASFX ,8
+.equ MF_NEWINSTR ,16
+
+.EQU MF_NOTEOFF ,64 @ LOCKED
+.EQU MF_NOTECUT ,128 @ LOCKED
+
+@.equ MF_NEWINSTR ,1 @ new instrument
+@.EQU MF_DVOL ,2
+@.EQU MF_START ,4
+@.EQU MF_HASFX ,8
+@.EQU MF_HASVCMD ,16
+@.EQU MF_NOTEOFF ,64 @ LOCKED
+@.EQU MF_NOTECUT ,128 @ LOCKED
+
+@ Other Definitions
+@ -----------------
+
+.equ IT_NNA_CUT ,0 @ New note actions
+.equ IT_NNA_CONT ,1
+.equ IT_NNA_OFF ,2
+.equ IT_NNA_FADE ,3
+
+.equ IT_DCA_CUT ,0 @ Duplicate check actions
+.equ IT_DCA_OFF ,1
+.equ IT_DCA_FADE ,2
+
+@ Misc Reference
+@ --------------
+
+@ BFLAGS:
+@ /////ctv nnppttvv
+@ nn...............new note action
+@ pp...............panbrello waveform
+@ tt...............tremolo waveform
+@ vv...............vibrato waveform
+@ dd...............duplicate check type
+@ v................volume envelope enabled
+@ t................tremor variable...
+@ c................cut channel volume
+@ //////...........reserved
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#ifndef MP_MIXER_GBA_INC
+#define MP_MIXER_GBA_INC
+
+@ definitions
+
+.equ MP_SAMPFRAC ,12
+
+.equ MIXER_CHN_SRC ,0
+.equ MIXER_CHN_READ ,4
+.equ MIXER_CHN_VOL ,8
+.equ MIXER_CHN_PAN ,9
+// 10
+// 11
+.equ MIXER_CHN_FREQ ,12
+.equ MIXER_CHN_SIZE ,16
+
+//////////////////////////////////.equ MIXER_CHN_LOOP ,8
+/////////////////////////////////////.equ MIXER_CHN_LEN ,16
+
+#endif
--- /dev/null
+/****************************************************************************
+ * __ *
+ * ____ ___ ____ __ ______ ___ ____ ____/ / *
+ * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
+ * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
+ * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
+ * *
+ * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted, provided that the above *
+ * copyright notice and this permission notice appear in all copies. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+.equ SWI_DIVIDE, 0x06
--- /dev/null
+ .text
+ .thumb
+
+ .globl fillblock_16byte
+fillblock_16byte:
+ push {r4-r6}
+ mov r3, r1
+ mov r4, r1
+ mov r5, r1
+ mov r6, r1
+0: stmia r0!, {r3, r4, r5, r6}
+ sub r2, #1
+ bne 0b
+ pop {r4-r6}
+ bx lr
+
+ .globl get_pc
+get_pc:
+ mov r0, lr
+ bx lr
+
+ .globl get_sp
+get_sp:
+ mov r0, sp
+ bx lr
+
+ .arm
+ .extern panic_regs
+ .globl get_panic_regs
+ .type get_panic_regs, %function
+get_panic_regs:
+ stmfd sp!, {sp, lr}
+ ldr lr, =panic_regs
+ stm lr, {r0-r15}
+ ldmfd sp!, {r0, lr}
+ ldr r0, =panic_regs + 13 * 4
+ stm r0, {sp, lr}
+ bx lr
--- /dev/null
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include "gbaregs.h"
+#include "intr.h"
+#include "debug.h"
+#include "util.h"
+
+uint16_t vblperf_color[] = {
+ /* grn blue cyan yellow orng red purple d.green purple ... */
+ /* 60 30 20 15 12 10 8.5 7.5 ... */
+ 0x3e0, 0xf863, 0xffc0, 0x3ff, 0x1ff, 0x001f, 0xf81f, 0x1e0, 0xf81f, 0xf81f, 0xf81f
+};
+
+void vblperf_setcolor(int palidx)
+{
+ vblperf_palptr = (uint16_t*)CRAM_BG_ADDR + palidx;
+}
+
+
+uint32_t panic_regs[16];
+void get_panic_regs(void);
+
+void panic(void *pc, const char *fmt, ...)
+{
+ int y;
+ va_list ap;
+ uint32_t *reg;
+
+ get_panic_regs();
+
+ intr_disable();
+ REG_DISPCNT = 4 | DISPCNT_BG2;
+
+ set_bg_color(0, 31, 0, 0);
+ set_bg_color(0xff, 31, 31, 31);
+
+ fillblock_16byte((void*)VRAM_LFB_FB0_ADDR, 0, 240 * 160 / 16);
+
+ fillblock_16byte((unsigned char*)VRAM_LFB_FB0_ADDR + 240 * 3, 0xffffffff, 240 / 16);
+ dbg_drawstr(44, 0, " Panic at %p ", pc);
+
+ va_start(ap, fmt);
+ y = dbg_vdrawstr(0, 12, fmt, ap) + 8;
+ va_end(ap);
+
+ fillblock_16byte((unsigned char*)VRAM_LFB_FB0_ADDR + 240 * (y + 4), 0xffffffff, 240 / 16);
+ y += 8;
+
+ reg = panic_regs;
+ y = dbg_drawstr(0, y, " r0 %08x r1 %08x\n r2 %08x r3 %08x\n r4 %08x r5 %08x\n r6 %08x r7 %08x\n",
+ reg[0], reg[1], reg[2], reg[3], reg[4], reg[5], reg[6], reg[7]);
+ 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(;;);
+}
+
+void dbg_drawglyph(int x, int y, int c)
+{
+ int i;
+ uint16_t pp;
+ unsigned char row;
+ uint16_t *ptr = (uint16_t*)VRAM_LFB_FB0_ADDR + (y << 7) - (y << 3) + (x >> 1);
+ unsigned char *fnt = font_8x8 + ((c & 0xff) << 3);
+
+ for(i=0; i<8; i++) {
+ row = *fnt++;
+ pp = row & 0x80 ? 0xff : 0;
+ *ptr++ = pp | (row & 0x40 ? 0xff00 : 0);
+ pp = row & 0x20 ? 0xff : 0;
+ *ptr++ = pp | (row & 0x10 ? 0xff00 : 0);
+ pp = row & 0x08 ? 0xff : 0;
+ *ptr++ = pp | (row & 0x04 ? 0xff00 : 0);
+ pp = row & 0x02 ? 0xff : 0;
+ *ptr++ = pp | (row & 0x01 ? 0xff00 : 0);
+ ptr += 120 - 4;
+ }
+}
+
+int dbg_vdrawstr(int x, int y, const char *fmt, va_list ap)
+{
+ int startx, c;
+ char buf[128];
+ char *ptr = buf;
+
+ vsnprintf(buf, sizeof buf, fmt, ap);
+
+ startx = x;
+ while(*ptr) {
+ if(y >= 160) break;
+
+ c = *ptr++;
+ switch(c) {
+ case '\n':
+ y += 8;
+ case '\r':
+ x = startx;
+ break;
+
+ default:
+ dbg_drawglyph(x, y, c);
+ x += 8;
+ if(x >= 240 - 8) {
+ while(*ptr && isspace(*ptr)) ptr++;
+ x = 0;
+ y += 8;
+ }
+ }
+ }
+
+ return y;
+}
+
+int dbg_drawstr(int x, int y, const char *fmt, ...)
+{
+ int res;
+ va_list ap;
+
+ va_start(ap, fmt);
+ res = dbg_vdrawstr(x, y, fmt, ap);
+ va_end(ap);
+ return res;
+}
+
+#ifdef EMUBUILD
+__attribute__((target("arm")))
+void emuprint(const char *fmt, ...)
+{
+ char buf[128];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof buf, fmt, ap);
+ va_end(ap);
+
+ asm volatile(
+ "mov r0, %0\n\t"
+ "swi 0xff0000\n\t" :
+ : "r" (buf)
+ : "r0"
+ );
+}
+#else
+void emuprint(const char *fmt, ...)
+{
+}
+#endif
--- /dev/null
+#ifndef DEBUG_H_
+#define DEBUG_H_
+
+#include <stdarg.h>
+#include "util.h"
+
+extern unsigned char font_8x8[];
+
+extern uint16_t vblperf_color[];
+uint16_t *vblperf_palptr;
+volatile int vblperf_count;
+
+void vblperf_setcolor(int palidx);
+
+#ifdef VBLBAR
+#define vblperf_begin() \
+ do { \
+ *vblperf_palptr = 0; \
+ vblperf_count = 0; \
+ } while(0)
+
+#define vblperf_end() \
+ do { \
+ *vblperf_palptr = vblperf_color[vblperf_count]; \
+ } while(0)
+#else
+#define vblperf_begin()
+#define vblperf_end()
+#endif
+
+void panic(void *pc, const char *fmt, ...) __attribute__((noreturn));
+
+void dbg_drawglyph(int x, int y, int c);
+int dbg_drawstr(int x, int y, const char *fmt, ...);
+int dbg_vdrawstr(int x, int y, const char *fmt, va_list ap);
+
+void emuprint(const char *fmt, ...);
+
+#endif /* DEBUG_H_ */
--- /dev/null
+#include "dma.h"
+
+/* DMA Options */
+#define DMA_ENABLE 0x80000000
+#define DMA_INT_ENABLE 0x40000000
+#define DMA_TIMING_IMMED 0x00000000
+#define DMA_TIMING_VBLANK 0x10000000
+#define DMA_TIMING_HBLANK 0x20000000
+#define DMA_TIMING_DISPSYNC 0x30000000
+#define DMA_16 0x00000000
+#define DMA_32 0x04000000
+#define DMA_REPEAT 0x02000000
+#define DMA_SRC_INC 0x00000000
+#define DMA_SRC_DEC 0x00800000
+#define DMA_SRC_FIX 0x01000000
+#define DMA_DST_INC 0x00000000
+#define DMA_DST_DEC 0x00200000
+#define DMA_DST_FIX1 0x00400000
+#define DMA_DST_RELOAD 0x00600000
+
+/* DMA Register Parts */
+#define DMA_SRC 0
+#define DMA_DST 1
+#define DMA_CTRL 2
+
+static volatile uint32_t *reg_dma[4] = {(void*)0x040000b0, (void*)0x040000bc, (void*)0x040000c8, (void*)0x040000d4 };
+
+/* --- perform a copy of words or halfwords using DMA --- */
+
+void dma_copy32(int channel, void *dst, void *src, int words, unsigned int flags)
+{
+ reg_dma[channel][DMA_SRC] = (uint32_t)src;
+ reg_dma[channel][DMA_DST] = (uint32_t)dst;
+ reg_dma[channel][DMA_CTRL] = words | flags | DMA_32 | DMA_ENABLE;
+}
+
+void dma_copy16(int channel, void *dst, void *src, int halfwords, unsigned int flags)
+{
+ reg_dma[channel][DMA_SRC] = (uint32_t)src;
+ reg_dma[channel][DMA_DST] = (uint32_t)dst;
+ reg_dma[channel][DMA_CTRL] = halfwords | flags | DMA_16 | DMA_ENABLE;
+}
+
+/* --- fill a buffer with an ammount of words and halfwords using DMA --- */
+
+static uint32_t fill[4];
+
+void dma_fill32(int channel, void *dst, uint32_t val, int words)
+{
+ fill[channel] = val;
+ reg_dma[channel][DMA_SRC] = (uint32_t)(fill + channel);
+ reg_dma[channel][DMA_DST] = (uint32_t)dst;
+ reg_dma[channel][DMA_CTRL] = words | DMA_SRC_FIX | DMA_TIMING_IMMED | DMA_32 | DMA_ENABLE;
+}
+
+void dma_fill16(int channel, void *dst, uint16_t val, int halfwords)
+{
+ fill[channel] = val;
+ reg_dma[channel][DMA_SRC] = (uint32_t)(fill + channel);
+ reg_dma[channel][DMA_DST] = (uint32_t)dst;
+ reg_dma[channel][DMA_CTRL] = halfwords | DMA_SRC_FIX | DMA_TIMING_IMMED | DMA_16 | DMA_ENABLE;
+}
--- /dev/null
+#ifndef DMA_H_
+#define DMA_H_
+
+#include <stdint.h>
+
+void dma_copy32(int channel, void *dst, void *src, int words, unsigned int flags);
+void dma_copy16(int channel, void *dst, void *src, int halfwords, unsigned int flags);
+
+void dma_fill32(int channel, void *dst, uint32_t val, int words);
+void dma_fill16(int channel, void *dst, uint16_t val, int halfwords);
+
+#endif /* DMA_H_ */
--- /dev/null
+/* Font data derived from Linux 2.6.7: drivers/video/console/font_8x8.c */
+
+unsigned char font_8x8[] = {
+
+ /* 0 0x00 '^@' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 1 0x01 '^A' */
+ 0x7e, /* 01111110 */
+ 0x81, /* 10000001 */
+ 0xa5, /* 10100101 */
+ 0x81, /* 10000001 */
+ 0xbd, /* 10111101 */
+ 0x99, /* 10011001 */
+ 0x81, /* 10000001 */
+ 0x7e, /* 01111110 */
+
+ /* 2 0x02 '^B' */
+ 0x7e, /* 01111110 */
+ 0xff, /* 11111111 */
+ 0xdb, /* 11011011 */
+ 0xff, /* 11111111 */
+ 0xc3, /* 11000011 */
+ 0xe7, /* 11100111 */
+ 0xff, /* 11111111 */
+ 0x7e, /* 01111110 */
+
+ /* 3 0x03 '^C' */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+
+ /* 4 0x04 '^D' */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+
+ /* 5 0x05 '^E' */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xd6, /* 11010110 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+
+ /* 6 0x06 '^F' */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+
+ /* 7 0x07 '^G' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 8 0x08 '^H' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xe7, /* 11100111 */
+ 0xc3, /* 11000011 */
+ 0xc3, /* 11000011 */
+ 0xe7, /* 11100111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+
+ /* 9 0x09 '^I' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x42, /* 01000010 */
+ 0x42, /* 01000010 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 10 0x0a '^J' */
+ 0xff, /* 11111111 */
+ 0xc3, /* 11000011 */
+ 0x99, /* 10011001 */
+ 0xbd, /* 10111101 */
+ 0xbd, /* 10111101 */
+ 0x99, /* 10011001 */
+ 0xc3, /* 11000011 */
+ 0xff, /* 11111111 */
+
+ /* 11 0x0b '^K' */
+ 0x0f, /* 00001111 */
+ 0x07, /* 00000111 */
+ 0x0f, /* 00001111 */
+ 0x7d, /* 01111101 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x78, /* 01111000 */
+
+ /* 12 0x0c '^L' */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+
+ /* 13 0x0d '^M' */
+ 0x3f, /* 00111111 */
+ 0x33, /* 00110011 */
+ 0x3f, /* 00111111 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x70, /* 01110000 */
+ 0xf0, /* 11110000 */
+ 0xe0, /* 11100000 */
+
+ /* 14 0x0e '^N' */
+ 0x7f, /* 01111111 */
+ 0x63, /* 01100011 */
+ 0x7f, /* 01111111 */
+ 0x63, /* 01100011 */
+ 0x63, /* 01100011 */
+ 0x67, /* 01100111 */
+ 0xe6, /* 11100110 */
+ 0xc0, /* 11000000 */
+
+ /* 15 0x0f '^O' */
+ 0x18, /* 00011000 */
+ 0xdb, /* 11011011 */
+ 0x3c, /* 00111100 */
+ 0xe7, /* 11100111 */
+ 0xe7, /* 11100111 */
+ 0x3c, /* 00111100 */
+ 0xdb, /* 11011011 */
+ 0x18, /* 00011000 */
+
+ /* 16 0x10 '^P' */
+ 0x80, /* 10000000 */
+ 0xe0, /* 11100000 */
+ 0xf8, /* 11111000 */
+ 0xfe, /* 11111110 */
+ 0xf8, /* 11111000 */
+ 0xe0, /* 11100000 */
+ 0x80, /* 10000000 */
+ 0x00, /* 00000000 */
+
+ /* 17 0x11 '^Q' */
+ 0x02, /* 00000010 */
+ 0x0e, /* 00001110 */
+ 0x3e, /* 00111110 */
+ 0xfe, /* 11111110 */
+ 0x3e, /* 00111110 */
+ 0x0e, /* 00001110 */
+ 0x02, /* 00000010 */
+ 0x00, /* 00000000 */
+
+ /* 18 0x12 '^R' */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+
+ /* 19 0x13 '^S' */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+
+ /* 20 0x14 '^T' */
+ 0x7f, /* 01111111 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0x7b, /* 01111011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x00, /* 00000000 */
+
+ /* 21 0x15 '^U' */
+ 0x3e, /* 00111110 */
+ 0x61, /* 01100001 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x86, /* 10000110 */
+ 0x7c, /* 01111100 */
+
+ /* 22 0x16 '^V' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+
+ /* 23 0x17 '^W' */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+
+ /* 24 0x18 '^X' */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+
+ /* 25 0x19 '^Y' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+
+ /* 26 0x1a '^Z' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0xfe, /* 11111110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 27 0x1b '^[' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xfe, /* 11111110 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 28 0x1c '^\' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 29 0x1d '^]' */
+ 0x00, /* 00000000 */
+ 0x24, /* 00100100 */
+ 0x66, /* 01100110 */
+ 0xff, /* 11111111 */
+ 0x66, /* 01100110 */
+ 0x24, /* 00100100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 30 0x1e '^^' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 31 0x1f '^_' */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 32 0x20 ' ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 33 0x21 '!' */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+
+ /* 34 0x22 '"' */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x24, /* 00100100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 35 0x23 '#' */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+
+ /* 36 0x24 '$' */
+ 0x18, /* 00011000 */
+ 0x3e, /* 00111110 */
+ 0x60, /* 01100000 */
+ 0x3c, /* 00111100 */
+ 0x06, /* 00000110 */
+ 0x7c, /* 01111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+
+ /* 37 0x25 '%' */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xcc, /* 11001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x66, /* 01100110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+
+ /* 38 0x26 '&' */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 39 0x27 ''' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 40 0x28 '(' */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x00, /* 00000000 */
+
+ /* 41 0x29 ')' */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+
+ /* 42 0x2a '*' */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0xff, /* 11111111 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 43 0x2b '+' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 44 0x2c ',' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+
+ /* 45 0x2d '-' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 46 0x2e '.' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+
+ /* 47 0x2f '/' */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0x80, /* 10000000 */
+ 0x00, /* 00000000 */
+
+ /* 48 0x30 '0' */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xd6, /* 11010110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+
+ /* 49 0x31 '1' */
+ 0x18, /* 00011000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+
+ /* 50 0x32 '2' */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0x06, /* 00000110 */
+ 0x1c, /* 00011100 */
+ 0x30, /* 00110000 */
+ 0x66, /* 01100110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+
+ /* 51 0x33 '3' */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0x06, /* 00000110 */
+ 0x3c, /* 00111100 */
+ 0x06, /* 00000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 52 0x34 '4' */
+ 0x1c, /* 00011100 */
+ 0x3c, /* 00111100 */
+ 0x6c, /* 01101100 */
+ 0xcc, /* 11001100 */
+ 0xfe, /* 11111110 */
+ 0x0c, /* 00001100 */
+ 0x1e, /* 00011110 */
+ 0x00, /* 00000000 */
+
+ /* 53 0x35 '5' */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xfc, /* 11111100 */
+ 0x06, /* 00000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 54 0x36 '6' */
+ 0x38, /* 00111000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0xfc, /* 11111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 55 0x37 '7' */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+
+ /* 56 0x38 '8' */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 57 0x39 '9' */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7e, /* 01111110 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+
+ /* 58 0x3a ':' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+
+ /* 59 0x3b ';' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+
+ /* 60 0x3c '<' */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x06, /* 00000110 */
+ 0x00, /* 00000000 */
+
+ /* 61 0x3d '=' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 62 0x3e '>' */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x00, /* 00000000 */
+
+ /* 63 0x3f '?' */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+
+ /* 64 0x40 '@' */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xde, /* 11011110 */
+ 0xde, /* 11011110 */
+ 0xde, /* 11011110 */
+ 0xc0, /* 11000000 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+
+ /* 65 0x41 'A' */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+
+ /* 66 0x42 'B' */
+ 0xfc, /* 11111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0xfc, /* 11111100 */
+ 0x00, /* 00000000 */
+
+ /* 67 0x43 'C' */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 68 0x44 'D' */
+ 0xf8, /* 11111000 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0xf8, /* 11111000 */
+ 0x00, /* 00000000 */
+
+ /* 69 0x45 'E' */
+ 0xfe, /* 11111110 */
+ 0x62, /* 01100010 */
+ 0x68, /* 01101000 */
+ 0x78, /* 01111000 */
+ 0x68, /* 01101000 */
+ 0x62, /* 01100010 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+
+ /* 70 0x46 'F' */
+ 0xfe, /* 11111110 */
+ 0x62, /* 01100010 */
+ 0x68, /* 01101000 */
+ 0x78, /* 01111000 */
+ 0x68, /* 01101000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+
+ /* 71 0x47 'G' */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xce, /* 11001110 */
+ 0x66, /* 01100110 */
+ 0x3a, /* 00111010 */
+ 0x00, /* 00000000 */
+
+ /* 72 0x48 'H' */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+
+ /* 73 0x49 'I' */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 74 0x4a 'J' */
+ 0x1e, /* 00011110 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+
+ /* 75 0x4b 'K' */
+ 0xe6, /* 11100110 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0x78, /* 01111000 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+
+ /* 76 0x4c 'L' */
+ 0xf0, /* 11110000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x62, /* 01100010 */
+ 0x66, /* 01100110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+
+ /* 77 0x4d 'M' */
+ 0xc6, /* 11000110 */
+ 0xee, /* 11101110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xd6, /* 11010110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+
+ /* 78 0x4e 'N' */
+ 0xc6, /* 11000110 */
+ 0xe6, /* 11100110 */
+ 0xf6, /* 11110110 */
+ 0xde, /* 11011110 */
+ 0xce, /* 11001110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+
+ /* 79 0x4f 'O' */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 80 0x50 'P' */
+ 0xfc, /* 11111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+
+ /* 81 0x51 'Q' */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xce, /* 11001110 */
+ 0x7c, /* 01111100 */
+ 0x0e, /* 00001110 */
+
+ /* 82 0x52 'R' */
+ 0xfc, /* 11111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+
+ /* 83 0x53 'S' */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 84 0x54 'T' */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x5a, /* 01011010 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 85 0x55 'U' */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 86 0x56 'V' */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+
+ /* 87 0x57 'W' */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+
+ /* 88 0x58 'X' */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+
+ /* 89 0x59 'Y' */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 90 0x5a 'Z' */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0x8c, /* 10001100 */
+ 0x18, /* 00011000 */
+ 0x32, /* 00110010 */
+ 0x66, /* 01100110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+
+ /* 91 0x5b '[' */
+ 0x3c, /* 00111100 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 92 0x5c '\' */
+ 0xc0, /* 11000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x06, /* 00000110 */
+ 0x02, /* 00000010 */
+ 0x00, /* 00000000 */
+
+ /* 93 0x5d ']' */
+ 0x3c, /* 00111100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 94 0x5e '^' */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 95 0x5f '_' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+
+ /* 96 0x60 '`' */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 97 0x61 'a' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 98 0x62 'b' */
+ 0xe0, /* 11100000 */
+ 0x60, /* 01100000 */
+ 0x7c, /* 01111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+
+ /* 99 0x63 'c' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 100 0x64 'd' */
+ 0x1c, /* 00011100 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 101 0x65 'e' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 102 0x66 'f' */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x60, /* 01100000 */
+ 0xf8, /* 11111000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+
+ /* 103 0x67 'g' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x7c, /* 01111100 */
+ 0x0c, /* 00001100 */
+ 0xf8, /* 11111000 */
+
+ /* 104 0x68 'h' */
+ 0xe0, /* 11100000 */
+ 0x60, /* 01100000 */
+ 0x6c, /* 01101100 */
+ 0x76, /* 01110110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+
+ /* 105 0x69 'i' */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 106 0x6a 'j' */
+ 0x06, /* 00000110 */
+ 0x00, /* 00000000 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+
+ /* 107 0x6b 'k' */
+ 0xe0, /* 11100000 */
+ 0x60, /* 01100000 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0x78, /* 01111000 */
+ 0x6c, /* 01101100 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+
+ /* 108 0x6c 'l' */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 109 0x6d 'm' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xec, /* 11101100 */
+ 0xfe, /* 11111110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0x00, /* 00000000 */
+
+ /* 110 0x6e 'n' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+
+ /* 111 0x6f 'o' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 112 0x70 'p' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+
+ /* 113 0x71 'q' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x7c, /* 01111100 */
+ 0x0c, /* 00001100 */
+ 0x1e, /* 00011110 */
+
+ /* 114 0x72 'r' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x76, /* 01110110 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+
+ /* 115 0x73 's' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0xc0, /* 11000000 */
+ 0x7c, /* 01111100 */
+ 0x06, /* 00000110 */
+ 0xfc, /* 11111100 */
+ 0x00, /* 00000000 */
+
+ /* 116 0x74 't' */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0xfc, /* 11111100 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x36, /* 00110110 */
+ 0x1c, /* 00011100 */
+ 0x00, /* 00000000 */
+
+ /* 117 0x75 'u' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 118 0x76 'v' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+
+ /* 119 0x77 'w' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+
+ /* 120 0x78 'x' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+
+ /* 121 0x79 'y' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7e, /* 01111110 */
+ 0x06, /* 00000110 */
+ 0xfc, /* 11111100 */
+
+ /* 122 0x7a 'z' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x4c, /* 01001100 */
+ 0x18, /* 00011000 */
+ 0x32, /* 00110010 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+
+ /* 123 0x7b '{' */
+ 0x0e, /* 00001110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x70, /* 01110000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x0e, /* 00001110 */
+ 0x00, /* 00000000 */
+
+ /* 124 0x7c '|' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+
+ /* 125 0x7d '}' */
+ 0x70, /* 01110000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x0e, /* 00001110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+
+ /* 126 0x7e '~' */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 127 0x7f '\7f' */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+
+ /* 128 0x80 '\80' */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x0c, /* 00001100 */
+ 0x78, /* 01111000 */
+
+ /* 129 0x81 '\81' */
+ 0xcc, /* 11001100 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 130 0x82 '\82' */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 131 0x83 '\83' */
+ 0x7c, /* 01111100 */
+ 0x82, /* 10000010 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 132 0x84 '\84' */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 133 0x85 '\85' */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 134 0x86 '\86' */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 135 0x87 '\87' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0x7e, /* 01111110 */
+ 0x0c, /* 00001100 */
+ 0x38, /* 00111000 */
+
+ /* 136 0x88 '\88' */
+ 0x7c, /* 01111100 */
+ 0x82, /* 10000010 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 137 0x89 '\89' */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 138 0x8a '\8a' */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 139 0x8b '\8b' */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 140 0x8c '\8c' */
+ 0x7c, /* 01111100 */
+ 0x82, /* 10000010 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 141 0x8d '\8d' */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 142 0x8e '\8e' */
+ 0xc6, /* 11000110 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+
+ /* 143 0x8f '\8f' */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+
+ /* 144 0x90 '\90' */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xf8, /* 11111000 */
+ 0xc0, /* 11000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+
+ /* 145 0x91 '\91' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0xd8, /* 11011000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+
+ /* 146 0x92 '\92' */
+ 0x3e, /* 00111110 */
+ 0x6c, /* 01101100 */
+ 0xcc, /* 11001100 */
+ 0xfe, /* 11111110 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xce, /* 11001110 */
+ 0x00, /* 00000000 */
+
+ /* 147 0x93 '\93' */
+ 0x7c, /* 01111100 */
+ 0x82, /* 10000010 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 148 0x94 '\94' */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 149 0x95 '\95' */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 150 0x96 '\96' */
+ 0x78, /* 01111000 */
+ 0x84, /* 10000100 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 151 0x97 '\97' */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 152 0x98 '\98' */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7e, /* 01111110 */
+ 0x06, /* 00000110 */
+ 0xfc, /* 11111100 */
+
+ /* 153 0x99 '\99' */
+ 0xc6, /* 11000110 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+
+ /* 154 0x9a '\9a' */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 155 0x9b '\9b' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 156 0x9c '\9c' */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x64, /* 01100100 */
+ 0xf0, /* 11110000 */
+ 0x60, /* 01100000 */
+ 0x66, /* 01100110 */
+ 0xfc, /* 11111100 */
+ 0x00, /* 00000000 */
+
+ /* 157 0x9d '\9d' */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 158 0x9e '\9e' */
+ 0xf8, /* 11111000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xfa, /* 11111010 */
+ 0xc6, /* 11000110 */
+ 0xcf, /* 11001111 */
+ 0xc6, /* 11000110 */
+ 0xc7, /* 11000111 */
+
+ /* 159 0x9f '\9f' */
+ 0x0e, /* 00001110 */
+ 0x1b, /* 00011011 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0xd8, /* 11011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+
+ /* 160 0xa0 ' ' */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 161 0xa1 '¡' */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 162 0xa2 '¢' */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+
+ /* 163 0xa3 '£' */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 164 0xa4 '¤' */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+
+ /* 165 0xa5 '¥' */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0xe6, /* 11100110 */
+ 0xf6, /* 11110110 */
+ 0xde, /* 11011110 */
+ 0xce, /* 11001110 */
+ 0x00, /* 00000000 */
+
+ /* 166 0xa6 '¦' */
+ 0x3c, /* 00111100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x3e, /* 00111110 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 167 0xa7 '§' */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 168 0xa8 '¨' */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x63, /* 01100011 */
+ 0x3e, /* 00111110 */
+ 0x00, /* 00000000 */
+
+ /* 169 0xa9 '©' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 170 0xaa 'ª' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 171 0xab '«' */
+ 0x63, /* 01100011 */
+ 0xe6, /* 11100110 */
+ 0x6c, /* 01101100 */
+ 0x7e, /* 01111110 */
+ 0x33, /* 00110011 */
+ 0x66, /* 01100110 */
+ 0xcc, /* 11001100 */
+ 0x0f, /* 00001111 */
+
+ /* 172 0xac '¬' */
+ 0x63, /* 01100011 */
+ 0xe6, /* 11100110 */
+ 0x6c, /* 01101100 */
+ 0x7a, /* 01111010 */
+ 0x36, /* 00110110 */
+ 0x6a, /* 01101010 */
+ 0xdf, /* 11011111 */
+ 0x06, /* 00000110 */
+
+ /* 173 0xad '' */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+
+ /* 174 0xae '®' */
+ 0x00, /* 00000000 */
+ 0x33, /* 00110011 */
+ 0x66, /* 01100110 */
+ 0xcc, /* 11001100 */
+ 0x66, /* 01100110 */
+ 0x33, /* 00110011 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 175 0xaf '¯' */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0x66, /* 01100110 */
+ 0x33, /* 00110011 */
+ 0x66, /* 01100110 */
+ 0xcc, /* 11001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 176 0xb0 '°' */
+ 0x22, /* 00100010 */
+ 0x88, /* 10001000 */
+ 0x22, /* 00100010 */
+ 0x88, /* 10001000 */
+ 0x22, /* 00100010 */
+ 0x88, /* 10001000 */
+ 0x22, /* 00100010 */
+ 0x88, /* 10001000 */
+
+ /* 177 0xb1 '±' */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+
+ /* 178 0xb2 '²' */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+
+ /* 179 0xb3 '³' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 180 0xb4 '´' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 181 0xb5 'µ' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 182 0xb6 '¶' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf6, /* 11110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 183 0xb7 '·' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 184 0xb8 '¸' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 185 0xb9 '¹' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf6, /* 11110110 */
+ 0x06, /* 00000110 */
+ 0xf6, /* 11110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 186 0xba 'º' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 187 0xbb '»' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x06, /* 00000110 */
+ 0xf6, /* 11110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 188 0xbc '¼' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf6, /* 11110110 */
+ 0x06, /* 00000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 189 0xbd '½' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 190 0xbe '¾' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 191 0xbf '¿' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 192 0xc0 'À' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 193 0xc1 'Á' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 194 0xc2 'Â' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 195 0xc3 'Ã' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 196 0xc4 'Ä' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 197 0xc5 'Å' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 198 0xc6 'Æ' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 199 0xc7 'Ç' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x37, /* 00110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 200 0xc8 'È' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x37, /* 00110111 */
+ 0x30, /* 00110000 */
+ 0x3f, /* 00111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 201 0xc9 'É' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3f, /* 00111111 */
+ 0x30, /* 00110000 */
+ 0x37, /* 00110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 202 0xca 'Ê' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf7, /* 11110111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 203 0xcb 'Ë' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xf7, /* 11110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 204 0xcc 'Ì' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x37, /* 00110111 */
+ 0x30, /* 00110000 */
+ 0x37, /* 00110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 205 0xcd 'Í' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 206 0xce 'Î' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf7, /* 11110111 */
+ 0x00, /* 00000000 */
+ 0xf7, /* 11110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 207 0xcf 'Ï' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 208 0xd0 'Ð' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 209 0xd1 'Ñ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 210 0xd2 'Ò' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 211 0xd3 'Ó' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x3f, /* 00111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 212 0xd4 'Ô' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 213 0xd5 'Õ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 214 0xd6 'Ö' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3f, /* 00111111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 215 0xd7 '×' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xff, /* 11111111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 216 0xd8 'Ø' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 217 0xd9 'Ù' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 218 0xda 'Ú' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 219 0xdb 'Û' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+
+ /* 220 0xdc 'Ü' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+
+ /* 221 0xdd 'Ý' */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+
+ /* 222 0xde 'Þ' */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+
+ /* 223 0xdf 'ß' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 224 0xe0 'à' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0xc8, /* 11001000 */
+ 0xdc, /* 11011100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+
+ /* 225 0xe1 'á' */
+ 0x78, /* 01111000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xd8, /* 11011000 */
+ 0xcc, /* 11001100 */
+ 0xc6, /* 11000110 */
+ 0xcc, /* 11001100 */
+ 0x00, /* 00000000 */
+
+ /* 226 0xe2 'â' */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+
+ /* 227 0xe3 'ã' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+
+ /* 228 0xe4 'ä' */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+
+ /* 229 0xe5 'å' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+
+ /* 230 0xe6 'æ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0xc0, /* 11000000 */
+
+ /* 231 0xe7 'ç' */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+
+ /* 232 0xe8 'è' */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+
+ /* 233 0xe9 'é' */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+
+ /* 234 0xea 'ê' */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0xee, /* 11101110 */
+ 0x00, /* 00000000 */
+
+ /* 235 0xeb 'ë' */
+ 0x0e, /* 00001110 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x3e, /* 00111110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 236 0xec 'ì' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 237 0xed 'í' */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x7e, /* 01111110 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0x7e, /* 01111110 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+
+ /* 238 0xee 'î' */
+ 0x1e, /* 00011110 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x7e, /* 01111110 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x1e, /* 00011110 */
+ 0x00, /* 00000000 */
+
+ /* 239 0xef 'ï' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+
+ /* 240 0xf0 'ð' */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 241 0xf1 'ñ' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+
+ /* 242 0xf2 'ò' */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+
+ /* 243 0xf3 'ó' */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+
+ /* 244 0xf4 'ô' */
+ 0x0e, /* 00001110 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 245 0xf5 'õ' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0x70, /* 01110000 */
+
+ /* 246 0xf6 'ö' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 247 0xf7 '÷' */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 248 0xf8 'ø' */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 249 0xf9 'ù' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 250 0xfa 'ú' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 251 0xfb 'û' */
+ 0x0f, /* 00001111 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0xec, /* 11101100 */
+ 0x6c, /* 01101100 */
+ 0x3c, /* 00111100 */
+ 0x1c, /* 00011100 */
+
+ /* 252 0xfc 'ü' */
+ 0x6c, /* 01101100 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 253 0xfd 'ý' */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 254 0xfe 'þ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 255 0xff 'ÿ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+};
--- /dev/null
+#ifndef GAME_H_
+#define GAME_H_
+
+void (*screen_vblank)(void);
+
+void menuscr(void);
+void gamescr(void);
+
+#endif /* GAME_H_ */
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include "gbaregs.h"
+#include "game.h"
+#include "dma.h"
+#include "util.h"
+#include "intr.h"
+#include "input.h"
+#include "sprite.h"
+#include "debug.h"
+
+static void draw(void);
+static void vblank(void);
+
+static int nframes, num_vbl, backbuf;
+static uint16_t *vram[] = { (uint16_t*)VRAM_LFB_FB0_ADDR, (uint16_t*)VRAM_LFB_FB1_ADDR };
+static uint16_t bnstate;
+
+
+void gamescr(void)
+{
+ int i;
+
+ REG_DISPCNT = 4 | DISPCNT_BG2 | DISPCNT_OBJ | DISPCNT_FB1;
+
+ vblperf_setcolor(0xff);//192);
+
+ fillblock_16byte(vram[0], 0xffffffff, 240 * 160 / 16);
+ fillblock_16byte(vram[1], 0xffffffff, 240 * 160 / 16);
+
+ mask(INTR_VBLANK);
+ screen_vblank = vblank;
+ unmask(INTR_VBLANK);
+
+ nframes = 0;
+ for(;;) {
+ backbuf = ++nframes & 1;
+
+ bnstate = ~REG_KEYINPUT;
+
+ draw();
+
+ vblperf_end();
+ wait_vblank();
+ present(backbuf);
+ vblperf_begin();
+ }
+}
+
+static void draw(void)
+{
+ int i, j;
+ uint16_t pix;
+ uint16_t *fb = vram[backbuf];
+
+ for(i=0; i<160; i++) {
+ for(j=0; j<240/2; j++) {
+ pix = ((i^j) << 1) & 0xff;
+ pix |= (i^j) << 9;
+ *fb++ = pix;
+ }
+ }
+}
+
+__attribute__((noinline, target("arm"), section(".iwram")))
+static void vblank(void)
+{
+ num_vbl++;
+}
--- /dev/null
+#ifndef GBAREGS_H_
+#define GBAREGS_H_
+
+#include <stdint.h>
+
+#define VRAM_START_ADDR 0x6000000
+#define VRAM_BG_ADDR VRAM_START_ADDR
+#define VRAM_OBJ_ADDR 0x6010000
+#define VRAM_LFB_OBJ_ADDR 0x6014000
+#define VRAM_LFB_FB0_ADDR VRAM_START_ADDR
+#define VRAM_LFB_FB1_ADDR 0x600a000
+
+/* address of character data block x (4 possible blocks, 16k each) */
+#define VRAM_CHR_BLOCK_ADDR(x) (VRAM_START_ADDR + ((x) << 14))
+/* address of screen data block x (32 possible blocks, 2k each) */
+#define VRAM_SCR_BLOCK_ADDR(x) (VRAM_START_ADDR + ((x) << 11))
+
+/* fields of a background tile in screen memory */
+#define BGTILE_HFLIP 0x0400
+#define BGTILE_VFLIP 0x0800
+#define BGTILE_PAL(x) ((uint16_t)(x) << 12)
+
+/* color palette ram addresses for backgrounds and sprites */
+#define CRAM_BG_ADDR 0x5000000
+#define CRAM_OBJ_ADDR 0x5000200
+
+/* OAM table */
+#define OAM_ADDR 0x7000000
+
+/* interrupt handler */
+#define INTR_VECTOR (*(volatile uint32_t*)0x3007ffc)
+
+/* battery backed RAM address */
+#define SRAM_ADDR 0xe000000
+
+/* I/O space */
+
+#define REG_BASE 0x4000000
+#define REG8(x) (*(volatile uint8_t*)(REG_BASE + (x)))
+#define REG16(x) (*(volatile uint16_t*)(REG_BASE + (x)))
+#define REG32(x) (*(volatile uint32_t*)(REG_BASE + (x)))
+
+/* ---- display registers ---- */
+#define REG_DISPCNT REG16(0x00)
+#define REG_GREENSWAP REG16(0x02)
+#define REG_DISPSTAT REG16(0x04)
+#define REG_VCOUNT REG16(0x06)
+#define REG_BG0CNT REG16(0x08)
+#define REG_BG1CNT REG16(0x0a)
+#define REG_BG2CNT REG16(0x0c)
+#define REG_BG3CNT REG16(0x0e)
+/* scrolling registers */
+#define REG_BG0HOFS REG16(0x10)
+#define REG_BG0VOFS REG16(0x12)
+#define REG_BG1HOFS REG16(0x14)
+#define REG_BG1VOFS REG16(0x16)
+#define REG_BG2HOFS REG16(0x18)
+#define REG_BG2VOFS REG16(0x1a)
+#define REG_BG3HOFS REG16(0x1c)
+#define REG_BG3VOFS REG16(0x1e)
+/* BG rotation and scaling registers */
+#define REG_BG2PA REG16(0x20)
+#define REG_BG2PB REG16(0x22)
+#define REG_BG2PC REG16(0x24)
+#define REG_BG2PD REG16(0x26)
+#define REG_BG2X REG32(0x28)
+#define REG_BG2Y REG32(0x2c)
+#define REG_BG3PA REG16(0x30)
+#define REG_BG3PB REG16(0x32)
+#define REG_BG3PC REG16(0x34)
+#define REG_BG3PD REG16(0x36)
+#define REG_BG3X REG32(0x38)
+#define REG_BG3Y REG32(0x3c)
+/* window registers */
+#define REG_WIN0H REG16(0x40)
+#define REG_WIN1H REG16(0x42)
+#define REG_WIN0V REG16(0x44)
+#define REG_WIN1V REG16(0x46)
+#define REG_WININ REG16(0x48)
+#define REG_WINOUT REG16(0x4a)
+
+#define REG_MOSAIC REG16(0x4c)
+/* color effects */
+#define REG_BLDCNT REG16(0x50)
+#define REG_BLDALPHA REG16(0x52)
+#define REG_BLDY REG16(0x54)
+
+/* ---- sound registers ---- */
+#define REG_SOUND1CNT_L REG16(0x60)
+#define REG_SOUND1CNT_H REG16(0x62)
+#define REG_SOUND1CNT_X REG16(0x64)
+#define REG_SOUND2CNT_L REG16(0x68)
+#define REG_SOUND2CNT_H REG16(0x6c)
+#define REG_SOUND3CNT_L REG16(0x70)
+#define REG_SOUND3CNT_H REG16(0x72)
+#define REG_SOUND3CNT_X REG16(0x74)
+#define REG_SOUND4CNT_L REG16(0x78)
+#define REG_SOUND4CNT_H REG16(0x7c)
+#define REG_SOUNDCNT_L REG16(0x80)
+#define REG_SOUNDCNT_H REG16(0x82)
+#define REG_SOUNDCNT_X REG16(0x84)
+#define REG_SOUNDBIAS REG16(0x88)
+#define WAVE_RAM_PTR ((unsigned char*)(REG_BASE + 0x90))
+#define REG_FIFO_A REG32(0xa0)
+#define REG_FIFO_B REG32(0xa4)
+#define FIFO_A_PTR ((unsigned char*)(REG_BASE + 0xa0))
+#define FIFO_B_PTR ((unsigned char*)(REG_BASE + 0xa4))
+
+/* ---- DMA registers ---- */
+#define REG_DMA0SAD REG32(0xb0)
+#define REG_DMA0DAD REG32(0xb4)
+#define REG_DMA0CNT REG32(0xb8)
+#define REG_DMA0CNT_L REG16(0xb8)
+#define REG_DMA0CNT_H REG16(0xba)
+#define REG_DMA1SAD REG32(0xbc)
+#define REG_DMA1DAD REG32(0xc0)
+#define REG_DMA1CNT REG32(0xc4)
+#define REG_DMA1CNT_L REG16(0xc4)
+#define REG_DMA1CNT_H REG16(0xc6)
+#define REG_DMA2SAD REG32(0xc8)
+#define REG_DMA2DAD REG32(0xcc)
+#define REG_DMA2CNT REG32(0xd0)
+#define REG_DMA2CNT_L REG16(0xd0)
+#define REG_DMA2CNT_H REG16(0xd2)
+#define REG_DMA3SAD REG32(0xd4)
+#define REG_DMA3DAD REG32(0xd8)
+#define REG_DMA3CNT REG32(0xdc)
+#define REG_DMA3CNT_L REG16(0xdc)
+#define REG_DMA3CNT_H REG16(0xde)
+
+/* ---- timer registers ---- */
+#define REG_TM0CNT_L REG16(0x100)
+#define REG_TM0CNT_H REG16(0x102)
+#define REG_TM1CNT_L REG16(0x104)
+#define REG_TM1CNT_H REG16(0x106)
+#define REG_TM2CNT_L REG16(0x108)
+#define REG_TM2CNT_H REG16(0x10a)
+#define REG_TM3CNT_L REG16(0x10c)
+#define REG_TM3CNT_H REG16(0x10e)
+
+#define REG_TMCNT_L(x) REG16(0x100 + ((x) << 2))
+#define REG_TMCNT_H(x) REG16(0x102 + ((x) << 2))
+
+/* ---- communication registers (serial/joybus/gpio) ---- */
+#define REG_SIODATA32 REG32(0x120)
+#define REG_SIOMULTI0 REG16(0x120)
+#define REG_SIOMULTI1 REG16(0x122)
+#define REG_SIOMULTI2 REG16(0x124)
+#define REG_SIOMULTI3 REG16(0x126)
+#define REG_SIOCNT REG16(0x128)
+#define REG_SIOMLT_SEND REG16(0x12a)
+#define REG_SIODATA8 REG16(0x12a)
+#define REG_RCNT REG16(0x134)
+#define REG_JOYCNT REG16(0x140)
+#define REG_JOY_RECV REG32(0x150)
+#define REG_JOY_TRANS REG32(0x154)
+#define REG_JOYSTAT REG16(0x158)
+
+/* ---- keypad registers ---- */
+#define REG_KEYINPUT REG16(0x130)
+#define REG_KEYCNT REG16(0x132)
+
+/* ---- interrupts ---- */
+#define REG_IE REG16(0x200)
+#define REG_IF REG16(0x202)
+#define REG_WAITCNT REG16(0x204)
+#define REG_IME REG16(0x208)
+
+#define REG_POSTFLG REG8(0x300)
+#define REG_HALTCNT REG8(0x301)
+#define REG_INTMEMCNT REG32(0x800)
+
+/* REG_DISPSTAT bits */
+#define DISPSTAT_VBLANK 0x01
+#define DISPSTAT_HBLANK 0x02
+#define DISPSTAT_VMATCH 0x04
+#define DISPSTAT_IEN_VBLANK 0x08
+#define DISPSTAT_IEN_HBLANK 0x10
+#define DISPSTAT_IEN_VMATCH 0x20
+#define DISPSTAT_VCOUNT(x) ((uint16_t)(x) << 8)
+
+/* REG_DISPCNT bits */
+#define DISPCNT_MODE(x) (x)
+#define DISPCNT_FB1 0x0010
+#define DISPCNT_HBLANK_OBJPROC 0x0020
+#define DISPCNT_OBJMAP_1D 0x0040
+#define DISPCNT_FORCE_BLANK 0x0080
+#define DISPCNT_BG0 0x0100
+#define DISPCNT_BG1 0x0200
+#define DISPCNT_BG2 0x0400
+#define DISPCNT_BG3 0x0800
+#define DISPCNT_OBJ 0x1000
+#define DISPCNT_WIN0 0x2000
+#define DISPCNT_WIN1 0x4000
+#define DISPCNT_WINOBJ 0x8000
+
+/* REG_BGXCNT bits */
+#define BGCNT_PRIO(x) ((uint16_t)(x))
+#define BGCNT_CHR_BASE(x) ((uint16_t)(x) << 2)
+#define BGCNT_MOSAIC 0x0040
+#define BGCNT_256COL 0x0080
+#define BGCNT_SCR_BASE(x) ((uint16_t)(x) << 8)
+#define BGCNT_WRAP 0x2000
+
+#define BGCNT_SZ(x) ((uint16_t)(x) << 14)
+#define BGCNT_SZ_TX_256X256 BGCNT_SZ(0)
+#define BGCNT_SZ_RS_128X128 BGCNT_SZ(0)
+#define BGCNT_SZ_TX_512X256 BGCNT_SZ(1)
+#define BGCNT_SZ_RS_256X256 BGCNT_SZ(1)
+#define BGCNT_SZ_TX_256X512 BGCNT_SZ(2)
+#define BGCNT_SZ_RS_512X512 BGCNT_SZ(2)
+#define BGCNT_SZ_TX_512X512 BGCNT_SZ(3)
+#define BGCNT_SZ_RS_1024X1024 BGCNT_SZ(3)
+
+/* REG_BLDCNT bits */
+#define BLDCNT_A_BG0 0x0001
+#define BLDCNT_A_BG1 0x0002
+#define BLDCNT_A_BG2 0x0004
+#define BLDCNT_A_BG3 0x0008
+#define BLDCNT_A_OBJ 0x0010
+#define BLDCNT_A_BACKDROP 0x0020
+#define BLDCNT_B_BG0 0x0100
+#define BLDCNT_B_BG1 0x0200
+#define BLDCNT_B_BG2 0x0400
+#define BLDCNT_B_BG3 0x0800
+#define BLDCNT_B_OBJ 0x1000
+#define BLDCNT_B_BACKDROP 0x2000
+
+#define BLDCNT_ALPHA 0x0040
+#define BLDCNT_BRIGHTEN 0x0080
+#define BLDCNT_DARKEN 0x00c0
+
+/* REG_IF bits */
+#define IF_VBLANK 0x0001
+#define IF_HBLANK 0x0002
+#define IF_VMATCH 0x0004
+#define IF_TIMER0 0x0008
+#define IF_TIMER1 0x0010
+#define IF_TIMER2 0x0020
+#define IF_TIMER3 0x0040
+#define IF_COMM 0x0080
+#define IF_DMA0 0x0100
+#define IF_DMA1 0x0200
+#define IF_DMA2 0x0400
+#define IF_DMA3 0x0800
+#define IF_KEY 0x1000
+#define IF_GPAK 0x2000
+
+/* REG_TMXCNT bits */
+#define TMCNT_PRESCL_CLK1 0
+#define TMCNT_PRESCL_CLK64 1
+#define TMCNT_PRESCL_CLK256 2
+#define TMCNT_PRESCL_CLK1024 3
+
+#define TMCNT_CASCADE 0x04
+#define TMCNT_IE 0x40
+#define TMCNT_EN 0x80
+
+/* REG_KEY* bits */
+#define KEY_A 0x0001
+#define KEY_B 0x0002
+#define KEY_SELECT 0x0004
+#define KEY_START 0x0008
+#define KEY_RIGHT 0x0010
+#define KEY_LEFT 0x0020
+#define KEY_UP 0x0040
+#define KEY_DOWN 0x0080
+#define KEY_RT 0x0100
+#define KEY_LT 0x0200
+
+#define KEYCNT_IE 0x4000
+#define KEYCNT_IAND 0x8000
+
+/* REG_SOUNDCNT_L bits */
+#define SCNT_SS_LVOL(x) ((x) & 7)
+#define SCNT_SS_RVOL(x) (((x) & 7) << 4)
+#define SCNT_SS_VOL(x) (SCNT_SS_LVOL(x) | SCNT_SS_RVOL(x))
+#define SCNT_SS1_EN_R 0x0100
+#define SCNT_SS2_EN_R 0x0200
+#define SCNT_SS3_EN_R 0x0400
+#define SCNT_SS4_EN_R 0x0800
+#define SCNT_SS_EN_R(x) (SCNT_SS1_EN_R << (x))
+#define SCNT_SS1_EN_L 0x1000
+#define SCNT_SS2_EN_L 0x2000
+#define SCNT_SS3_EN_L 0x4000
+#define SCNT_SS4_EN_L 0x8000
+#define SCNT_SS_EN_L(x) (SCNT_SS1_EN_L << (x))
+#define SCNT_SS1_EN (SCNT_SS1_EN_R | SCNT_SS1_EN_L)
+#define SCNT_SS2_EN (SCNT_SS2_EN_R | SCNT_SS2_EN_L)
+#define SCNT_SS3_EN (SCNT_SS3_EN_R | SCNT_SS3_EN_L)
+#define SCNT_SS4_EN (SCNT_SS4_EN_R | SCNT_SS4_EN_L)
+#define SCNT_SS_EN(x) (SCNT_SS_EN_L(x) | SCNT_SS_EN_R(x))
+
+#define SCNT_SS1 0
+#define SCNT_SS2 1
+#define SCNT_SS3 2
+#define SCNT_SS4 3
+
+/* REG_SOUNDCNT_X bits */
+#define SCNT_MASTER_EN 0x0080
+
+/* REG_SOUNDCNT_H bits */
+#define SCNT_SS_VOL_QRT 0x0000
+#define SCNT_SS_VOL_HALF 0x0001
+#define SCNT_SS_VOL_FULL 0x0002
+#define SCNT_DSA_VOL_HALF 0
+#define SCNT_DSA_VOL_FULL 0x0004
+#define SCNT_DSB_VOL_HALF 0
+#define SCNT_DSB_VOL_FULL 0x0008
+#define SCNT_DSA_EN_R 0x0100
+#define SCNT_DSA_EN_L 0x0200
+#define SCNT_DSA_TIMER0 0
+#define SCNT_DSA_TIMER1 0x0400
+#define SCNT_DSA_CLRFIFO 0x0800
+#define SCNT_DSB_EN_R 0x1000
+#define SCNT_DSB_EN_L 0x2000
+#define SCNT_DSB_TIMER0 0
+#define SCNT_DSB_TIMER1 0x4000
+#define SCNT_DSB_CLRFIFO 0x8000
+
+/* REG_DMAxCNT_H bits */
+#define DMACNTH_DST_INC 0
+#define DMACNTH_DST_DEC 0x0020
+#define DMACNTH_DST_FIXED 0x0040
+#define DMACNTH_INC_RELOAD 0x0060
+#define DMACNTH_SRC_INC 0
+#define DMACNTH_SRC_DEC 0x0080
+#define DMACNTH_SRC_FIXED 0x0100
+#define DMACNTH_REPEAT 0x0200
+#define DMACNTH_16BIT 0
+#define DMACNTH_32BIT 0x0400
+#define DMACNTH_VBLANK 0x1000
+#define DMACNTH_HBLANK 0x2000
+#define DMACNTH_SOUND 0x3000
+#define DMACNTH_IEN 0x4000
+#define DMACNTH_EN 0x8000
+
+#define DMACNT_DST_INC 0
+#define DMACNT_DST_DEC 0x00200000
+#define DMACNT_DST_FIXED 0x00400000
+#define DMACNT_INC_RELOAD 0x00600000
+#define DMACNT_SRC_INC 0
+#define DMACNT_SRC_DEC 0x00800000
+#define DMACNT_SRC_FIXED 0x01000000
+#define DMACNT_REPEAT 0x02000000
+#define DMACNT_16BIT 0
+#define DMACNT_32BIT 0x04000000
+#define DMACNT_VBLANK 0x10000000
+#define DMACNT_HBLANK 0x20000000
+#define DMACNT_SOUND 0x30000000
+#define DMACNT_IEN 0x40000000
+#define DMACNT_EN 0x80000000
+
+/* REG_WAITCNT bits */
+#define WAITCNT_ROM_4_2 0x0000
+#define WAITCNT_ROM_3_2 0x0004
+#define WAITCNT_ROM_2_2 0x0008
+#define WAITCNT_ROM_8_2 0x000c
+#define WAITCNT_ROM_4_1 0x0010
+#define WAITCNT_ROM_3_1 0x0014
+#define WAITCNT_ROM_2_1 0x0018
+#define WAITCNT_ROM_8_1 0x001c
+#define WAITCNT_PREFETCH 0x4000
+
+#endif /* GBAREGS_H_ */
--- /dev/null
+#include "input.h"
+#include "gbaregs.h"
+#include "intr.h"
+
+static void keyintr(void);
+
+static uint16_t bnstate;
+
+void select_input(uint16_t bmask)
+{
+ bnstate = 0;
+
+ mask(INTR_KEY);
+ if(bmask) {
+ REG_KEYCNT = bmask | KEYCNT_IE;
+ interrupt(INTR_KEY, keyintr);
+ unmask(INTR_KEY);
+ } else {
+ REG_KEYCNT = 0;
+ interrupt(INTR_KEY, 0);
+ }
+}
+
+uint16_t get_input(void)
+{
+ uint16_t s;
+
+ mask(INTR_KEY);
+ s = bnstate;
+ bnstate = 0;
+ unmask(INTR_KEY);
+
+ return s;
+}
+
+static void keyintr(void)
+{
+ bnstate |= ~REG_KEYINPUT;
+}
--- /dev/null
+#ifndef INPUT_H_
+#define INPUT_H_
+
+#include <stdint.h>
+
+enum {
+ BN_A = 0x0001,
+ BN_B = 0x0002,
+ BN_SELECT = 0x0004,
+ BN_START = 0x0008,
+ BN_RIGHT = 0x0010,
+ BN_LEFT = 0x0020,
+ BN_UP = 0x0040,
+ BN_DOWN = 0x0080,
+ BN_RT = 0x0100,
+ BN_LT = 0x0200
+};
+
+#define BN_DPAD (BN_RIGHT | BN_LEFT | BN_UP | BN_DOWN)
+
+void select_input(uint16_t bmask);
+uint16_t get_input(void);
+
+#endif /* INPUT_H_ */
--- /dev/null
+#include "intr.h"
+
+#define MAX_INTR 14
+static void (*intr_table[MAX_INTR])(void);
+
+__attribute__ ((target("arm"), section(".iwram")))
+static void intr_handler(void)
+{
+ int i;
+ uint16_t iflags;
+
+ iflags = REG_IF;
+
+ for(i=0; i<MAX_INTR; i++) {
+ if((iflags & (1 << i)) && intr_table[i]) {
+ intr_table[i]();
+ }
+ }
+
+ REG_IF = iflags; /* ack intr */
+}
+
+void intr_init(void)
+{
+ INTR_VECTOR = (uint32_t)intr_handler;
+}
+
+void interrupt(int intr, void (*handler)(void))
+{
+ intr_table[intr] = handler;
+}
--- /dev/null
+#ifndef INTR_H_
+#define INTR_H_
+
+#include "gbaregs.h"
+
+/* interrupts */
+enum {
+ INTR_VBLANK,
+ INTR_HBLANK,
+ INTR_VCOUNT,
+ INTR_TIMER0,
+ INTR_TIMER1,
+ INTR_TIMER2,
+ INTR_TIMER3,
+ INTR_COMM,
+ INTR_DMA0,
+ INTR_DMA1,
+ INTR_DMA2,
+ INTR_DMA3,
+ INTR_KEY,
+ INTR_GPAK
+};
+
+void intr_init(void);
+
+/* set/clear interrupts */
+#define intr_enable() \
+ do { REG_IME |= 0x0001; } while(0)
+#define intr_disable() \
+ do { REG_IME &= 0xfffe; } while(0)
+
+/* set an interrupt handler */
+void interrupt(int intr, void (*handler)(void));
+
+/* mask/unmask an interrupt */
+#define mask(intr) do {REG_IE &= ~(1 << (intr));} while(0)
+#define unmask(intr) do {REG_IE |= 1 << (intr);} while(0)
+
+#endif /* INTR_H_ */
--- /dev/null
+#include <math.h>
+#include "gbaregs.h"
+#include "intr.h"
+#include "debug.h"
+#include "game.h"
+#include "maxmod.h"
+
+static void vblank(void);
+static void nopfunc(void);
+
+int main(void)
+{
+ int i;
+ volatile uint16_t *cptr;
+
+ intr_init();
+
+ REG_WAITCNT = WAITCNT_PREFETCH | WAITCNT_ROM_2_1;
+
+ cptr = (uint16_t*)CRAM_BG_ADDR;
+ for(i=0; i<256; i++) {
+ int c = i >> 3;
+ *cptr++ = c | ((c >> 1) << 10);
+ }
+
+#ifndef NOSOUND
+ mmInitDefault(sound_data, 8);
+ mmStart(MOD_POPCORN, MM_PLAY_LOOP);
+#endif
+
+ screen_vblank = nopfunc;
+
+ 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++;
+
+ screen_vblank();
+
+#ifndef NOSOUND
+ mmVBlank();
+ mmFrame();
+#endif
+}
+
+static void nopfunc(void)
+{
+}
--- /dev/null
+#include "gbaregs.h"
+
+void menuscr(void)
+{
+}
--- /dev/null
+/*
+blender for the Gameboy Advance
+Copyright (C) 2021 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#include <string.h>
+#include "polyfill.h"
+#include "debug.h"
+
+static unsigned char *fb;
+static int fbwidth, fbheight;
+static short scantab[2][160] __attribute__((section(".iwram")));
+
+void polyfill_framebuffer(unsigned char *ptr, int w, int h)
+{
+ fb = ptr;
+ fbwidth = w;
+ fbheight = h;
+}
+
+#define VNEXT(p) (((p) == vlast) ? varr : (p) + 1)
+#define VPREV(p) ((p) == varr ? vlast : (p) - 1)
+#define VSUCC(p, side) ((side) == 0 ? VNEXT(p) : VPREV(p))
+
+void polyfill_flat(struct pvertex *varr, int vnum, unsigned char col)
+{
+ int i, line, top, bot;
+ struct pvertex *vlast, *v, *vn;
+ int32_t x, y0, y1, dx, dy, slope, fx, fy;
+ short *tab, start, len;
+ unsigned char *fbptr;
+ uint16_t *pptr, pcol = ((uint16_t)col << 8) | (uint16_t)col;
+
+ vlast = varr + vnum - 1;
+ top = fbheight;
+ bot = 0;
+
+ for(i=0; i<vnum; i++) {
+ v = varr + i;
+ vn = VNEXT(v);
+
+ if(vn->y == v->y) continue;
+
+ if(vn->y > v->y) {
+ tab = scantab[0];
+ } else {
+ tab = scantab[1];
+ v = vn;
+ vn = varr + i;
+ }
+
+ dx = vn->x - v->x;
+ dy = vn->y - v->y;
+ slope = (dx << 8) / dy;
+
+ y0 = (v->y + 0x100) & 0xffffff00; /* start from the next scanline */
+ fy = y0 - v->y; /* fractional part before the next scanline */
+ fx = (fy * slope) >> 8; /* X adjust for the step to the next scanline */
+ x = v->x + fx; /* adjust X */
+ y1 = vn->y & 0xffffff00; /* last scanline of the edge <= vn->y */
+
+ line = y0 >> 8;
+ if(line < top) top = line;
+ if((y1 >> 8) > bot) bot = y1 >> 8;
+
+ if(line > 0) tab += line;
+
+ while(line <= (y1 >> 8) && line < fbheight) {
+ if(line >= 0) {
+ int val = x < 0 ? 0 : x >> 8;
+ *tab++ = val < fbwidth ? val : fbwidth - 1;
+ }
+ x += slope;
+ line++;
+ }
+ }
+
+ fbptr = fb + top * fbwidth;
+ for(i=top; i<=bot; i++) {
+ start = scantab[0][i];
+ len = scantab[1][i] - start;
+
+ if(len > 0) {
+ if(start & 1) {
+ pptr = (uint16_t*)(fbptr + (start & 0xfffe));
+ *pptr = (*pptr & 0xff) | ((uint16_t)col << 8);
+ len--;
+ start++;
+ }
+ pptr = (uint16_t*)(fbptr + start);
+ while(len > 1) {
+ *pptr++ = pcol;
+ len -= 2;
+ }
+ if(len) {
+ *pptr = (*pptr & 0xff00) | col;
+ }
+ }
+ fbptr += fbwidth;
+ }
+}
+
+
+/* ----- line drawing and clipping ------ */
+enum {
+ IN = 0,
+ LEFT = 1,
+ RIGHT = 2,
+ TOP = 4,
+ BOTTOM = 8
+};
+
+static int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax)
+{
+ int code = 0;
+
+ if(x < xmin) {
+ code |= LEFT;
+ } else if(x > xmax) {
+ code |= RIGHT;
+ }
+ if(y < ymin) {
+ code |= TOP;
+ } else if(y > ymax) {
+ code |= BOTTOM;
+ }
+ return code;
+}
+
+#define FIXMUL(a, b) (((a) * (b)) >> 8)
+#define FIXDIV(a, b) (((a) << 8) / (b))
+
+#define LERP(a, b, t) ((a) + FIXMUL((b) - (a), (t)))
+
+int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax)
+{
+ int oc_out;
+
+ int oc0 = outcode(*x0, *y0, xmin, ymin, xmax, ymax);
+ int oc1 = outcode(*x1, *y1, xmin, ymin, xmax, ymax);
+
+ long fx0, fy0, fx1, fy1, fxmin, fymin, fxmax, fymax;
+
+ if(!(oc0 | oc1)) return 1; /* both points are inside */
+
+ fx0 = *x0 << 8;
+ fy0 = *y0 << 8;
+ fx1 = *x1 << 8;
+ fy1 = *y1 << 8;
+ fxmin = xmin << 8;
+ fymin = ymin << 8;
+ fxmax = xmax << 8;
+ fymax = ymax << 8;
+
+ for(;;) {
+ long x, y, t;
+
+ if(oc0 & oc1) return 0; /* both have points with the same outbit, not visible */
+ if(!(oc0 | oc1)) break; /* both points are inside */
+
+ oc_out = oc0 ? oc0 : oc1;
+
+ if(oc_out & TOP) {
+ t = FIXDIV(fymin - fy0, fy1 - fy0);
+ x = LERP(fx0, fx1, t);
+ y = fymin;
+ } else if(oc_out & BOTTOM) {
+ t = FIXDIV(fymax - fy0, fy1 - fy0);
+ x = LERP(fx0, fx1, t);
+ y = fymax;
+ } else if(oc_out & LEFT) {
+ t = FIXDIV(fxmin - fx0, fx1 - fx0);
+ x = fxmin;
+ y = LERP(fy0, fy1, t);
+ } else {/*if(oc_out & RIGHT) {*/
+ t = FIXDIV(fxmax - fx0, fx1 - fx0);
+ x = fxmax;
+ y = LERP(fy0, fy1, t);
+ }
+
+ if(oc_out == oc0) {
+ fx0 = x;
+ fy0 = y;
+ oc0 = outcode(fx0 >> 8, fy0 >> 8, xmin, ymin, xmax, ymax);
+ } else {
+ fx1 = x;
+ fy1 = y;
+ oc1 = outcode(fx1 >> 8, fy1 >> 8, xmin, ymin, xmax, ymax);
+ }
+ }
+
+ *x0 = fx0 >> 8;
+ *y0 = fy0 >> 8;
+ *x1 = fx1 >> 8;
+ *y1 = fy1 >> 8;
+ return 1;
+}
+
+#ifdef ALT_LCLIP
+#define PUTPIXEL(ptr) \
+ do { \
+ if(x0 >= 0 && x0 < fbwidth && y0 >= 0 && y0 < fbheight) { \
+ uint16_t *pptr = (uint16_t*)((uint32_t)ptr & 0xfffffffe); \
+ if((uint32_t)ptr & 1) { \
+ *pptr = (*pptr & 0xff) | (color << 8); \
+ } else { \
+ *pptr = (*pptr & 0xff00) | color; \
+ } \
+ } \
+ } while(0)
+#else /* !ALT_LCLIP */
+#define PUTPIXEL(ptr) \
+ do { \
+ uint16_t *pptr = (uint16_t*)((uint32_t)ptr & 0xfffffffe); \
+ if((uint32_t)ptr & 1) { \
+ *pptr = (*pptr & 0xff) | (color << 8); \
+ } else { \
+ *pptr = (*pptr & 0xff00) | color; \
+ } \
+ } while(0)
+#endif
+
+void draw_line(int x0, int y0, int x1, int y1, unsigned short color)
+{
+ int i, dx, dy, x_inc, y_inc, error;
+#ifdef ALT_LCLIP
+ int y0inc;
+#endif
+ unsigned char *fbptr = fb;
+
+ fbptr += y0 * fbwidth + x0;
+
+ dx = x1 - x0;
+ dy = y1 - y0;
+
+ if(dx >= 0) {
+ x_inc = 1;
+ } else {
+ x_inc = -1;
+ dx = -dx;
+ }
+ if(dy >= 0) {
+ y_inc = fbwidth;
+#ifdef ALT_LCLIP
+ y0inc = 1;
+#endif
+ } else {
+ y_inc = -fbwidth;
+#ifdef ALT_LCLIP
+ y0inc = -1;
+#endif
+ dy = -dy;
+ }
+
+ if(dx > dy) {
+ error = dy * 2 - dx;
+ for(i=0; i<=dx; i++) {
+ PUTPIXEL(fbptr);
+ if(error >= 0) {
+ error -= dx * 2;
+ fbptr += y_inc;
+#ifdef ALT_LCLIP
+ y0 += y0inc;
+#endif
+ }
+ error += dy * 2;
+ fbptr += x_inc;
+#ifdef ALT_LCLIP
+ x0 += x_inc;
+#endif
+ }
+ } else {
+ error = dx * 2 - dy;
+ for(i=0; i<=dy; i++) {
+ PUTPIXEL(fbptr);
+ if(error >= 0) {
+ error -= dy * 2;
+ fbptr += x_inc;
+#ifdef ALT_LCLIP
+ x0 += x_inc;
+#endif
+ }
+ error += dx * 2;
+ fbptr += y_inc;
+#ifdef ALT_LCLIP
+ y0 += y0inc;
+#endif
+ }
+ }
+}
+
--- /dev/null
+/*
+blender for the Gameboy Advance
+Copyright (C) 2021 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef POLYFILL_H_
+#define POLYFILL_H_
+
+#include <stdint.h>
+
+struct pvertex {
+ int32_t x, y;
+};
+
+void polyfill_framebuffer(unsigned char *fb, int width, int height);
+void polyfill_flat(struct pvertex *v, int vnum, unsigned char col);
+
+int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax);
+void draw_line(int x0, int y0, int x1, int y1, unsigned short color);
+
+#endif /* POLYFILL_H_ */
--- /dev/null
+#include "sprite.h"
+#include "gbaregs.h"
+
+
+void spr_setup(int xtiles, int ytiles, unsigned char *pixels, unsigned char *cmap)
+{
+ int i, j, num_tiles;
+ uint16_t *cptr, *src, *dst;
+
+ num_tiles = xtiles * ytiles;
+ dst = (uint16_t*)VRAM_LFB_OBJ_ADDR;
+ src = (uint16_t*)pixels;
+ for(i=0; i<num_tiles; i++) {
+ /* copy every row of tile i (8x8) */
+ for(j=0; j<8; j++) {
+ *dst++ = src[j * 64];
+ *dst++ = src[j * 64 + 1];
+ }
+ src += 2;
+
+ if((i & 31) == 31) {
+ src += 7 * 64; /* skip to the next row of tiles (skip 7 rows of pixels) */
+ }
+ }
+
+ cptr = (uint16_t*)CRAM_OBJ_ADDR;
+ for(i=0; i<16; i++) {
+ unsigned char r = *cmap++ >> 3;
+ unsigned char g = *cmap++ >> 3;
+ unsigned char b = *cmap++ >> 3;
+ *cptr++ = r | ((uint16_t)g << 5) | ((uint16_t)b << 10);
+ }
+}
+
+void spr_clear(void)
+{
+ int i;
+
+ for(i=0; i<128; i++) {
+ spr_oam_clear(0, i);
+ }
+}
+
+void spr_oam(uint16_t *oam, int idx, int spr, int x, int y, unsigned int flags)
+{
+ if(!oam) oam = (uint16_t*)OAM_ADDR;
+
+ oam += idx << 2;
+
+ oam[0] = (y & 0xff) | (flags & 0xff00);
+ oam[1] = (x & 0x1ff) | ((flags >> 8) & 0xfe00);
+ oam[2] = (spr & 0x3ff) | ((flags & 3) << 10);
+}
+
+void spr_spr_oam(uint16_t *oam, int idx, struct sprite *spr)
+{
+ int i;
+ struct hwsprite *s;
+
+ s = spr->hwspr;
+ for(i=0; i<spr->num_hwspr; i++) {
+ spr_oam(oam, idx, s->id, spr->x + s->x, spr->y + s->y, s->flags);
+ s++;
+ }
+}
+
+void spr_transform(uint16_t *oam, int idx, int16_t *mat)
+{
+ if(!oam) oam = (uint16_t*)OAM_ADDR;
+
+ oam += (idx << 4) + 3;
+
+ oam[0] = *mat++;
+ oam[4] = *mat++;
+ oam[8] = *mat++;
+ oam[12] = *mat;
+}
--- /dev/null
+#ifndef SPRITE_H_
+#define SPRITE_H_
+
+#include <stdint.h>
+
+enum {
+ SPR_ROTSCL = 0x0100,
+ SPR_DBLSZ = 0x0200,
+ SPR_BLEND = 0x0400,
+ SPR_OBJWIN = 0x0800,
+ SPR_MOSAIC = 0x1000,
+ SPR_256COL = 0x2000,
+ SPR_HRECT = 0x4000,
+ SPR_VRECT = 0x8000,
+
+ SPR_HFLIP = 0x100000,
+ SPR_VFLIP = 0x200000,
+ SPR_SZ16 = 0x400000,
+ SPR_SZ32 = 0x800000,
+ SPR_SZ64 = 0xc00000
+};
+#define SPR_SZ8 0
+#define SPR_ROTSCL_SEL(x) ((unsigned int)(x) << 17)
+#define SPR_PRIO(x) ((unsigned int)(x) & 3)
+
+
+struct hwsprite {
+ short id;
+ short width, height;
+ short x, y;
+ unsigned int flags;
+};
+
+struct sprite {
+ short x, y;
+ struct hwsprite hwspr[8];
+ short num_hwspr;
+};
+
+void spr_setup(int xtiles, int ytiles, unsigned char *pixels, unsigned char *cmap);
+void spr_clear(void);
+
+#define spr_oam_clear(oam, idx) spr_oam(oam, idx, 0, 0, 160, 0)
+void spr_oam(uint16_t *oam, int idx, int spr, int x, int y, unsigned int flags);
+void spr_spr_oam(uint16_t *oam, int idx, struct sprite *spr);
+
+/* idx is the rotation/scale parameter index (0-31), not the sprite index */
+void spr_transform(uint16_t *oam, int idx, int16_t *mat);
+
+
+#endif /* SPRITE_H_ */
--- /dev/null
+#include "intr.h"
+#include "timer.h"
+
+#define F_CLK 16780000
+/* clock is 16.78MHz
+ * - no prescale: 59.595ns
+ * - prescale 64: 3.814us
+ * - prescale 256: 15.256us
+ * - prescale 1024: 61.025us
+ */
+
+static void timer_intr(void);
+
+void init_timer(int tm, unsigned long rate_hz, void (*intr)(void))
+{
+ static const unsigned long clk[] = {F_CLK, F_CLK / 64, F_CLK / 256, F_CLK / 1024};
+ unsigned long count;
+ int pscl = 0;
+
+ do {
+ count = clk[pscl] / rate_hz;
+ } while(count >= 65536 && ++pscl < 4);
+
+ if(pscl >= 4) return; /* impossible rate */
+
+ REG_TMCNT_H(tm) = 0;
+ REG_TMCNT_L(tm) = 65536 - count;
+ if(intr) {
+ interrupt(INTR_TIMER0 + tm, intr);
+ unmask(INTR_TIMER0 + tm);
+ REG_TMCNT_H(tm) = TMCNT_IE;
+ }
+ REG_TMCNT_H(tm) |= TMCNT_EN | pscl;
+}
+
+void reset_msec_timer(void)
+{
+ REG_TM0CNT_H &= ~TMCNT_EN;
+ interrupt(INTR_TIMER0, timer_intr);
+ timer_msec = 0;
+ REG_TM0CNT_L = 65535 - 16779;
+ REG_TM0CNT_H |= TMCNT_IE | TMCNT_EN;
+ unmask(INTR_TIMER0);
+}
+
+void delay(unsigned long ms)
+{
+ unsigned long end = timer_msec + ms;
+ while(timer_msec < end);
+}
+
+static void timer_intr(void)
+{
+ timer_msec++;
+}
--- /dev/null
+#ifndef TIMER_H_
+#define TIMER_H_
+
+#include "gbaregs.h"
+
+#define enable_timer(x) \
+ do { REG_TMCNT_H(x) |= TMCNT_EN; } while(0)
+
+#define disable_timer(x) \
+ do { REG_TMCNT_H(x) &= ~TMCNT_EN; } while(0)
+
+volatile unsigned long timer_msec;
+
+void init_timer(int tm, unsigned long rate_hz, void (*intr)(void));
+
+void reset_msec_timer(void);
+
+void delay(unsigned long ms);
+
+#ifdef __thumb__
+#define udelay(x) asm volatile ( \
+ "0: sub %0, %0, #1\n\t" \
+ "bne 0b\n\t" \
+ :: "r"(x) : "cc")
+#else
+#define udelay(x) asm volatile ( \
+ "0: subs %0, %0, #1\n\t" \
+ "bne 0b\n\t" \
+ :: "r"(x) : "cc")
+#endif
+
+#endif /* TIMER_H_ */
--- /dev/null
+#include "util.h"
+#include "debug.h"
+
+extern char __iheap_start;
+static char *top = &__iheap_start;
+
+int iwram_brk(void *addr)
+{
+ if((char*)addr < &__iheap_start) {
+ addr = &__iheap_start;
+ }
+ if(addr > get_sp()) {
+ /*return -1;*/
+ panic(get_pc(), "iwram_brk (%p) >= sp", addr);
+ }
+ top = addr;
+ return 0;
+}
+
+void *iwram_sbrk(intptr_t delta)
+{
+ void *prev = top;
+ iwram_brk(top + delta);
+ return prev;
+}
--- /dev/null
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <stdint.h>
+
+#define wait_vblank() \
+ do { \
+ while(REG_DISPSTAT & DISPSTAT_VBLANK); \
+ while(!(REG_DISPSTAT & DISPSTAT_VBLANK)); \
+ } while(0)
+
+#define present(x) \
+ do { \
+ REG_DISPCNT = DISPCNT_BG2 | DISPCNT_OBJ | 4 | ((x) << 4); \
+ } while(0)
+
+
+#define set_bg_color(idx, r, g, b) \
+ do { \
+ ((uint16_t*)CRAM_BG_ADDR)[idx] = (uint16_t)(r) | ((uint16_t)(g) << 5) | ((uint16_t)(b) << 10); \
+ } while(0)
+
+extern int16_t sinlut[];
+
+#define SIN(x) sinlut[(x) & 0xff]
+#define COS(x) sinlut[((x) + 64) & 0xff]
+
+int iwram_brk(void *addr);
+void *iwram_sbrk(intptr_t delta);
+
+void fillblock_16byte(void *dest, uint32_t val, int count);
+
+void *get_pc(void);
+void *get_sp(void);
+
+#endif /* UTIL_H_ */
--- /dev/null
+/*
+blender for the Gameboy Advance
+Copyright (C) 2021 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#include <string.h>
+#include <math.h>
+#include "xgl.h"
+#include "polyfill.h"
+#include "debug.h"
+
+#define MAT_STACK_SIZE 4
+
+static int vp[4];
+static int32_t mat[MAT_STACK_SIZE][16];
+static int mtop;
+static unsigned int opt;
+static int32_t ldir[3];
+
+static void draw_ptlines(int prim, const struct xvertex *varr, int vcount);
+
+
+void xgl_init(void)
+{
+ xgl_viewport(0, 0, 240, 160);
+ xgl_load_identity();
+
+ ldir[0] = ldir[1] = 0;
+ ldir[2] = -0x100;
+}
+
+void xgl_enable(unsigned int o)
+{
+ opt |= o;
+}
+
+void xgl_disable(unsigned int o)
+{
+ opt &= ~o;
+}
+
+void xgl_viewport(int x, int y, int w, int h)
+{
+ vp[0] = x;
+ vp[1] = y;
+ vp[2] = w;
+ vp[3] = h;
+}
+
+void xgl_push_matrix(void)
+{
+ int prev;
+
+ if(mtop >= MAT_STACK_SIZE - 1) return;
+
+ prev = mtop++;
+ memcpy(mat[mtop], mat[prev], sizeof mat[0]);
+}
+
+void xgl_pop_matrix(void)
+{
+ if(mtop > 0) mtop--;
+}
+
+static int32_t id[] = {
+ 0x10000, 0, 0, 0,
+ 0, 0x10000, 0, 0,
+ 0, 0, 0x10000, 0,
+ 0, 0, 0, 0x10000
+};
+
+void xgl_load_identity(void)
+{
+ memcpy(mat[mtop], id, sizeof mat[0]);
+}
+
+void xgl_load_matrix(const int32_t *m)
+{
+ memcpy(mat[mtop], m, sizeof mat[0]);
+}
+
+void xgl_get_matrix(int32_t *m)
+{
+ memcpy(m, mat[mtop], sizeof mat[0]);
+}
+
+#define M(i,j) (((i) << 2) + (j))
+#define XMUL(a, b) (((a) >> 8) * ((b) >> 8))
+void xgl_mult_matrix(const int32_t *m2)
+{
+ int i, j;
+ int32_t m1[16];
+ int32_t *dest = mat[mtop];
+
+ memcpy(m1, dest, sizeof m1);
+
+ for(i=0; i<4; i++) {
+ for(j=0; j<4; j++) {
+ *dest++ = XMUL(m1[M(0, j)], m2[M(i, 0)]) +
+ XMUL(m1[M(1, j)], m2[M(i, 1)]) +
+ XMUL(m1[M(2, j)], m2[M(i, 2)]) +
+ XMUL(m1[M(3, j)], m2[M(i, 3)]);
+ }
+ }
+}
+
+#define XSIN(x) (int32_t)(sin(x / 65536.0f) * 65536.0f)
+#define XCOS(x) (int32_t)(cos(x / 65536.0f) * 65536.0f)
+
+void xgl_translate(int32_t x, int32_t y, int32_t z)
+{
+ int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000};
+ m[12] = x;
+ m[13] = y;
+ m[14] = z;
+ xgl_mult_matrix(m);
+}
+
+void xgl_rotate_x(int32_t angle)
+{
+ int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000};
+ int32_t sa = XSIN(angle);
+ int32_t ca = XCOS(angle);
+ m[5] = ca;
+ m[6] = sa;
+ m[9] = -sa;
+ m[10] = ca;
+ xgl_mult_matrix(m);
+}
+
+void xgl_rotate_y(int32_t angle)
+{
+ int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000};
+ int32_t sa = XSIN(angle);
+ int32_t ca = XCOS(angle);
+ m[0] = ca;
+ m[2] = -sa;
+ m[8] = sa;
+ m[10] = ca;
+ xgl_mult_matrix(m);
+}
+
+void xgl_rotate_z(int32_t angle)
+{
+ int32_t m[16] = {0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000, 0, 0, 0, 0, 0x10000};
+ int32_t sa = XSIN(angle);
+ int32_t ca = XCOS(angle);
+ m[0] = ca;
+ m[1] = sa;
+ m[4] = -sa;
+ m[5] = ca;
+ xgl_mult_matrix(m);
+}
+
+void xgl_scale(int32_t x, int32_t y, int32_t z)
+{
+ int32_t m[16] = {0};
+ m[0] = x;
+ m[5] = y;
+ m[10] = z;
+ m[15] = 0x10000;
+ xgl_mult_matrix(m);
+}
+
+static void xform(struct xvertex *out, const struct xvertex *in, const int32_t *m)
+{
+ out->x = XMUL(m[0], in->x) + XMUL(m[4], in->y) + XMUL(m[8], in->z) + m[12];
+ out->y = XMUL(m[1], in->x) + XMUL(m[5], in->y) + XMUL(m[9], in->z) + m[13];
+ out->z = XMUL(m[2], in->x) + XMUL(m[6], in->y) + XMUL(m[10], in->z) + m[14];
+}
+
+static void xform_norm(struct xvertex *out, const struct xvertex *in, const int32_t *m)
+{
+ out->nx = XMUL(m[0], in->nx) + XMUL(m[4], in->ny) + XMUL(m[8], in->nz);
+ out->ny = XMUL(m[1], in->nx) + XMUL(m[5], in->ny) + XMUL(m[9], in->nz);
+ out->nz = XMUL(m[2], in->nx) + XMUL(m[6], in->ny) + XMUL(m[10], in->nz);
+}
+
+/* d = 1.0 / tan(fov/2) */
+#define PROJ_D 0x20000
+
+void xgl_draw(int prim, const struct xvertex *varr, int vcount)
+{
+ int i, cidx;
+ struct xvertex xv[4];
+ struct pvertex pv[4];
+ int32_t ndotl;
+
+ if(prim < 3) {
+ draw_ptlines(prim, varr, vcount);
+ return;
+ }
+
+ while(vcount >= prim) {
+ cidx = varr->cidx;
+
+ xform(xv, varr, mat[mtop]);
+ xform_norm(xv, varr, mat[mtop]);
+
+ if(xv->nz > 0) {
+ /* backface */
+ varr += prim;
+ vcount -= prim;
+ continue;
+ }
+
+ if(opt & XGL_LIGHTING) {
+ ndotl = (xv->nx >> 8) * ldir[0] + (xv->ny >> 8) * ldir[1] + (xv->nz >> 8) * ldir[2];
+ if(ndotl < 0) ndotl = 0;
+ cidx = 128 + (ndotl >> 9);
+ if(cidx > 255) cidx = 255;
+ }
+
+ xv->x = (xv->x << 1) / (xv->z >> 8); /* assume aspect: ~2 */
+ xv->y = (xv->y << 2) / (xv->z >> 8); /* the shift is * PROJ_D */
+ /* projection result is 24.8 */
+ /* viewport */
+ pv->x = (((xv->x + 0x100) >> 1) * vp[2]) + (vp[0] << 8);
+ pv->y = (((0x100 - xv->y) >> 1) * vp[3]) + (vp[1] << 8);
+ varr++;
+
+ for(i=1; i<prim; i++) {
+ xform(xv + i, varr, mat[mtop]);
+
+ xv[i].x = (xv[i].x << 1) / (xv[i].z >> 8); /* assume aspect: ~2 */
+ xv[i].y = (xv[i].y << 2) / (xv[i].z >> 8); /* the shift is * PROJ_D */
+ /* projection result is 24.8 */
+ /* viewport */
+ pv[i].x = (((xv[i].x + 0x100) >> 1) * vp[2]) + (vp[0] << 8);
+ pv[i].y = (((0x100 - xv[i].y) >> 1) * vp[3]) + (vp[1] << 8);
+ varr++;
+ }
+ vcount -= prim;
+
+ polyfill_flat(pv, prim, cidx);
+ }
+}
+
+void xgl_transform(const struct xvertex *vin, int *x, int *y)
+{
+ struct xvertex v;
+ xform(&v, vin, mat[mtop]);
+
+ v.x = (v.x << 1) / (v.z >> 8); /* assume aspect: ~2 */
+ v.y = (v.y << 2) / (v.z >> 8); /* the shift is * PROJ_D */
+ /* projection result is 24.8 */
+ /* viewport */
+ *x = ((((v.x + 0x100) >> 1) * vp[2]) >> 8) + vp[0];
+ *y = ((((0x100 - v.y) >> 1) * vp[3]) >> 8) + vp[1];
+}
+
+static void draw_ptlines(int prim, const struct xvertex *varr, int vcount)
+{
+ int i;
+ struct xvertex xv[2];
+
+ while(vcount >= prim) {
+ for(i=0; i<prim; i++) {
+ xform(xv + i, varr, mat[mtop]);
+
+ xv[i].x = (xv[i].x << 1) / (xv[i].z >> 8); /* assume aspect: ~2 */
+ xv[i].y = (xv[i].y << 2) / (xv[i].z >> 8); /* the shift is * PROJ_D */
+ /* projection result is 24.8 */
+ /* viewport */
+ xv[i].x = ((((xv[i].x + 0x100) >> 1) * vp[2]) >> 8) + vp[0];
+ xv[i].y = ((((0x100 - xv[i].y) >> 1) * vp[3]) >> 8) + vp[1];
+ varr++;
+ }
+ vcount -= prim;
+
+ /* line clipping */
+#ifndef ALT_LCLIP
+ clip_line((int*)&xv[0].x, (int*)&xv[0].y, (int*)&xv[1].x, (int*)&xv[1].y, vp[0], vp[1], vp[2] - 1, vp[3] - 1);
+#endif
+ draw_line(xv[0].x, xv[0].y, xv[1].x, xv[1].y, varr[-2].cidx);
+ }
+}
+
+void xgl_xyzzy(void)
+{
+ mat[mtop][12] = mat[mtop][13] = 0;
+}
--- /dev/null
+/*
+blender for the Gameboy Advance
+Copyright (C) 2021 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef XGL_H_
+#define XGL_H_
+
+#define X_PI 0x3243f
+#define X_2PI 0x6487f
+#define X_HPI 0x19220
+#define X_QPI 0xc910
+
+enum {
+ XGL_LIGHTING = 1,
+ XGL_DEPTH_TEST = 2,
+};
+
+enum {
+ XGL_LINES = 2,
+ XGL_TRIANGLES = 3,
+ XGL_QUADS = 4
+};
+
+struct xvertex {
+ int32_t x, y, z;
+ int32_t nx, ny, nz;
+ unsigned char cidx;
+};
+
+void xgl_init(void);
+
+void xgl_enable(unsigned int opt);
+void xgl_disable(unsigned int opt);
+
+void xgl_viewport(int x, int y, int w, int h);
+
+void xgl_push_matrix(void);
+void xgl_pop_matrix(void);
+void xgl_load_identity(void);
+void xgl_load_matrix(const int32_t *m);
+void xgl_get_matrix(int32_t *m);
+void xgl_mult_matrix(const int32_t *m);
+
+void xgl_translate(int32_t x, int32_t y, int32_t z);
+void xgl_rotate_x(int32_t angle);
+void xgl_rotate_y(int32_t angle);
+void xgl_rotate_z(int32_t angle);
+void xgl_scale(int32_t x, int32_t y, int32_t z);
+
+void xgl_draw(int prim, const struct xvertex *varr, int vcount);
+void xgl_transform(const struct xvertex *vin, int *x, int *y);
+
+void xgl_xyzzy(void);
+
+#endif /* XGL_H_ */
--- /dev/null
+#include <stdio.h>
+#include <math.h>
+
+int main(void)
+{
+ int i;
+
+ puts("\t.data");
+ puts("\t.globl sinlut");
+ puts("sinlut:");
+ for(i=0; i<256; i++) {
+ float x = sin((float)i / 128.0f * M_PI);
+ printf("\t.short %d\n", (int)(x * 256.0f));
+ }
+ return 0;
+}