shithub: pt2-clone

Download patch

ref: 653e85a92f58a1aab94793e209e12fde6a8d734b
parent: 6ccfc575a5017980a2685fa2e2b8f717b86b7580
author: Olav Sørensen <olav.sorensen@live.no>
date: Tue Oct 11 10:56:39 EDT 2022

Mega commit (v1.52)

- Updated SDL to v2.24.1
- The default Disk Op. directory is now set to the user's desktop
- SHIFT+F12 now toggles audio panning between centered/Amiga/custom
- Show "[EDITING]" in window title when you are in pattern edit mode
- The default MOD2WAV output frequency is now set to 44100Hz, and it now has its own config entry in protracker.ini.
- MOD2WAV now supports looping. You can select the number of times to loop the song.
- MOD2WAV now supports end fadeout (in number of seconds)
- Bugfix: After dragging a sample into the program and it asks about downsampling, the first mouse click would not be registered.
- PAT2SMP: You can now manually select the note (frequency), row start and number of rows
- Bugfix: On sample trigger, some of the first sample points would be zero
- Bugfix: The playback counter was very slightly off in VBL/vblank tempo mode
- Bugfix: If the program received a sigterm while MOD2WAV was ongoing, weird things could happen.
- The tuning tone (SAMPLER screen) now sounds slightly cleaner
- Code refactoring ("ask dialogs" now work in a much simpler and cleaner way)
- Code cleanup
- Updated help.txt and keybindings.txt
- NOTE: Because of the new Paula and replayer changes, you may get a short click before a voice plays for the first time in the tracker after pressing PLAY. This is how it is on real Amiga as well.

diff: cannot open b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/CMake//null: file does not exist: '.../Frameworks/SDL2.framework/Versions/A/Resources/CMake//null'
--- a/make-macos.sh
+++ b/make-macos.sh
@@ -41,7 +41,7 @@
 }
 
 echo Compiling x86_64 binary, please wait patiently...
-CFLAGS="-target x86_64-apple-macos10.7 -mmacosx-version-min=10.7 -arch x86_64 -mmmx -mfpmath=sse -msse2 -O3"
+CFLAGS="-target x86_64-apple-macos10.9 -mmacosx-version-min=10.9 -arch x86_64 -mmmx -mfpmath=sse -msse2 -O3"
 LDFLAGS=
 export SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
 compile $TARGET_X86_64
--- a/release/help.txt
+++ b/release/help.txt
@@ -28,7 +28,8 @@
  - Adjust the STEREOSEPARATION setting in protracker.ini. It's a percentage
    value ranging from 0 to 100. 0 being mono and 100 being 100% separated like
    the audio output from an Amiga.
-   Pressing SHIFT+F12 will toggle between STEREOSEPARATION and 100% (hard pan).
+   Pressing SHIFT+F12 toggles between centered (0%), Amiga (100%) and
+   custom (STEREOSEPARATION %).
 
  * How do I change the Multi channel ordering?
  - When in idle mode (not edit/play etc), press ALT+1/2/3/4 to increase
--- a/release/keybindings.txt
+++ b/release/keybindings.txt
@@ -21,7 +21,7 @@
    alt+F11     - Toggle between real/fake VU-Meters
    F11         - Toggle fullscreen
    F12         - Toggle Amiga model (for low-pass filter)
-   shift+F12   - Toggle Amiga panning (100% stereo separation)
+   shift+F12   - Toggle audio panning between mono/custom/Amiga
    ctrl+F12    - Toggle CIA/VBLANK timing for tempo/speed effect (Fxx)
    alt+1/2/3/4 - Increase Multi ordering (when in idle, not play/edit/rec.)
    home        - Go to row 0
--- a/release/macos/protracker.ini
+++ b/release/macos/protracker.ini
@@ -252,7 +252,7 @@
 ; Audio output frequency
 ;        Syntax: Number, in hertz
 ; Default value: 48000
-;       Comment: Ranges from 44100 to 192000. Also applies to MOD2WAV.
+;       Comment: Ranges from 44100 to 192000. Does not apply to MOD2WAV.
 ;
 FREQUENCY=48000
 
@@ -263,6 +263,13 @@
 ;         the frequency used for your audio input device (for sampling).
 ;
 SAMPLINGFREQ=44100
+
+; MOD2WAV output frequency
+;        Syntax: Number, in hertz
+; Default value: 44100
+;       Comment: Ranges from 44100 to 192000.
+;
+MOD2WAVFREQUENCY=44100
 
 ; Filter model (Amiga model)
 ;        Syntax: A500 or A1200
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL.h
@@ -29,41 +29,42 @@
 #ifndef SDL_h_
 #define SDL_h_
 
-#include "SDL_main.h"
-#include "SDL_stdinc.h"
-#include "SDL_assert.h"
-#include "SDL_atomic.h"
-#include "SDL_audio.h"
-#include "SDL_clipboard.h"
-#include "SDL_cpuinfo.h"
-#include "SDL_endian.h"
-#include "SDL_error.h"
-#include "SDL_events.h"
-#include "SDL_filesystem.h"
-#include "SDL_gamecontroller.h"
-#include "SDL_haptic.h"
-#include "SDL_hidapi.h"
-#include "SDL_hints.h"
-#include "SDL_joystick.h"
-#include "SDL_loadso.h"
-#include "SDL_log.h"
-#include "SDL_messagebox.h"
-#include "SDL_metal.h"
-#include "SDL_mutex.h"
-#include "SDL_power.h"
-#include "SDL_render.h"
-#include "SDL_rwops.h"
-#include "SDL_sensor.h"
-#include "SDL_shape.h"
-#include "SDL_system.h"
-#include "SDL_thread.h"
-#include "SDL_timer.h"
-#include "SDL_version.h"
-#include "SDL_video.h"
-#include "SDL_locale.h"
-#include "SDL_misc.h"
+#include <SDL2/SDL_main.h>
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_assert.h>
+#include <SDL2/SDL_atomic.h>
+#include <SDL2/SDL_audio.h>
+#include <SDL2/SDL_clipboard.h>
+#include <SDL2/SDL_cpuinfo.h>
+#include <SDL2/SDL_endian.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_events.h>
+#include <SDL2/SDL_filesystem.h>
+#include <SDL2/SDL_gamecontroller.h>
+#include <SDL2/SDL_guid.h>
+#include <SDL2/SDL_haptic.h>
+#include <SDL2/SDL_hidapi.h>
+#include <SDL2/SDL_hints.h>
+#include <SDL2/SDL_joystick.h>
+#include <SDL2/SDL_loadso.h>
+#include <SDL2/SDL_log.h>
+#include <SDL2/SDL_messagebox.h>
+#include <SDL2/SDL_metal.h>
+#include <SDL2/SDL_mutex.h>
+#include <SDL2/SDL_power.h>
+#include <SDL2/SDL_render.h>
+#include <SDL2/SDL_rwops.h>
+#include <SDL2/SDL_sensor.h>
+#include <SDL2/SDL_shape.h>
+#include <SDL2/SDL_system.h>
+#include <SDL2/SDL_thread.h>
+#include <SDL2/SDL_timer.h>
+#include <SDL2/SDL_version.h>
+#include <SDL2/SDL_video.h>
+#include <SDL2/SDL_locale.h>
+#include <SDL2/SDL_misc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -225,7 +226,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_assert.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_assert.h
@@ -22,9 +22,9 @@
 #ifndef SDL_assert_h_
 #define SDL_assert_h_
 
-#include "SDL_config.h"
+#include <SDL2/SDL_stdinc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -51,6 +51,8 @@
 /* Don't include intrin.h here because it contains C++ code */
     extern void __cdecl __debugbreak(void);
     #define SDL_TriggerBreakpoint() __debugbreak()
+#elif _SDL_HAS_BUILTIN(__builtin_debugtrap)
+    #define SDL_TriggerBreakpoint() __builtin_debugtrap()
 #elif ( (!defined(__NACL__)) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))) )
     #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
 #elif ( defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) )  /* this might work on other ARM targets, but this is a known quantity... */
@@ -69,7 +71,7 @@
 
 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */
 #   define SDL_FUNCTION __func__
-#elif ((__GNUC__ >= 2) || defined(_MSC_VER) || defined (__WATCOMC__))
+#elif ((defined(__GNUC__) && (__GNUC__ >= 2)) || defined(_MSC_VER) || defined (__WATCOMC__))
 #   define SDL_FUNCTION __FUNCTION__
 #else
 #   define SDL_FUNCTION "???"
@@ -317,7 +319,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_assert_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_atomic.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_atomic.h
@@ -59,10 +59,10 @@
 #ifndef SDL_atomic_h_
 #define SDL_atomic_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_platform.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_platform.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
@@ -237,6 +237,26 @@
 #endif
 #endif
 
+/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
+#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
+    #define SDL_CPUPauseInstruction() __asm__ __volatile__("pause\n")  /* Some assemblers can't do REP NOP, so go with PAUSE. */
+#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
+    #define SDL_CPUPauseInstruction() __asm__ __volatile__("yield" ::: "memory")
+#elif (defined(__powerpc__) || defined(__powerpc64__))
+    #define SDL_CPUPauseInstruction() __asm__ __volatile__("or 27,27,27");
+#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
+    #define SDL_CPUPauseInstruction() _mm_pause()  /* this is actually "rep nop" and not a SIMD instruction. No inline asm in MSVC x86-64! */
+#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
+    #define SDL_CPUPauseInstruction() __yield()
+#elif defined(__WATCOMC__) && defined(__386__)
+    /* watcom assembler rejects PAUSE if CPU < i686, and it refuses REP NOP as an invalid combination. Hardcode the bytes.  */
+    extern __inline void SDL_CPUPauseInstruction(void);
+    #pragma aux SDL_CPUPauseInstruction = "db 0f3h,90h"
+#else
+    #define SDL_CPUPauseInstruction()
+#endif
+
+
 /**
  * \brief A type representing an atomic integer value.  It is a struct
  *        so people don't accidentally use numeric operations on it.
@@ -388,7 +408,7 @@
 }
 #endif
 
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_atomic_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_audio.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_audio.h
@@ -30,14 +30,14 @@
 #ifndef SDL_audio_h_
 #define SDL_audio_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
-#include "SDL_endian.h"
-#include "SDL_mutex.h"
-#include "SDL_thread.h"
-#include "SDL_rwops.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_endian.h>
+#include <SDL2/SDL_mutex.h>
+#include <SDL2/SDL_thread.h>
+#include <SDL2/SDL_rwops.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -172,7 +172,7 @@
  *  2:  FL FR                       (stereo)
  *  3:  FL FR LFE                   (2.1 surround)
  *  4:  FL FR BL BR                 (quad)
- *  5:  FL FR FC BL BR              (quad + center)
+ *  5:  FL FR LFE BL BR             (4.1 surround)
  *  6:  FL FR FC LFE SL SR          (5.1 surround - last two can also be BL BR)
  *  7:  FL FR FC LFE BC SL SR       (6.1 surround)
  *  8:  FL FR FC LFE BL BR SL SR    (7.1 surround)
@@ -487,6 +487,7 @@
  * \since This function is available since SDL 2.0.0.
  *
  * \sa SDL_GetNumAudioDevices
+ * \sa SDL_GetDefaultAudioInfo
  */
 extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index,
                                                            int iscapture);
@@ -512,6 +513,7 @@
  * \since This function is available since SDL 2.0.16.
  *
  * \sa SDL_GetNumAudioDevices
+ * \sa SDL_GetDefaultAudioInfo
  */
 extern DECLSPEC int SDLCALL SDL_GetAudioDeviceSpec(int index,
                                                    int iscapture,
@@ -519,6 +521,41 @@
 
 
 /**
+ * Get the name and preferred format of the default audio device.
+ *
+ * Some (but not all!) platforms have an isolated mechanism to get information
+ * about the "default" device. This can actually be a completely different
+ * device that's not in the list you get from SDL_GetAudioDeviceSpec(). It can
+ * even be a network address! (This is discussed in SDL_OpenAudioDevice().)
+ *
+ * As a result, this call is not guaranteed to be performant, as it can query
+ * the sound server directly every time, unlike the other query functions. You
+ * should call this function sparingly!
+ *
+ * `spec` will be filled with the sample rate, sample format, and channel
+ * count, if a default device exists on the system. If `name` is provided,
+ * will be filled with either a dynamically-allocated UTF-8 string or NULL.
+ *
+ * \param name A pointer to be filled with the name of the default device (can
+ *             be NULL). Please call SDL_free() when you are done with this
+ *             pointer!
+ * \param spec The SDL_AudioSpec to be initialized by this function.
+ * \param iscapture non-zero to query the default recording device, zero to
+ *                  query the default output device.
+ * \returns 0 on success, nonzero on error
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GetAudioDeviceName
+ * \sa SDL_GetAudioDeviceSpec
+ * \sa SDL_OpenAudioDevice
+ */
+extern DECLSPEC int SDLCALL SDL_GetDefaultAudioInfo(char **name,
+                                                    SDL_AudioSpec *spec,
+                                                    int iscapture);
+
+
+/**
  * Open a specific audio device.
  *
  * SDL_OpenAudio(), unlike this function, always acts on device ID 1. As such,
@@ -584,6 +621,7 @@
  * - `SDL_AUDIO_ALLOW_FREQUENCY_CHANGE`
  * - `SDL_AUDIO_ALLOW_FORMAT_CHANGE`
  * - `SDL_AUDIO_ALLOW_CHANNELS_CHANGE`
+ * - `SDL_AUDIO_ALLOW_SAMPLES_CHANGE`
  * - `SDL_AUDIO_ALLOW_ANY_CHANGE`
  *
  * These flags specify how SDL should behave when a device cannot offer a
@@ -1455,7 +1493,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_audio_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_bits.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_bits.h
@@ -28,9 +28,9 @@
 #ifndef SDL_bits_h_
 #define SDL_bits_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -119,7 +119,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_bits_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_blendmode.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_blendmode.h
@@ -28,7 +28,7 @@
 #ifndef SDL_blendmode_h_
 #define SDL_blendmode_h_
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -191,7 +191,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_blendmode_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_clipboard.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_clipboard.h
@@ -28,9 +28,9 @@
 #ifndef SDL_clipboard_h_
 #define SDL_clipboard_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -87,7 +87,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_clipboard_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_config.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_config.h
@@ -22,7 +22,7 @@
 #ifndef SDL_config_h_
 #define SDL_config_h_
 
-#include "SDL_platform.h"
+#include <SDL2/SDL_platform.h>
 
 /**
  *  \file SDL_config.h
@@ -30,22 +30,28 @@
 
 /* Add any platform that doesn't build using the configure system. */
 #if defined(__WIN32__)
-#include "SDL_config_windows.h"
+#include <SDL2/SDL_config_windows.h>
 #elif defined(__WINRT__)
-#include "SDL_config_winrt.h"
+#include <SDL2/SDL_config_winrt.h>
+#elif defined(__WINGDK__)
+#include <SDL2/SDL_config_wingdk.h>
+#elif defined(__XBOXONE__) || defined(__XBOXSERIES__)
+#include <SDL2/SDL_config_xbox.h>
 #elif defined(__MACOSX__)
-#include "SDL_config_macosx.h"
+#include <SDL2/SDL_config_macosx.h>
 #elif defined(__IPHONEOS__)
-#include "SDL_config_iphoneos.h"
+#include <SDL2/SDL_config_iphoneos.h>
 #elif defined(__ANDROID__)
-#include "SDL_config_android.h"
+#include <SDL2/SDL_config_android.h>
 #elif defined(__OS2__)
-#include "SDL_config_os2.h"
+#include <SDL2/SDL_config_os2.h>
 #elif defined(__EMSCRIPTEN__)
-#include "SDL_config_emscripten.h"
+#include <SDL2/SDL_config_emscripten.h>
+#elif defined(__NGAGE__)
+#include <SDL2/SDL_config_ngage.h>
 #else
 /* This is a minimal configuration just to get SDL running on new platforms. */
-#include "SDL_config_minimal.h"
+#include <SDL2/SDL_config_minimal.h>
 #endif /* platform config */
 
 #ifdef USING_GENERATED_CONFIG_H
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_config_macosx.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_config_macosx.h
@@ -23,7 +23,7 @@
 #define SDL_config_macosx_h_
 #define SDL_config_h_
 
-#include "SDL_platform.h"
+#include <SDL2/SDL_platform.h>
 
 /* This gets us MAC_OS_X_VERSION_MIN_REQUIRED... */
 #include <AvailabilityMacros.h>
@@ -63,6 +63,7 @@
 #define HAVE_PUTENV 1
 #define HAVE_UNSETENV   1
 #define HAVE_QSORT  1
+#define HAVE_BSEARCH 1
 #define HAVE_ABS    1
 #define HAVE_BCOPY  1
 #define HAVE_MEMSET 1
@@ -120,7 +121,7 @@
 #define HAVE_LROUNDF 1
 #define HAVE_POW    1
 #define HAVE_POWF   1
-#define HAVE_ROUND 1
+#define HAVE_ROUND  1
 #define HAVE_ROUNDF 1
 #define HAVE_SCALBN 1
 #define HAVE_SCALBNF    1
@@ -185,17 +186,13 @@
 #undef SDL_VIDEO_DRIVER_X11
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC "/opt/X11/lib/libX11.6.dylib"
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT "/opt/X11/lib/libXext.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA "/opt/X11/lib/libXinerama.1.dylib"
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 "/opt/X11/lib/libXi.6.dylib"
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "/opt/X11/lib/libXrandr.2.dylib"
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS "/opt/X11/lib/libXss.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE "/opt/X11/lib/libXxf86vm.1.dylib"
 #define SDL_VIDEO_DRIVER_X11_XDBE 1
-#define SDL_VIDEO_DRIVER_X11_XINERAMA 1
 #define SDL_VIDEO_DRIVER_X11_XRANDR 1
 #define SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1
 #define SDL_VIDEO_DRIVER_X11_XSHAPE 1
-#define SDL_VIDEO_DRIVER_X11_XVIDMODE 1
 #define SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM 1
 
 #ifdef MAC_OS_X_VERSION_10_8
@@ -272,7 +269,6 @@
 #define SDL_FILESYSTEM_COCOA   1
 
 /* Enable assembly routines */
-#define SDL_ASSEMBLY_ROUTINES   1
 #ifdef __ppc__
 #define SDL_ALTIVEC_BLITTERS    1
 #endif
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_cpuinfo.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_cpuinfo.h
@@ -28,7 +28,7 @@
 #ifndef SDL_cpuinfo_h_
 #define SDL_cpuinfo_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
 /* Need to do this here because intrin.h has C++ code in it */
 /* Visual Studio 2005 has a bug where intrin.h conflicts with winnt.h */
@@ -79,7 +79,7 @@
 #if !defined(SDL_DISABLE_ARM_NEON_H)
 #  if defined(__ARM_NEON)
 #    include <arm_neon.h>
-#  elif defined(__WINDOWS__) || defined(__WINRT__)
+#  elif defined(__WINDOWS__) || defined(__WINRT__) || defined(__GDK__)
 /* Visual Studio doesn't define __ARM_ARCH, but _M_ARM (if set, always 7), and _M_ARM64 (if set, always 1). */
 #    if defined(_M_ARM)
 #      include <armintr.h>
@@ -98,6 +98,14 @@
 #if defined(__3dNOW__) && !defined(SDL_DISABLE_MM3DNOW_H)
 #include <mm3dnow.h>
 #endif
+#if defined(__loongarch_sx) && !defined(SDL_DISABLE_LSX_H)
+#include <lsxintrin.h>
+#define __LSX__
+#endif
+#if defined(__loongarch_asx) && !defined(SDL_DISABLE_LASX_H)
+#include <lasxintrin.h>
+#define __LASX__
+#endif
 #if defined(HAVE_IMMINTRIN_H) && !defined(SDL_DISABLE_IMMINTRIN_H)
 #include <immintrin.h>
 #else
@@ -115,7 +123,7 @@
 #endif
 #endif /* HAVE_IMMINTRIN_H */
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -434,9 +442,35 @@
 extern DECLSPEC SDL_bool SDLCALL SDL_HasNEON(void);
 
 /**
+ * Determine whether the CPU has LSX (LOONGARCH SIMD) features.
+ *
+ * This always returns false on CPUs that aren't using LOONGARCH instruction
+ * sets.
+ *
+ * \returns SDL_TRUE if the CPU has LOONGARCH LSX features or SDL_FALSE if
+ *          not.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasLSX(void);
+
+/**
+ * Determine whether the CPU has LASX (LOONGARCH SIMD) features.
+ *
+ * This always returns false on CPUs that aren't using LOONGARCH instruction
+ * sets.
+ *
+ * \returns SDL_TRUE if the CPU has LOONGARCH LASX features or SDL_FALSE if
+ *          not.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasLASX(void);
+
+/**
  * Get the amount of RAM configured in the system.
  *
- * \returns the amount of RAM configured in the system in MB.
+ * \returns the amount of RAM configured in the system in MiB.
  *
  * \since This function is available since SDL 2.0.1.
  */
@@ -494,7 +528,7 @@
  *
  * \since This function is available since SDL 2.0.10.
  *
- * \sa SDL_SIMDAlignment
+ * \sa SDL_SIMDGetAlignment
  * \sa SDL_SIMDRealloc
  * \sa SDL_SIMDFree
  */
@@ -518,7 +552,7 @@
  *
  * \since This function is available since SDL 2.0.14.
  *
- * \sa SDL_SIMDAlignment
+ * \sa SDL_SIMDGetAlignment
  * \sa SDL_SIMDAlloc
  * \sa SDL_SIMDFree
  */
@@ -552,7 +586,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_cpuinfo_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_endian.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_endian.h
@@ -28,7 +28,7 @@
 #ifndef SDL_endian_h_
 #define SDL_endian_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
 /* As of Clang 11, '_m_prefetchw' is conflicting with the winnt.h's version,
@@ -39,7 +39,7 @@
 static __inline__ void __attribute__((__always_inline__, __nodebug__))
 _m_prefetch(void *__P)
 {
-  __builtin_prefetch (__P, 0, 3 /* _MM_HINT_T0 */);
+  __builtin_prefetch(__P, 0, 3 /* _MM_HINT_T0 */);
 }
 #endif /* __PRFCHWINTRIN_H */
 #endif /* __clang__ */
@@ -59,7 +59,7 @@
 #ifdef __linux__
 #include <endian.h>
 #define SDL_BYTEORDER  __BYTE_ORDER
-#elif defined(__OpenBSD__)
+#elif defined(__OpenBSD__) || defined(__DragonFly__)
 #include <endian.h>
 #define SDL_BYTEORDER  BYTE_ORDER
 #elif defined(__FreeBSD__) || defined(__NetBSD__)
@@ -78,7 +78,7 @@
 #if defined(__hppa__) || \
     defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
     (defined(__MIPS__) && defined(__MIPSEB__)) || \
-    defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \
+    defined(__ppc__) || defined(__POWERPC__) || defined(__powerpc__) || defined(__PPC__) || \
     defined(__sparc__)
 #define SDL_BYTEORDER   SDL_BIG_ENDIAN
 #else
@@ -87,8 +87,30 @@
 #endif /* __linux__ */
 #endif /* !SDL_BYTEORDER */
 
+#ifndef SDL_FLOATWORDORDER           /* Not defined in SDL_config.h? */
+/* predefs from newer gcc versions: */
+#if defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__FLOAT_WORD_ORDER__)
+#if (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define SDL_FLOATWORDORDER   SDL_LIL_ENDIAN
+#elif (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define SDL_FLOATWORDORDER   SDL_BIG_ENDIAN
+#else
+#error Unsupported endianness
+#endif /**/
+#elif defined(__MAVERICK__)
+/* For Maverick, float words are always little-endian. */
+#define SDL_FLOATWORDORDER   SDL_LIL_ENDIAN
+#elif (defined(__arm__) || defined(__thumb__)) && !defined(__VFP_FP__) && !defined(__ARM_EABI__)
+/* For FPA, float words are always big-endian. */
+#define SDL_FLOATWORDORDER   SDL_BIG_ENDIAN
+#else
+/* By default, assume that floats words follow the memory system mode. */
+#define SDL_FLOATWORDORDER   SDL_BYTEORDER
+#endif /* __FLOAT_WORD_ORDER__ */
+#endif /* !SDL_FLOATWORDORDER */
 
-#include "begin_code.h"
+
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -319,7 +341,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_endian_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_error.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_error.h
@@ -28,9 +28,9 @@
 #ifndef SDL_error_h_
 #define SDL_error_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -156,7 +156,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_error_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_events.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_events.h
@@ -28,18 +28,18 @@
 #ifndef SDL_events_h_
 #define SDL_events_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
-#include "SDL_video.h"
-#include "SDL_keyboard.h"
-#include "SDL_mouse.h"
-#include "SDL_joystick.h"
-#include "SDL_gamecontroller.h"
-#include "SDL_quit.h"
-#include "SDL_gesture.h"
-#include "SDL_touch.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_video.h>
+#include <SDL2/SDL_keyboard.h>
+#include <SDL2/SDL_mouse.h>
+#include <SDL2/SDL_joystick.h>
+#include <SDL2/SDL_gamecontroller.h>
+#include <SDL2/SDL_quit.h>
+#include <SDL2/SDL_gesture.h>
+#include <SDL2/SDL_touch.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -118,6 +118,7 @@
     SDL_JOYBUTTONUP,            /**< Joystick button released */
     SDL_JOYDEVICEADDED,         /**< A new joystick has been inserted into the system */
     SDL_JOYDEVICEREMOVED,       /**< An opened joystick has been removed */
+    SDL_JOYBATTERYUPDATED,      /**< Joystick battery level change */
 
     /* Game controller events */
     SDL_CONTROLLERAXISMOTION  = 0x650, /**< Game controller axis motion */
@@ -395,6 +396,16 @@
     Sint32 which;       /**< The joystick device index for the ADDED event, instance id for the REMOVED event */
 } SDL_JoyDeviceEvent;
 
+/**
+ *  \brief Joysick battery level change event structure (event.jbattery.*)
+ */
+typedef struct SDL_JoyBatteryEvent
+{
+    Uint32 type;        /**< ::SDL_JOYBATTERYUPDATED */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    SDL_JoystickID which; /**< The joystick instance id */
+    SDL_JoystickPowerLevel level; /**< The joystick battery level */
+} SDL_JoyBatteryEvent;
 
 /**
  *  \brief Game controller axis motion event structure (event.caxis.*)
@@ -625,6 +636,7 @@
     SDL_JoyHatEvent jhat;                   /**< Joystick hat event data */
     SDL_JoyButtonEvent jbutton;             /**< Joystick button event data */
     SDL_JoyDeviceEvent jdevice;             /**< Joystick device change event data */
+    SDL_JoyBatteryEvent jbattery;           /**< Joystick battery event data */
     SDL_ControllerAxisEvent caxis;          /**< Game Controller axis event data */
     SDL_ControllerButtonEvent cbutton;      /**< Game Controller button event data */
     SDL_ControllerDeviceEvent cdevice;      /**< Game Controller device event data */
@@ -1143,7 +1155,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_events_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_filesystem.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_filesystem.h
@@ -28,9 +28,9 @@
 #ifndef SDL_filesystem_h_
 #define SDL_filesystem_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
@@ -92,7 +92,7 @@
  *
  * `C:\\Users\\bob\\AppData\\Roaming\\My Company\\My Program Name\\`
  *
- * On Linux, the string might look like"
+ * On Linux, the string might look like:
  *
  * `/home/bob/.local/share/My Program Name/`
  *
@@ -138,7 +138,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_filesystem_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_gamecontroller.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_gamecontroller.h
@@ -28,13 +28,13 @@
 #ifndef SDL_gamecontroller_h_
 #define SDL_gamecontroller_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
-#include "SDL_rwops.h"
-#include "SDL_sensor.h"
-#include "SDL_joystick.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_rwops.h>
+#include <SDL2/SDL_sensor.h>
+#include <SDL2/SDL_joystick.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -69,7 +69,11 @@
     SDL_CONTROLLER_TYPE_VIRTUAL,
     SDL_CONTROLLER_TYPE_PS5,
     SDL_CONTROLLER_TYPE_AMAZON_LUNA,
-    SDL_CONTROLLER_TYPE_GOOGLE_STADIA
+    SDL_CONTROLLER_TYPE_GOOGLE_STADIA,
+    SDL_CONTROLLER_TYPE_NVIDIA_SHIELD,
+    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT,
+    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT,
+    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
 } SDL_GameControllerType;
 
 typedef enum
@@ -290,6 +294,25 @@
 extern DECLSPEC const char *SDLCALL SDL_GameControllerNameForIndex(int joystick_index);
 
 /**
+ * Get the implementation dependent path for the game controller.
+ *
+ * This function can be called before any controllers are opened.
+ *
+ * `joystick_index` is the same as the `device_index` passed to
+ * SDL_JoystickOpen().
+ *
+ * \param joystick_index the device_index of a device, from zero to
+ *                       SDL_NumJoysticks()-1
+ * \returns the implementation-dependent path for the game controller, or NULL
+ *          if there is no path or the index is invalid.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GameControllerPath
+ */
+extern DECLSPEC const char *SDLCALL SDL_GameControllerPathForIndex(int joystick_index);
+
+/**
  * Get the type of a game controller.
  *
  * This can be called before any controllers are opened.
@@ -387,6 +410,23 @@
 extern DECLSPEC const char *SDLCALL SDL_GameControllerName(SDL_GameController *gamecontroller);
 
 /**
+ * Get the implementation-dependent path for an opened game controller.
+ *
+ * This is the same path as returned by SDL_GameControllerNameForIndex(), but
+ * it takes a controller identifier instead of the (unstable) device index.
+ *
+ * \param gamecontroller a game controller identifier previously returned by
+ *                       SDL_GameControllerOpen()
+ * \returns the implementation dependent path for the game controller, or NULL
+ *          if there is no path or the identifier passed is invalid.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GameControllerPathForIndex
+ */
+extern DECLSPEC const char *SDLCALL SDL_GameControllerPath(SDL_GameController *gamecontroller);
+
+/**
  * Get the type of this currently opened controller
  *
  * This is the same name as returned by SDL_GameControllerTypeForIndex(), but
@@ -415,7 +455,8 @@
  * Set the player index of an opened game controller.
  *
  * \param gamecontroller the game controller object to adjust.
- * \param player_index Player index to assign to this controller.
+ * \param player_index Player index to assign to this controller, or -1 to
+ *                     clear the player index and turn off player LEDs.
  *
  * \since This function is available since SDL 2.0.12.
  */
@@ -458,6 +499,18 @@
 extern DECLSPEC Uint16 SDLCALL SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller);
 
 /**
+ * Get the firmware version of an opened controller, if available.
+ *
+ * If the firmware version isn't available this function returns 0.
+ *
+ * \param gamecontroller the game controller object to query.
+ * \return the controller firmware version, or zero if unavailable.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC Uint16 SDLCALL SDL_GameControllerGetFirmwareVersion(SDL_GameController *gamecontroller);
+
+/**
  * Get the serial number of an opened controller, if available.
  *
  * Returns the serial number of the controller, or NULL if it is not
@@ -995,7 +1048,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_gamecontroller_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_gesture.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_gesture.h
@@ -28,14 +28,14 @@
 #ifndef SDL_gesture_h_
 #define SDL_gesture_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
-#include "SDL_video.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_video.h>
 
-#include "SDL_touch.h"
+#include <SDL2/SDL_touch.h>
 
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -110,7 +110,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_gesture_h_ */
 
--- /dev/null
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_guid.h
@@ -1,0 +1,100 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/**
+ *  \file SDL_guid.h
+ *
+ *  Include file for handling ::SDL_GUID values.
+ */
+
+#ifndef SDL_guid_h_
+#define SDL_guid_h_
+
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+
+#include <SDL2/begin_code.h>
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * An SDL_GUID is a 128-bit identifier for an input device that
+ *   identifies that device across runs of SDL programs on the same
+ *   platform.  If the device is detached and then re-attached to a
+ *   different port, or if the base system is rebooted, the device
+ *   should still report the same GUID.
+ *
+ * GUIDs are as precise as possible but are not guaranteed to
+ *   distinguish physically distinct but equivalent devices.  For
+ *   example, two game controllers from the same vendor with the same
+ *   product ID and revision may have the same GUID.
+ *
+ * GUIDs may be platform-dependent (i.e., the same device may report
+ *   different GUIDs on different operating systems).
+ */
+typedef struct {
+    Uint8 data[16];
+} SDL_GUID;
+
+/* Function prototypes */
+
+/**
+ * Get an ASCII string representation for a given ::SDL_GUID.
+ *
+ * You should supply at least 33 bytes for pszGUID.
+ *
+ * \param guid the ::SDL_GUID you wish to convert to string
+ * \param pszGUID buffer in which to write the ASCII string
+ * \param cbGUID the size of pszGUID
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GUIDFromString
+ */
+extern DECLSPEC void SDLCALL SDL_GUIDToString(SDL_GUID guid, char *pszGUID, int cbGUID);
+
+/**
+ * Convert a GUID string into a ::SDL_GUID structure.
+ *
+ * Performs no error checking. If this function is given a string containing
+ * an invalid GUID, the function will silently succeed, but the GUID generated
+ * will not be useful.
+ *
+ * \param pchGUID string containing an ASCII representation of a GUID
+ * \returns a ::SDL_GUID structure.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GUIDToString
+ */
+extern DECLSPEC SDL_GUID SDLCALL SDL_GUIDFromString(const char *pchGUID);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include <SDL2/close_code.h>
+
+#endif /* SDL_guid_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_haptic.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_haptic.h
@@ -107,11 +107,11 @@
 #ifndef SDL_haptic_h_
 #define SDL_haptic_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
-#include "SDL_joystick.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_joystick.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -1334,7 +1334,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_haptic_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_hidapi.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_hidapi.h
@@ -62,9 +62,9 @@
 #ifndef SDL_hidapi_h_
 #define SDL_hidapi_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -444,7 +444,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_hidapi_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_hints.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_hints.h
@@ -39,9 +39,9 @@
 #ifndef SDL_hints_h_
 #define SDL_hints_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -392,13 +392,14 @@
 #define SDL_HINT_ENABLE_STEAM_CONTROLLERS "SDL_ENABLE_STEAM_CONTROLLERS"
 
 /**
- *  \brief  A variable controlling whether SDL logs all events pushed onto its internal queue.
+ *  \brief  A variable controlling verbosity of the logging of SDL events pushed onto the internal queue.
  *
- *  This variable can be set to the following values:
+ *  This variable can be set to the following values, from least to most verbose:
  *
  *    "0"     - Don't log any events (default)
- *    "1"     - Log all events except mouse and finger motion, which are pretty spammy.
- *    "2"     - Log all events.
+ *    "1"     - Log most events (other than the really spammy ones).
+ *    "2"     - Include mouse and finger motion events.
+ *    "3"     - Include SDL_SysWMEvent events.
  *
  *  This is generally meant to be used to debug SDL itself, but can be useful
  *  for application developers that need better visibility into what is going
@@ -651,18 +652,27 @@
  */
 #define SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE "SDL_JOYSTICK_GAMECUBE_RUMBLE_BRAKE"
 
- /**
-  *  \brief  A variable controlling whether Switch Joy-Cons should be treated the same as Switch Pro Controllers when using the HIDAPI driver.
+/**
+  *  \brief  A variable controlling whether the HIDAPI driver for Nintendo Switch Joy-Cons should be used.
   *
   *  This variable can be set to the following values:
-  *    "0"       - basic Joy-Con support with no analog input (the default)
-  *    "1"       - Joy-Cons treated as half full Pro Controllers with analog inputs and sensors
+  *    "0"       - HIDAPI driver is not used
+  *    "1"       - HIDAPI driver is used
   *
-  *  This does not combine Joy-Cons into a single controller. That's up to the user.
+  *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
   */
 #define SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS "SDL_JOYSTICK_HIDAPI_JOY_CONS"
 
- /**
+/**
+  *  \brief  A variable controlling whether Nintendo Switch Joy-Con controllers will be combined into a single Pro-like controller when using the HIDAPI driver
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - Left and right Joy-Con controllers will not be combined and each will be a mini-gamepad
+  *    "1"       - Left and right Joy-Con controllers will be combined into a single controller (the default)
+  */
+#define SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS "SDL_JOYSTICK_HIDAPI_COMBINE_JOY_CONS"
+
+/**
   *  \brief  A variable controlling whether the HIDAPI driver for Amazon Luna controllers connected via Bluetooth should be used.
   *
   *  This variable can be set to the following values:
@@ -674,6 +684,28 @@
 #define SDL_HINT_JOYSTICK_HIDAPI_LUNA "SDL_JOYSTICK_HIDAPI_LUNA"
 
 /**
+  *  \brief  A variable controlling whether the HIDAPI driver for Nintendo Online classic controllers should be used.
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - HIDAPI driver is not used
+  *    "1"       - HIDAPI driver is used
+  *
+  *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+  */
+#define SDL_HINT_JOYSTICK_HIDAPI_NINTENDO_CLASSIC "SDL_JOYSTICK_HIDAPI_NINTENDO_CLASSIC"
+
+/**
+  *  \brief  A variable controlling whether the HIDAPI driver for NVIDIA SHIELD controllers should be used.
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - HIDAPI driver is not used
+  *    "1"       - HIDAPI driver is used
+  *
+  *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+  */
+#define SDL_HINT_JOYSTICK_HIDAPI_SHIELD "SDL_JOYSTICK_HIDAPI_SHIELD"
+
+/**
  *  \brief  A variable controlling whether the HIDAPI driver for PS4 controllers should be used.
  *
  *  This variable can be set to the following values:
@@ -778,17 +810,37 @@
 #define SDL_HINT_JOYSTICK_HIDAPI_SWITCH "SDL_JOYSTICK_HIDAPI_SWITCH"
 
 /**
- *  \brief  A variable controlling whether the Home button LED should be turned on when a Nintendo Switch controller is opened
+ *  \brief  A variable controlling whether the Home button LED should be turned on when a Nintendo Switch Pro controller is opened
  *
  *  This variable can be set to the following values:
  *    "0"       - home button LED is turned off
  *    "1"       - home button LED is turned on
  *
- *  By default the Home button LED state is not changed.
+ *  By default the Home button LED state is not changed. This hint can also be set to a floating point value between 0.0 and 1.0 which controls the brightness of the Home button LED.
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED "SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED"
 
 /**
+ *  \brief  A variable controlling whether the Home button LED should be turned on when a Nintendo Switch Joy-Con controller is opened
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - home button LED is turned off
+ *    "1"       - home button LED is turned on
+ *
+ *  By default the Home button LED state is not changed. This hint can also be set to a floating point value between 0.0 and 1.0 which controls the brightness of the Home button LED.
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED "SDL_JOYSTICK_HIDAPI_JOYCON_HOME_LED"
+
+/**
+ *  \brief  A variable controlling whether the player LEDs should be lit to indicate which player is associated with a Nintendo Switch controller.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - player LEDs are not enabled
+ *    "1"       - player LEDs are enabled (the default)
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED "SDL_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED"
+
+/**
  *  \brief  A variable controlling whether the HIDAPI driver for XBox controllers should be used.
  *
  *  This variable can be set to the following values:
@@ -799,7 +851,7 @@
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_XBOX   "SDL_JOYSTICK_HIDAPI_XBOX"
 
- /**
+/**
   *  \brief  A variable controlling whether the RAWINPUT joystick drivers should be used for better handling XInput-capable devices.
   *
   *  This variable can be set to the following values:
@@ -808,7 +860,7 @@
   */
 #define SDL_HINT_JOYSTICK_RAWINPUT "SDL_JOYSTICK_RAWINPUT"
 
- /**
+/**
   *  \brief  A variable controlling whether the RAWINPUT driver should pull correlated data from XInput.
   *
   *  This variable can be set to the following values:
@@ -821,7 +873,7 @@
   */
 #define SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT   "SDL_JOYSTICK_RAWINPUT_CORRELATE_XINPUT"
 
- /**
+/**
   *  \brief  A variable controlling whether the ROG Chakram mice should show up as joysticks
   *
   *  This variable can be set to the following values:
@@ -830,7 +882,7 @@
   */
 #define SDL_HINT_JOYSTICK_ROG_CHAKRAM "SDL_JOYSTICK_ROG_CHAKRAM"
 
- /**
+/**
   *  \brief  A variable controlling whether a separate thread should be used
   *          for handling joystick detection and raw input messages on Windows
   *
@@ -864,7 +916,7 @@
  */
 #define SDL_HINT_KMSDRM_REQUIRE_DRM_MASTER      "SDL_KMSDRM_REQUIRE_DRM_MASTER"
 
- /**
+/**
   *  \brief  A comma separated list of devices to open as joysticks
   *
   *  This variable is currently only used by the Linux joystick driver.
@@ -871,7 +923,25 @@
   */
 #define SDL_HINT_JOYSTICK_DEVICE "SDL_JOYSTICK_DEVICE"
 
- /**
+/**
+  *  \brief  A variable controlling whether joysticks on Linux will always treat 'hat' axis inputs (ABS_HAT0X - ABS_HAT3Y) as 8-way digital hats without checking whether they may be analog.
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - Only map hat axis inputs to digital hat outputs if the input axes appear to actually be digital (the default)
+  *    "1"       - Always handle the input axes numbered ABS_HAT0X to ABS_HAT3Y as digital hats
+  */
+#define SDL_HINT_LINUX_DIGITAL_HATS "SDL_LINUX_DIGITAL_HATS"
+
+/**
+  *  \brief  A variable controlling whether digital hats on Linux will apply deadzones to their underlying input axes or use unfiltered values.
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - Return digital hat values based on unfiltered input axis values
+  *    "1"       - Return digital hat values with deadzones on the input axes taken into account (the default)
+  */
+#define SDL_HINT_LINUX_HAT_DEADZONES "SDL_LINUX_HAT_DEADZONES"
+
+/**
   *  \brief  A variable controlling whether to use the classic /dev/input/js* joystick interface or the newer /dev/input/event* joystick interface on Linux
   *
   *  This variable can be set to the following values:
@@ -882,7 +952,7 @@
   */
 #define SDL_HINT_LINUX_JOYSTICK_CLASSIC "SDL_LINUX_JOYSTICK_CLASSIC"
 
- /**
+/**
   *  \brief  A variable controlling whether joysticks on Linux adhere to their HID-defined deadzones or return unfiltered values.
   *
   *  This variable can be set to the following values:
@@ -908,6 +978,24 @@
 #define SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK "SDL_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK"
 
 /**
+ *  \brief   A variable controlling whether dispatching OpenGL context updates should block the dispatching thread until the main thread finishes processing
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Dispatching OpenGL context updates will block the dispatching thread until the main thread finishes processing (default).
+ *    "1"       - Dispatching OpenGL context updates will allow the dispatching thread to continue execution.
+ *
+ *  Generally you want the default, but if you have OpenGL code in a background thread on a Mac, and the main thread
+ *  hangs because it's waiting for that background thread, but that background thread is also hanging because it's
+ *  waiting for the main thread to do an update, this might fix your issue.
+ *
+ *  This hint only applies to macOS.
+ *
+ *  This hint is available since SDL 2.24.0.
+ *
+ */
+#define SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH "SDL_MAC_OPENGL_ASYNC_DISPATCH"
+
+/**
  *  \brief  A variable setting the double click radius, in pixels.
  */
 #define SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS    "SDL_MOUSE_DOUBLE_CLICK_RADIUS"
@@ -977,6 +1065,17 @@
 #define SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE    "SDL_MOUSE_RELATIVE_SPEED_SCALE"
 
 /**
+ *  \brief  A variable controlling whether a motion event should be generated for mouse warping in relative mode.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Warping the mouse will not generate a motion event in relative mode
+ *    "1"       - Warping the mouse will generate a motion event in relative mode
+ *
+ *  By default warping the mouse will not generate motion events in relative mode. This avoids the application having to filter out large relative motion due to warping.
+ */
+#define SDL_HINT_MOUSE_RELATIVE_WARP_MOTION  "SDL_MOUSE_RELATIVE_WARP_MOTION"
+
+/**
  *  \brief  A variable controlling whether mouse events should generate synthetic touch events
  *
  *  This variable can be set to the following values:
@@ -1181,6 +1280,8 @@
  *
  *  This variable is case insensitive and can be set to the following values:
  *    "direct3d"
+ *    "direct3d11"
+ *    "direct3d12"
  *    "opengl"
  *    "opengles2"
  *    "opengles"
@@ -1237,7 +1338,7 @@
  */
 #define SDL_HINT_RENDER_VSYNC               "SDL_RENDER_VSYNC"
 
- /**
+/**
  * \brief A variable to control whether the return key on the soft keyboard
  *        should hide the soft keyboard on Android and iOS.
  *
@@ -1450,9 +1551,7 @@
  *                SDL_WINDOW_RESIZABLE windows will offer the "fullscreen"
  *                button on their titlebars).
  *
- *  The default value is "1". Spaces are disabled regardless of this hint if
- *   the OS isn't at least Mac OS X Lion (10.7). This hint must be set before
- *   any windows are created.
+ *  The default value is "1". This hint must be set before any windows are created.
  */
 #define SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES    "SDL_VIDEO_MAC_FULLSCREEN_SPACES"
 
@@ -1490,6 +1589,21 @@
 #define SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR "SDL_VIDEO_WAYLAND_PREFER_LIBDECOR"
 
 /**
+ *  \brief  A variable controlling whether video mode emulation is enabled under Wayland.
+ *
+ *  When this hint is set, a standard set of emulated CVT video modes will be exposed for use by the application.
+ *  If it is disabled, the only modes exposed will be the logical desktop size and, in the case of a scaled
+ *  desktop, the native display resolution.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Video mode emulation is disabled.
+ *    "1"       - Video mode emulation is enabled.
+ *
+ *  By default video mode emulation is enabled.
+ */
+#define SDL_HINT_VIDEO_WAYLAND_MODE_EMULATION "SDL_VIDEO_WAYLAND_MODE_EMULATION"
+
+/**
 *  \brief  A variable that is the address of another SDL_Window* (as a hex string formatted with "%p").
 *  
 *  If this hint is set before SDL_CreateWindowFrom() and the SDL_Window* it is set to has
@@ -1590,13 +1704,11 @@
 #define SDL_HINT_VIDEO_X11_WINDOW_VISUALID      "SDL_VIDEO_X11_WINDOW_VISUALID"
 
 /**
- *  \brief  A variable controlling whether the X11 Xinerama extension should be used.
+ *  \brief  A no-longer-used variable controlling whether the X11 Xinerama extension should be used.
  *
- *  This variable can be set to the following values:
- *    "0"       - Disable Xinerama
- *    "1"       - Enable Xinerama
- *
- *  By default SDL will use Xinerama if it is available.
+ * Before SDL 2.0.24, this would let apps and users disable Xinerama support on X11.
+ *  Now SDL never uses Xinerama, and does not check for this hint at all.
+ *  The preprocessor define is left here for source compatibility.
  */
 #define SDL_HINT_VIDEO_X11_XINERAMA         "SDL_VIDEO_X11_XINERAMA"
 
@@ -1607,18 +1719,16 @@
  *    "0"       - Disable XRandR
  *    "1"       - Enable XRandR
  *
- *  By default SDL will not use XRandR because of window manager issues.
+ *  By default SDL will use XRandR.
  */
 #define SDL_HINT_VIDEO_X11_XRANDR           "SDL_VIDEO_X11_XRANDR"
 
 /**
- *  \brief  A variable controlling whether the X11 VidMode extension should be used.
+ *  \brief  A no-longer-used variable controlling whether the X11 VidMode extension should be used.
  *
- *  This variable can be set to the following values:
- *    "0"       - Disable XVidMode
- *    "1"       - Enable XVidMode
- *
- *  By default SDL will use XVidMode if it is available.
+ * Before SDL 2.0.24, this would let apps and users disable XVidMode support on X11.
+ *  Now SDL never uses XVidMode, and does not check for this hint at all.
+ *  The preprocessor define is left here for source compatibility.
  */
 #define SDL_HINT_VIDEO_X11_XVIDMODE         "SDL_VIDEO_X11_XVIDMODE"
 
@@ -1779,6 +1889,57 @@
 #define SDL_HINT_WINDOWS_USE_D3D9EX "SDL_WINDOWS_USE_D3D9EX"
 
 /**
+ * \brief Controls whether SDL will declare the process to be DPI aware.
+ *
+ *  This hint must be set before initializing the video subsystem.
+ *
+ *  The main purpose of declaring DPI awareness is to disable OS bitmap scaling of SDL windows on monitors with 
+ *  a DPI scale factor.
+ * 
+ *  This hint is equivalent to requesting DPI awareness via external means (e.g. calling SetProcessDpiAwarenessContext)
+ *  and does not cause SDL to use a virtualized coordinate system, so it will generally give you 1 SDL coordinate = 1 pixel
+ *  even on high-DPI displays.
+ * 
+ *  For more information, see:
+ *  https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
+ * 
+ *  This variable can be set to the following values:
+ *    ""             - Do not change the DPI awareness (default).
+ *    "unaware"      - Declare the process as DPI unaware. (Windows 8.1 and later).
+ *    "system"       - Request system DPI awareness. (Vista and later).
+ *    "permonitor"   - Request per-monitor DPI awareness. (Windows 8.1 and later).
+ *    "permonitorv2" - Request per-monitor V2 DPI awareness. (Windows 10, version 1607 and later).
+ *                     The most visible difference from "permonitor" is that window title bar will be scaled
+ *                     to the visually correct size when dragging between monitors with different scale factors.
+ *                     This is the preferred DPI awareness level.
+ *
+ * If the requested DPI awareness is not available on the currently running OS, SDL will try to request the best
+ * available match.
+ */
+#define SDL_HINT_WINDOWS_DPI_AWARENESS "SDL_WINDOWS_DPI_AWARENESS"
+
+/**
+ * \brief Uses DPI-scaled points as the SDL coordinate system on Windows.
+ * 
+ *  This changes the SDL coordinate system units to be DPI-scaled points, rather than pixels everywhere.
+ *  This means windows will be appropriately sized, even when created on high-DPI displays with scaling.
+ * 
+ *  e.g. requesting a 640x480 window from SDL, on a display with 125% scaling in Windows display settings,
+ *  will create a window with an 800x600 client area (in pixels).
+ *
+ *  Setting this to "1" implicitly requests process DPI awareness (setting SDL_WINDOWS_DPI_AWARENESS is unnecessary),
+ *  and forces SDL_WINDOW_ALLOW_HIGHDPI on all windows.
+ * 
+ *  This variable can be set to the following values:
+ *    "0"       - SDL coordinates equal Windows coordinates. No automatic window resizing when dragging
+ *                between monitors with different scale factors (unless this is performed by
+ *                Windows itself, which is the case when the process is DPI unaware).
+ *    "1"       - SDL coordinates are in DPI-scaled points. Automatically resize windows as needed on
+ *                displays with non-100% scale factors.
+ */
+#define SDL_HINT_WINDOWS_DPI_SCALING "SDL_WINDOWS_DPI_SCALING"
+
+/**
  *  \brief  A variable controlling whether the window frame and title bar are interactive when the cursor is hidden 
  *
  *  This variable can be set to the following values:
@@ -1920,6 +2081,15 @@
  */
 #define SDL_HINT_XINPUT_ENABLED "SDL_XINPUT_ENABLED"
 
+ /**
+  *  \brief  A variable that lets you disable the detection and use of DirectInput gamepad devices
+  *
+  *  The variable can be set to the following values:
+  *    "0"       - Disable DirectInput detection (only uses XInput)
+  *    "1"       - Enable DirectInput detection (the default)
+  */
+#define SDL_HINT_DIRECTINPUT_ENABLED "SDL_DIRECTINPUT_ENABLED"
+
 /**
  *  \brief  A variable that causes SDL to use the old axis and button mapping for XInput devices.
  *
@@ -2039,8 +2209,44 @@
  */
 #define SDL_HINT_AUDIODRIVER "SDL_AUDIODRIVER"
 
+/**
+ *  \brief  A variable that decides what KMSDRM device to use.
+ *
+ *  Internally, SDL might open something like "/dev/dri/cardNN" to
+ *  access KMSDRM functionality, where "NN" is a device index number.
+ *
+ *  SDL makes a guess at the best index to use (usually zero), but the
+ *  app or user can set this hint to a number between 0 and 99 to
+ *  force selection.
+ *
+ *  This hint is available since SDL 2.24.0.
+ */
+#define SDL_HINT_KMSDRM_DEVICE_INDEX "SDL_KMSDRM_DEVICE_INDEX"
 
+
 /**
+ *  \brief  A variable that treats trackpads as touch devices.
+ *
+ *  On macOS (and possibly other platforms in the future), SDL will report
+ *  touches on a trackpad as mouse input, which is generally what users
+ *  expect from this device; however, these are often actually full
+ *  multitouch-capable touch devices, so it might be preferable to some apps
+ *  to treat them as such.
+ *
+ *  Setting this hint to true will make the trackpad input report as a
+ *  multitouch device instead of a mouse. The default is false.
+ *
+ *  Note that most platforms don't support this hint. As of 2.24.0, it
+ *  only supports MacBooks' trackpads on macOS. Others may follow later.
+ *
+ *  This hint is checked during SDL_Init and can not be changed after.
+ *
+ *  This hint is available since SDL 2.24.0.
+ */
+#define SDL_HINT_TRACKPAD_IS_TOUCH_ONLY "SDL_TRACKPAD_IS_TOUCH_ONLY"
+
+
+/**
  *  \brief  An enumeration of hint priorities
  */
 typedef enum
@@ -2092,6 +2298,23 @@
                                              const char *value);
 
 /**
+ * Reset a hint to the default value.
+ *
+ * This will reset a hint to the value of the environment variable, or NULL if
+ * the environment isn't set. Callbacks will be called normally with this
+ * change.
+ *
+ * \param name the hint to set
+ * \returns SDL_TRUE if the hint was set, SDL_FALSE otherwise.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GetHint
+ * \sa SDL_SetHint
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_ResetHint(const char *name);
+
+/**
  * Get the value of a hint.
  *
  * \param name the hint to query
@@ -2175,7 +2398,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_hints_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_joystick.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_joystick.h
@@ -41,10 +41,11 @@
 #ifndef SDL_joystick_h_
 #define SDL_joystick_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_guid.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -69,9 +70,7 @@
 typedef struct _SDL_Joystick SDL_Joystick;
 
 /* A structure that encodes the stable unique id for a joystick device */
-typedef struct {
-    Uint8 data[16];
-} SDL_JoystickGUID;
+typedef SDL_GUID SDL_JoystickGUID;
 
 /**
  * This is a unique ID for a joystick for the time it is connected to the system,
@@ -153,6 +152,7 @@
  * \since This function is available since SDL 2.0.0.
  *
  * \sa SDL_JoystickName
+ * \sa SDL_JoystickPath
  * \sa SDL_JoystickOpen
  */
 extern DECLSPEC int SDLCALL SDL_NumJoysticks(void);
@@ -175,6 +175,23 @@
 extern DECLSPEC const char *SDLCALL SDL_JoystickNameForIndex(int device_index);
 
 /**
+ * Get the implementation dependent path of a joystick.
+ *
+ * This can be called before any joysticks are opened.
+ *
+ * \param device_index the index of the joystick to query (the N'th joystick
+ *                     on the system)
+ * \returns the path of the selected joystick. If no path can be found, this
+ *          function returns NULL; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_JoystickPath
+ * \sa SDL_JoystickOpen
+ */
+extern DECLSPEC const char *SDLCALL SDL_JoystickPathForIndex(int device_index);
+
+/**
  * Get the player index of a joystick, or -1 if it's not available This can be
  * called before any joysticks are opened.
  *
@@ -331,6 +348,54 @@
                                                       int nhats);
 
 /**
+ * The structure that defines an extended virtual joystick description
+ *
+ * The caller must zero the structure and then initialize the version with `SDL_VIRTUAL_JOYSTICK_DESC_VERSION` before passing it to SDL_JoystickAttachVirtualEx()
+ *  All other elements of this structure are optional and can be left 0.
+ *
+ * \sa SDL_JoystickAttachVirtualEx
+ */
+typedef struct SDL_VirtualJoystickDesc
+{
+    Uint16 version;     /**< `SDL_VIRTUAL_JOYSTICK_DESC_VERSION` */
+    Uint16 type;        /**< `SDL_JoystickType` */
+    Uint16 naxes;       /**< the number of axes on this joystick */
+    Uint16 nbuttons;    /**< the number of buttons on this joystick */
+    Uint16 nhats;       /**< the number of hats on this joystick */
+    Uint16 vendor_id;   /**< the USB vendor ID of this joystick */
+    Uint16 product_id;  /**< the USB product ID of this joystick */
+    Uint16 padding;     /**< unused */
+    Uint32 button_mask; /**< A mask of which buttons are valid for this controller
+                             e.g. (1 << SDL_CONTROLLER_BUTTON_A) */
+    Uint32 axis_mask;   /**< A mask of which axes are valid for this controller
+                             e.g. (1 << SDL_CONTROLLER_AXIS_LEFTX) */
+    const char *name;   /**< the name of the joystick */
+
+    void *userdata;     /**< User data pointer passed to callbacks */
+    void (SDLCALL *Update)(void *userdata); /**< Called when the joystick state should be updated */
+    void (SDLCALL *SetPlayerIndex)(void *userdata, int player_index); /**< Called when the player index is set */
+    int (SDLCALL *Rumble)(void *userdata, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble); /**< Implements SDL_JoystickRumble() */
+    int (SDLCALL *RumbleTriggers)(void *userdata, Uint16 left_rumble, Uint16 right_rumble); /**< Implements SDL_JoystickRumbleTriggers() */
+    int (SDLCALL *SetLED)(void *userdata, Uint8 red, Uint8 green, Uint8 blue); /**< Implements SDL_JoystickSetLED() */
+    int (SDLCALL *SendEffect)(void *userdata, const void *data, int size); /**< Implements SDL_JoystickSendEffect() */
+
+} SDL_VirtualJoystickDesc;
+
+/**
+ * \brief The current version of the SDL_VirtualJoystickDesc structure
+ */
+#define SDL_VIRTUAL_JOYSTICK_DESC_VERSION   1
+
+/**
+ * Attach a new virtual joystick with extended properties.
+ *
+ * \returns the joystick's device index, or -1 if an error occurred.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickAttachVirtualEx(const SDL_VirtualJoystickDesc *desc);
+
+/**
  * Detach a virtual joystick.
  *
  * \param device_index a value previously returned from
@@ -420,6 +485,19 @@
 extern DECLSPEC const char *SDLCALL SDL_JoystickName(SDL_Joystick *joystick);
 
 /**
+ * Get the implementation dependent path of a joystick.
+ *
+ * \param joystick the SDL_Joystick obtained from SDL_JoystickOpen()
+ * \returns the path of the selected joystick. If no path can be found, this
+ *          function returns NULL; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_JoystickPathForIndex
+ */
+extern DECLSPEC const char *SDLCALL SDL_JoystickPath(SDL_Joystick *joystick);
+
+/**
  * Get the player index of an opened joystick.
  *
  * For XInput controllers this returns the XInput user index. Many joysticks
@@ -436,7 +514,8 @@
  * Set the player index of an opened joystick.
  *
  * \param joystick the SDL_Joystick obtained from SDL_JoystickOpen()
- * \param player_index the player index to set.
+ * \param player_index Player index to assign to this joystick, or -1 to clear
+ *                     the player index and turn off player LEDs.
  *
  * \since This function is available since SDL 2.0.12.
  */
@@ -496,6 +575,19 @@
 extern DECLSPEC Uint16 SDLCALL SDL_JoystickGetProductVersion(SDL_Joystick *joystick);
 
 /**
+ * Get the firmware version of an opened joystick, if available.
+ *
+ * If the firmware version isn't available this function returns 0.
+ *
+ * \param joystick the SDL_Joystick obtained from SDL_JoystickOpen()
+ * \returns the firmware version of the selected joystick, or 0 if
+ *          unavailable.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC Uint16 SDLCALL SDL_JoystickGetFirmwareVersion(SDL_Joystick *joystick);
+
+/**
  * Get the serial number of an opened joystick, if available.
  *
  * Returns the serial number of the joystick, or NULL if it is not available.
@@ -939,7 +1031,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_joystick_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_keyboard.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_keyboard.h
@@ -28,12 +28,12 @@
 #ifndef SDL_keyboard_h_
 #define SDL_keyboard_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
-#include "SDL_keycode.h"
-#include "SDL_video.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_keycode.h>
+#include <SDL2/SDL_video.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -90,10 +90,22 @@
  * \since This function is available since SDL 2.0.0.
  *
  * \sa SDL_PumpEvents
+ * \sa SDL_ResetKeyboard
  */
 extern DECLSPEC const Uint8 *SDLCALL SDL_GetKeyboardState(int *numkeys);
 
 /**
+ * Clear the state of the keyboard
+ *
+ * This function will generate key up events for all pressed keys.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GetKeyboardState
+ */
+extern DECLSPEC void SDLCALL SDL_ResetKeyboard(void);
+
+/**
  * Get the current key modifier state for the keyboard.
  *
  * \returns an OR'd combination of the modifier keys for the keyboard. See
@@ -288,7 +300,11 @@
 /**
  * Set the rectangle used to type Unicode text inputs.
  *
- * Note: If you want use system native IME window, try to set hint
+ * To start text input in a given location, this function is intended to be
+ * called before SDL_StartTextInput, although some platforms support moving
+ * the rectangle even while text input (and a composition) is active.
+ *
+ * Note: If you want to use the system native IME window, try setting hint
  * **SDL_HINT_IME_SHOW_UI** to **1**, otherwise this function won't give you
  * any feedback.
  *
@@ -299,7 +315,7 @@
  *
  * \sa SDL_StartTextInput
  */
-extern DECLSPEC void SDLCALL SDL_SetTextInputRect(SDL_Rect *rect);
+extern DECLSPEC void SDLCALL SDL_SetTextInputRect(const SDL_Rect *rect);
 
 /**
  * Check whether the platform has screen keyboard support.
@@ -330,7 +346,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_keyboard_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_keycode.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_keycode.h
@@ -28,8 +28,8 @@
 #ifndef SDL_keycode_h_
 #define SDL_keycode_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_scancode.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_scancode.h>
 
 /**
  *  \brief The SDL virtual key representation.
@@ -318,7 +318,12 @@
     SDLK_APP2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_APP2),
 
     SDLK_AUDIOREWIND = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOREWIND),
-    SDLK_AUDIOFASTFORWARD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOFASTFORWARD)
+    SDLK_AUDIOFASTFORWARD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOFASTFORWARD),
+
+    SDLK_SOFTLEFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SOFTLEFT),
+    SDLK_SOFTRIGHT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SOFTRIGHT),
+    SDLK_CALL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CALL),
+    SDLK_ENDCALL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_ENDCALL)
 } SDL_KeyCode;
 
 /**
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_loadso.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_loadso.h
@@ -41,10 +41,10 @@
 #ifndef SDL_loadso_h_
 #define SDL_loadso_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -108,7 +108,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_loadso_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_locale.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_locale.h
@@ -28,10 +28,10 @@
 #ifndef _SDL_locale_h
 #define _SDL_locale_h
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 /* *INDENT-OFF* */
@@ -96,7 +96,7 @@
 }
 /* *INDENT-ON* */
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* _SDL_locale_h */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_log.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_log.h
@@ -37,9 +37,9 @@
 #ifndef SDL_log_h_
 #define SDL_log_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -47,9 +47,9 @@
 
 
 /**
- *  \brief The maximum size of a log message
+ *  \brief The maximum size of a log message prior to SDL 2.0.24
  *
- *  Messages longer than the maximum size will be truncated
+ *  As of 2.0.24 there is no limit to the length of SDL log messages.
  */
 #define SDL_MAX_LOG_MESSAGE 4096
 
@@ -397,7 +397,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_log_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_main.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_main.h
@@ -22,7 +22,7 @@
 #ifndef SDL_main_h_
 #define SDL_main_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
 /**
  *  \file SDL_main.h
@@ -51,6 +51,15 @@
 */
 #define SDL_MAIN_NEEDED
 
+#elif defined(__GDK__)
+/* On GDK, SDL provides a main function that initializes the game runtime.
+
+   Please note that #include'ing SDL_main.h is not enough to get a main()
+   function working. You must either link against SDL2main or, if not possible,
+   call the SDL_GDKRunApp function from your entry point.
+*/
+#define SDL_MAIN_NEEDED
+
 #elif defined(__IPHONEOS__)
 /* On iOS SDL provides a main function that creates an application delegate
    and starts the iOS application run loop.
@@ -92,6 +101,13 @@
  */
 #define SDL_MAIN_AVAILABLE
 
+#elif defined(__PS2__)
+#define SDL_MAIN_AVAILABLE
+
+#define SDL_PS2_SKIP_IOP_RESET() \
+   void reset_IOP(); \
+   void reset_IOP() {}
+
 #endif
 #endif /* SDL_MAIN_HANDLED */
 
@@ -118,7 +134,7 @@
 #define main    SDL_main
 #endif
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -145,7 +161,7 @@
  */
 extern DECLSPEC void SDLCALL SDL_SetMainReady(void);
 
-#ifdef __WIN32__
+#if defined(__WIN32__) || defined(__GDK__)
 
 /**
  * Register a win32 window class for SDL's use.
@@ -189,7 +205,7 @@
  */
 extern DECLSPEC void SDLCALL SDL_UnregisterApp(void);
 
-#endif /* __WIN32__ */
+#endif /* defined(__WIN32__) || defined(__GDK__) */
 
 
 #ifdef __WINRT__
@@ -224,11 +240,26 @@
 
 #endif /* __IPHONEOS__ */
 
+#ifdef __GDK__
 
+/**
+ * Initialize and launch an SDL GDK application.
+ *
+ * \param mainFunction the SDL app's C-style main(), an SDL_main_func
+ * \param reserved reserved for future use; should be NULL
+ * \returns 0 on success or -1 on failure; call SDL_GetError() to retrieve
+ *          more information on the failure.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC int SDLCALL SDL_GDKRunApp(SDL_main_func mainFunction, void *reserved);
+
+#endif /* __GDK__ */
+
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_main_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_messagebox.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_messagebox.h
@@ -22,10 +22,10 @@
 #ifndef SDL_messagebox_h_
 #define SDL_messagebox_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_video.h"      /* For SDL_Window */
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_video.h>      /* For SDL_Window */
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -186,7 +186,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_messagebox_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_metal.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_metal.h
@@ -28,9 +28,9 @@
 #ifndef SDL_metal_h_
 #define SDL_metal_h_
 
-#include "SDL_video.h"
+#include <SDL2/SDL_video.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -108,6 +108,6 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_metal_h_ */
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_misc.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_misc.h
@@ -28,9 +28,9 @@
 #ifndef SDL_misc_h_
 #define SDL_misc_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
@@ -72,7 +72,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_misc_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_mouse.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_mouse.h
@@ -28,11 +28,11 @@
 #ifndef SDL_mouse_h_
 #define SDL_mouse_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
-#include "SDL_video.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_video.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -154,7 +154,9 @@
 /**
  * Move the mouse cursor to the given position within the window.
  *
- * This function generates a mouse motion event.
+ * This function generates a mouse motion event if relative mode is not
+ * enabled. If relative mode is enabled, you can force mouse events for the
+ * warp by setting the SDL_HINT_MOUSE_RELATIVE_WARP_MOTION hint.
  *
  * Note that this function will appear to succeed, but not actually move the
  * mouse when used over Microsoft Remote Desktop.
@@ -245,6 +247,15 @@
  * While capturing is enabled, the current window will have the
  * `SDL_WINDOW_MOUSE_CAPTURE` flag set.
  *
+ * Please note that as of SDL 2.0.22, SDL will attempt to "auto capture" the
+ * mouse while the user is pressing a button; this is to try and make mouse
+ * behavior more consistent between platforms, and deal with the common case
+ * of a user dragging the mouse outside of the window. This means that if you
+ * are calling SDL_CaptureMouse() only to deal with this situation, you no
+ * longer have to (although it is safe to do so). If this causes problems for
+ * your app, you can disable auto capture by setting the
+ * `SDL_HINT_MOUSE_AUTO_CAPTURE` hint to zero.
+ *
  * \param enabled SDL_TRUE to enable capturing, SDL_FALSE to disable.
  * \returns 0 on success or -1 if not supported; call SDL_GetError() for more
  *          information.
@@ -447,7 +458,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_mouse_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_mutex.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_mutex.h
@@ -28,10 +28,10 @@
  *  Functions to provide thread synchronization primitives.
  */
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -464,7 +464,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_mutex_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengl.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengl.h
@@ -35,7 +35,7 @@
 #ifndef SDL_opengl_h_
 #define SDL_opengl_h_
 
-#include "SDL_config.h"
+#include <SDL2/SDL_config.h>
 
 #ifndef __IPHONEOS__  /* No OpenGL on iOS. */
 
@@ -69,7 +69,7 @@
 #define __gl_h_
 
 #if defined(USE_MGL_NAMESPACE)
-#include "gl_mangle.h"
+#include <SDL2/gl_mangle.h>
 #endif
 
 
@@ -2102,7 +2102,7 @@
  * defined in gl.h).  Otherwise, extensions will be included from glext.h.
  */
 #if !defined(NO_SDL_GLEXT) && !defined(GL_GLEXT_LEGACY)
-#include "SDL_opengl_glext.h"
+#include <SDL2/SDL_opengl_glext.h>
 #endif  /* GL_GLEXT_LEGACY */
 
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengles.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengles.h
@@ -24,7 +24,7 @@
  *
  *  This is a simple file to encapsulate the OpenGL ES 1.X API headers.
  */
-#include "SDL_config.h"
+#include <SDL2/SDL_config.h>
 
 #ifdef __IPHONEOS__
 #include <OpenGLES/ES1/gl.h>
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengles2.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengles2.h
@@ -24,7 +24,7 @@
  *
  *  This is a simple file to encapsulate the OpenGL ES 2.0 API headers.
  */
-#include "SDL_config.h"
+#include <SDL2/SDL_config.h>
 
 #if !defined(_MSC_VER) && !defined(SDL_USE_BUILTIN_OPENGL_DEFINITIONS)
 
@@ -40,10 +40,10 @@
 #else /* _MSC_VER */
 
 /* OpenGL ES2 headers for Visual Studio */
-#include "SDL_opengles2_khrplatform.h"
-#include "SDL_opengles2_gl2platform.h"
-#include "SDL_opengles2_gl2.h"
-#include "SDL_opengles2_gl2ext.h"
+#include <SDL2/SDL_opengles2_khrplatform.h>
+#include <SDL2/SDL_opengles2_gl2platform.h>
+#include <SDL2/SDL_opengles2_gl2.h>
+#include <SDL2/SDL_opengles2_gl2ext.h>
 
 #endif /* _MSC_VER */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_pixels.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_pixels.h
@@ -28,10 +28,10 @@
 #ifndef SDL_pixels_h_
 #define SDL_pixels_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_endian.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_endian.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -637,7 +637,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_pixels_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_platform.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_platform.h
@@ -65,11 +65,15 @@
 #undef __LINUX__ /* do we need to do this? */
 #define __ANDROID__ 1
 #endif
+#if defined(__NGAGE__)
+#undef __NGAGE__
+#define __NGAGE__ 1
+#endif
 
 #if defined(__APPLE__)
 /* lets us know what version of Mac OS X we're compiling on */
-#include "AvailabilityMacros.h"
-#include "TargetConditionals.h"
+#include <AvailabilityMacros.h>
+#include <TargetConditionals.h>
 
 /* Fix building with older SDKs that don't define these
    See this for more information:
@@ -104,9 +108,9 @@
 /* if not compiling for iOS */
 #undef __MACOSX__
 #define __MACOSX__  1
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
-# error SDL for Mac OS X only supports deploying on 10.6 and above.
-#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+# error SDL for Mac OS X only supports deploying on 10.7 and above.
+#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1070 */
 #endif /* TARGET_OS_IPHONE */
 #endif /* defined(__APPLE__) */
 
@@ -140,7 +144,7 @@
 #endif
 
 #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
-/* Try to find out if we're compiling for WinRT or non-WinRT */
+/* Try to find out if we're compiling for WinRT, GDK or non-WinRT/GDK */
 #if defined(_MSC_VER) && defined(__has_include)
 #if __has_include(<winapifamily.h>)
 #define HAVE_WINAPIFAMILY_H 1
@@ -165,6 +169,15 @@
 #if WINAPI_FAMILY_WINRT
 #undef __WINRT__
 #define __WINRT__ 1
+#elif defined(_GAMING_DESKTOP) /* GDK project configuration always defines _GAMING_XXX */
+#undef __WINGDK__
+#define __WINGDK__ 1
+#elif defined(_GAMING_XBOX_XBOXONE)
+#undef __XBOXONE__
+#define __XBOXONE__ 1
+#elif defined(_GAMING_XBOX_SCARLETT)
+#undef __XBOXSERIES__
+#define __XBOXSERIES__ 1
 #else
 #undef __WINDOWS__
 #define __WINDOWS__ 1
@@ -175,10 +188,18 @@
 #undef __WIN32__
 #define __WIN32__ 1
 #endif
+/* This is to support generic "any GDK" separate from a platform-specific GDK */
+#if defined(__WINGDK__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
+#undef __GDK__
+#define __GDK__ 1
+#endif
 #if defined(__PSP__)
 #undef __PSP__
 #define __PSP__ 1
 #endif
+#if defined(PS2)
+#define __PS2__ 1
+#endif
 
 /* The NACL compiler defines __native_client__ and __pnacl__
  * Ref: http://www.chromium.org/nativeclient/pnacl/stability-of-the-pnacl-bitcode-abi
@@ -200,7 +221,7 @@
 #define __VITA__ 1
 #endif
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -228,7 +249,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_platform_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_power.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_power.h
@@ -28,9 +28,9 @@
  *  Header for the SDL power management routines.
  */
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -81,7 +81,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_power_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_quit.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_quit.h
@@ -28,8 +28,8 @@
 #ifndef SDL_quit_h_
 #define SDL_quit_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
 
 /**
  *  \file SDL_quit.h
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_rect.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_rect.h
@@ -28,12 +28,12 @@
 #ifndef SDL_rect_h_
 #define SDL_rect_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
-#include "SDL_pixels.h"
-#include "SDL_rwops.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_pixels.h>
+#include <SDL2/SDL_rwops.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -252,10 +252,10 @@
 SDL_FORCE_INLINE SDL_bool SDL_FRectEqualsEpsilon(const SDL_FRect *a, const SDL_FRect *b, const float epsilon)
 {
     return (a && b && ((a == b) ||
-            ((SDL_fabs(a->x - b->x) <= epsilon) &&
-            (SDL_fabs(a->y - b->y) <= epsilon) &&
-            (SDL_fabs(a->w - b->w) <= epsilon) &&
-            (SDL_fabs(a->h - b->h) <= epsilon))))
+            ((SDL_fabsf(a->x - b->x) <= epsilon) &&
+            (SDL_fabsf(a->y - b->y) <= epsilon) &&
+            (SDL_fabsf(a->w - b->w) <= epsilon) &&
+            (SDL_fabsf(a->h - b->h) <= epsilon))))
             ? SDL_TRUE : SDL_FALSE;
 }
 
@@ -369,7 +369,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_rect_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_render.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_render.h
@@ -48,11 +48,11 @@
 #ifndef SDL_render_h_
 #define SDL_render_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_rect.h"
-#include "SDL_video.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_rect.h>
+#include <SDL2/SDL_video.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -825,10 +825,14 @@
 /**
  * Get device independent resolution for rendering.
  *
- * This may return 0 for `w` and `h` if the SDL_Renderer has never had its
- * logical size set by SDL_RenderSetLogicalSize() and never had a render
- * target set.
+ * When using the main rendering target (eg no target texture is set): this
+ * may return 0 for `w` and `h` if the SDL_Renderer has never had its logical
+ * size set by SDL_RenderSetLogicalSize(). Otherwise it returns the logical
+ * width and height.
  *
+ * When using a target texture: Never return 0 for `w` and `h` at first. Then
+ * it returns the logical width and height that are set.
+ *
  * \param renderer a rendering context
  * \param w an int to be filled with the width
  * \param h an int to be filled with the height
@@ -1000,7 +1004,7 @@
  * and logical renderer size set
  *
  * \param renderer the renderer from which the logical coordinates should be
- *                 calcualted
+ *                 calculated
  * \param windowX the real X coordinate in the window
  * \param windowY the real Y coordinate in the window
  * \param logicalX the pointer filled with the logical x coordinate
@@ -1017,19 +1021,23 @@
                                                             int windowX, int windowY, 
                                                             float *logicalX, float *logicalY);
                                                   
-                                                  /**
- * Get real coordinates of point in window when given logical coordinates of point in renderer.
- * Logical coordinates will differ from real coordinates when render is scaled and logical renderer size set
- * 
- * \param renderer the renderer from which the window coordinates should be calculated
+
+/**
+ * Get real coordinates of point in window when given logical coordinates of
+ * point in renderer.
+ *
+ * Logical coordinates will differ from real coordinates when render is scaled
+ * and logical renderer size set
+ *
+ * \param renderer the renderer from which the window coordinates should be
+ *                 calculated
  * \param logicalX the logical x coordinate
  * \param logicalY the logical y coordinate
  * \param windowX the pointer filled with the real X coordinate in the window
  * \param windowY the pointer filled with the real Y coordinate in the window
- 
- *  
+ *
  * \since This function is available since SDL 2.0.18.
- * 
+ *
  * \sa SDL_RenderGetScale
  * \sa SDL_RenderSetScale
  * \sa SDL_RenderGetLogicalSize
@@ -1901,7 +1909,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_render_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_revision.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_revision.h
@@ -1,2 +1,2 @@
-#define SDL_REVISION "https://github.com/libsdl-org/SDL.git@53dea9830964eee8b5c2a7ee0a65d6e268dc78a1"
+#define SDL_REVISION "https://github.com/libsdl-org/SDL.git@a1d1946dcba6509f0679f507b57e7b228d32e6f8"
 #define SDL_REVISION_NUMBER 0
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_rwops.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_rwops.h
@@ -29,10 +29,10 @@
 #ifndef SDL_rwops_h_
 #define SDL_rwops_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -45,9 +45,6 @@
 #define SDL_RWOPS_JNIFILE   3U  /**< Android asset */
 #define SDL_RWOPS_MEMORY    4U  /**< Memory stream */
 #define SDL_RWOPS_MEMORY_RO 5U  /**< Read-Only memory stream */
-#if defined(__VITA__)
-#define SDL_RWOPS_VITAFILE  6U  /**< Vita file */
-#endif
 
 /**
  * This is the read/write operation structure -- very basic.
@@ -101,7 +98,7 @@
         {
             void *asset;
         } androidio;
-#elif defined(__WIN32__)
+#elif defined(__WIN32__) || defined(__GDK__)
         struct
         {
             SDL_bool append;
@@ -113,17 +110,6 @@
                 size_t left;
             } buffer;
         } windowsio;
-#elif defined(__VITA__)
-        struct
-        {
-            int h;
-            struct
-            {
-                void *data;
-                size_t size;
-                size_t left;
-            } buffer;
-        } vitaio;
 #endif
 
 #ifdef HAVE_STDIO_H
@@ -848,7 +834,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_rwops_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_scancode.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_scancode.h
@@ -28,7 +28,7 @@
 #ifndef SDL_scancode_h_
 #define SDL_scancode_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
 /**
  *  \brief The SDL keyboard scancode representation.
@@ -401,6 +401,26 @@
     SDL_SCANCODE_AUDIOFASTFORWARD = 286,
 
     /* @} *//* Usage page 0x0C (additional media keys) */
+
+    /**
+     *  \name Mobile keys
+     *
+     *  These are values that are often used on mobile phones.
+     */
+    /* @{ */
+
+    SDL_SCANCODE_SOFTLEFT = 287, /**< Usually situated below the display on phones and
+                                      used as a multi-function feature key for selecting
+                                      a software defined function shown on the bottom left
+                                      of the display. */
+    SDL_SCANCODE_SOFTRIGHT = 288, /**< Usually situated below the display on phones and
+                                       used as a multi-function feature key for selecting
+                                       a software defined function shown on the bottom right
+                                       of the display. */
+    SDL_SCANCODE_CALL = 289, /**< Used for accepting phone calls. */
+    SDL_SCANCODE_ENDCALL = 290, /**< Used for rejecting phone calls. */
+
+    /* @} *//* Mobile keys */
 
     /* Add any other keys here. */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_sensor.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_sensor.h
@@ -29,10 +29,10 @@
 #ifndef SDL_sensor_h_
 #define SDL_sensor_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 /* *INDENT-OFF* */
@@ -294,7 +294,7 @@
 }
 /* *INDENT-ON* */
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_sensor_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_shape.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_shape.h
@@ -22,13 +22,13 @@
 #ifndef SDL_shape_h_
 #define SDL_shape_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_pixels.h"
-#include "SDL_rect.h"
-#include "SDL_surface.h"
-#include "SDL_video.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_pixels.h>
+#include <SDL2/SDL_rect.h>
+#include <SDL2/SDL_surface.h>
+#include <SDL2/SDL_video.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -150,6 +150,6 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_shape_h_ */
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_stdinc.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_stdinc.h
@@ -28,7 +28,7 @@
 #ifndef SDL_stdinc_h_
 #define SDL_stdinc_h_
 
-#include "SDL_config.h"
+#include <SDL2/SDL_config.h>
 
 #ifdef __APPLE__
 #ifndef _DARWIN_C_SOURCE
@@ -115,6 +115,12 @@
 # endif
 #endif
 
+#ifdef SIZE_MAX
+# define SDL_SIZE_MAX SIZE_MAX
+#else
+# define SDL_SIZE_MAX ((size_t) -1)
+#endif
+
 /**
  * Check if the compiler supports a given builtin.
  * Supported by virtually all clang versions and recent gcc. Use this
@@ -253,7 +259,7 @@
 #ifndef SDL_PRIs64
 #ifdef PRIs64
 #define SDL_PRIs64 PRIs64
-#elif defined(__WIN32__)
+#elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIs64 "I64d"
 #elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIs64 "ld"
@@ -264,7 +270,7 @@
 #ifndef SDL_PRIu64
 #ifdef PRIu64
 #define SDL_PRIu64 PRIu64
-#elif defined(__WIN32__)
+#elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIu64 "I64u"
 #elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIu64 "lu"
@@ -275,7 +281,7 @@
 #ifndef SDL_PRIx64
 #ifdef PRIx64
 #define SDL_PRIx64 PRIx64
-#elif defined(__WIN32__)
+#elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIx64 "I64x"
 #elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIx64 "lx"
@@ -286,7 +292,7 @@
 #ifndef SDL_PRIX64
 #ifdef PRIX64
 #define SDL_PRIX64 PRIX64
-#elif defined(__WIN32__)
+#elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIX64 "I64X"
 #elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIX64 "lX"
@@ -367,14 +373,22 @@
 #endif
 #endif /* SDL_DISABLE_ANALYZE_MACROS */
 
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
-#define SDL_COMPILE_TIME_ASSERT(name, x) _Static_assert(x, #x)
-#elif defined(__cplusplus) && (__cplusplus >= 201103L)
+#ifndef SDL_COMPILE_TIME_ASSERT
+#if defined(__cplusplus)
+#if (__cplusplus >= 201103L)
 #define SDL_COMPILE_TIME_ASSERT(name, x)  static_assert(x, #x)
-#else /* universal, but may trigger -Wunused-local-typedefs */
+#endif
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+#define SDL_COMPILE_TIME_ASSERT(name, x) _Static_assert(x, #x)
+#endif
+#endif /* !SDL_COMPILE_TIME_ASSERT */
+
+#ifndef SDL_COMPILE_TIME_ASSERT
+/* universal, but may trigger -Wunused-local-typedefs */
 #define SDL_COMPILE_TIME_ASSERT(name, x)               \
        typedef int SDL_compile_time_assert_ ## name[(x) * 2 - 1]
 #endif
+
 /** \cond */
 #ifndef DOXYGEN_SHOULD_IGNORE_THIS
 SDL_COMPILE_TIME_ASSERT(uint8, sizeof(Uint8) == 1);
@@ -408,7 +422,7 @@
 #endif /* DOXYGEN_SHOULD_IGNORE_THIS */
 /** \endcond */
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -433,6 +447,16 @@
 typedef void (SDLCALL *SDL_free_func)(void *mem);
 
 /**
+ * Get the original set of SDL memory functions
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC void SDLCALL SDL_GetOriginalMemoryFunctions(SDL_malloc_func *malloc_func,
+                                                            SDL_calloc_func *calloc_func,
+                                                            SDL_realloc_func *realloc_func,
+                                                            SDL_free_func *free_func);
+
+/**
  * Get the current set of SDL memory functions
  *
  * \since This function is available since SDL 2.0.7.
@@ -462,7 +486,8 @@
 extern DECLSPEC char *SDLCALL SDL_getenv(const char *name);
 extern DECLSPEC int SDLCALL SDL_setenv(const char *name, const char *value, int overwrite);
 
-extern DECLSPEC void SDLCALL SDL_qsort(void *base, size_t nmemb, size_t size, int (*compare) (const void *, const void *));
+extern DECLSPEC void SDLCALL SDL_qsort(void *base, size_t nmemb, size_t size, int (SDLCALL *compare) (const void *, const void *));
+extern DECLSPEC void * SDLCALL SDL_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (SDLCALL *compare) (const void *, const void *));
 
 extern DECLSPEC int SDLCALL SDL_abs(int x);
 
@@ -486,6 +511,7 @@
 extern DECLSPEC int SDLCALL SDL_toupper(int x);
 extern DECLSPEC int SDLCALL SDL_tolower(int x);
 
+extern DECLSPEC Uint16 SDLCALL SDL_crc16(Uint16 crc, const void *data, size_t len);
 extern DECLSPEC Uint32 SDLCALL SDL_crc32(Uint32 crc, const void *data, size_t len);
 
 extern DECLSPEC void *SDLCALL SDL_memset(SDL_OUT_BYTECAP(len) void *dst, int c, size_t len);
@@ -494,6 +520,11 @@
 #define SDL_zerop(x) SDL_memset((x), 0, sizeof(*(x)))
 #define SDL_zeroa(x) SDL_memset((x), 0, sizeof((x)))
 
+#define SDL_copyp(dst, src)                                                                 \
+    { SDL_COMPILE_TIME_ASSERT(SDL_copyp, sizeof (*(dst)) == sizeof (*(src))); }             \
+    SDL_memcpy((dst), (src), sizeof (*(src)))
+
+
 /* Note that memset() is a byte assignment and this is a 32-bit assignment, so they're not directly equivalent. */
 SDL_FORCE_INLINE void SDL_memset4(void *dst, Uint32 val, size_t dwords)
 {
@@ -554,6 +585,7 @@
 extern DECLSPEC char *SDLCALL SDL_strstr(const char *haystack, const char *needle);
 extern DECLSPEC char *SDLCALL SDL_strtokr(char *s1, const char *s2, char **saveptr);
 extern DECLSPEC size_t SDLCALL SDL_utf8strlen(const char *str);
+extern DECLSPEC size_t SDLCALL SDL_utf8strnlen(const char *str, size_t bytes);
 
 extern DECLSPEC char *SDLCALL SDL_itoa(int value, char *str, int radix);
 extern DECLSPEC char *SDLCALL SDL_uitoa(unsigned int value, char *str, int radix);
@@ -727,11 +759,70 @@
     return SDL_memcpy(dst, src, dwords * 4);
 }
 
+/**
+ * If a * b would overflow, return -1. Otherwise store a * b via ret
+ * and return 0.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+SDL_FORCE_INLINE int SDL_size_mul_overflow (size_t a,
+                                            size_t b,
+                                            size_t *ret)
+{
+    if (a != 0 && b > SDL_SIZE_MAX / a) {
+        return -1;
+    }
+    *ret = a * b;
+    return 0;
+}
+
+#if _SDL_HAS_BUILTIN(__builtin_mul_overflow)
+/* This needs to be wrapped in an inline rather than being a direct #define,
+ * because __builtin_mul_overflow() is type-generic, but we want to be
+ * consistent about interpreting a and b as size_t. */
+SDL_FORCE_INLINE int _SDL_size_mul_overflow_builtin (size_t a,
+                                                     size_t b,
+                                                     size_t *ret)
+{
+    return __builtin_mul_overflow(a, b, ret) == 0 ? 0 : -1;
+}
+#define SDL_size_mul_overflow(a, b, ret) (_SDL_size_mul_overflow_builtin(a, b, ret))
+#endif
+
+/**
+ * If a + b would overflow, return -1. Otherwise store a + b via ret
+ * and return 0.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+SDL_FORCE_INLINE int SDL_size_add_overflow (size_t a,
+                                            size_t b,
+                                            size_t *ret)
+{
+    if (b > SDL_SIZE_MAX - a) {
+        return -1;
+    }
+    *ret = a + b;
+    return 0;
+}
+
+#if _SDL_HAS_BUILTIN(__builtin_add_overflow)
+/* This needs to be wrapped in an inline rather than being a direct #define,
+ * the same as the call to __builtin_mul_overflow() above. */
+SDL_FORCE_INLINE int _SDL_size_add_overflow_builtin (size_t a,
+                                                     size_t b,
+                                                     size_t *ret)
+{
+    return __builtin_add_overflow(a, b, ret) == 0 ? 0 : -1;
+}
+#define SDL_size_add_overflow(a, b, ret) (_SDL_size_add_overflow_builtin(a, b, ret))
+#endif
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_stdinc_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_surface.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_surface.h
@@ -28,13 +28,13 @@
 #ifndef SDL_surface_h_
 #define SDL_surface_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_pixels.h"
-#include "SDL_rect.h"
-#include "SDL_blendmode.h"
-#include "SDL_rwops.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_pixels.h>
+#include <SDL2/SDL_rect.h>
+#include <SDL2/SDL_blendmode.h>
+#include <SDL2/SDL_rwops.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -61,6 +61,8 @@
  */
 #define SDL_MUSTLOCK(S) (((S)->flags & SDL_RLEACCEL) != 0)
 
+typedef struct SDL_BlitMap SDL_BlitMap;  /* this is an opaque type. */
+
 /**
  * \brief A collection of pixels used in software blitting.
  *
@@ -88,7 +90,7 @@
     SDL_Rect clip_rect;         /**< Read-only */
 
     /** info for fast blit mapping to other surfaces */
-    struct SDL_BlitMap *map;    /**< Private */
+    SDL_BlitMap *map;           /**< Private */
 
     /** Reference count -- used when freeing surface */
     int refcount;               /**< Read-mostly */
@@ -988,7 +990,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_surface_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_system.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_system.h
@@ -28,12 +28,12 @@
 #ifndef SDL_system_h_
 #define SDL_system_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_keyboard.h"
-#include "SDL_render.h"
-#include "SDL_video.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_keyboard.h>
+#include <SDL2/SDL_render.h>
+#include <SDL2/SDL_video.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -41,7 +41,7 @@
 
 
 /* Platform specific functions for Windows */
-#ifdef __WIN32__
+#if defined(__WIN32__) || defined(__GDK__)
 	
 typedef void (SDLCALL * SDL_WindowsMessageHook)(void *userdata, void *hWnd, unsigned int message, Uint64 wParam, Sint64 lParam);
 
@@ -55,6 +55,10 @@
  */
 extern DECLSPEC void SDLCALL SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata);
 
+#endif /* defined(__WIN32__) || defined(__GDK__) */
+
+#if defined(__WIN32__) || defined(__WINGDK__)
+
 /**
  * Get the D3D9 adapter index that matches the specified display index.
  *
@@ -102,7 +106,31 @@
  */
 extern DECLSPEC ID3D11Device* SDLCALL SDL_RenderGetD3D11Device(SDL_Renderer * renderer);
 
+#endif /* defined(__WIN32__) || defined(__WINGDK__) */
+
+#if defined(__WIN32__) || defined(__GDK__)
+
+typedef struct ID3D12Device ID3D12Device;
+
 /**
+ * Get the D3D12 device associated with a renderer.
+ *
+ * Once you are done using the device, you should release it to avoid a
+ * resource leak.
+ *
+ * \param renderer the renderer from which to get the associated D3D12 device
+ * \returns the D3D12 device associated with given renderer or NULL if it is
+ *          not a D3D12 renderer; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC ID3D12Device* SDLCALL SDL_RenderGetD3D12Device(SDL_Renderer* renderer);
+
+#endif /* defined(__WIN32__) || defined(__GDK__) */
+
+#if defined(__WIN32__) || defined(__WINGDK__)
+
+/**
  * Get the DXGI Adapter and Output indices for the specified display index.
  *
  * The DXGI Adapter and Output indices can be passed to `EnumAdapters` and
@@ -122,9 +150,8 @@
  */
 extern DECLSPEC SDL_bool SDLCALL SDL_DXGIGetOutputInfo( int displayIndex, int *adapterIndex, int *outputIndex );
 
-#endif /* __WIN32__ */
+#endif /* defined(__WIN32__) || defined(__WINGDK__) */
 
-
 /* Platform specific functions for Linux */
 #ifdef __LINUX__
 
@@ -178,7 +205,7 @@
  * This function is only available on Apple iOS.
  *
  * For more information see:
- * [README-ios.md](https://hg.libsdl.org/SDL/file/default/docs/README-ios.md)
+ * https://github.com/libsdl-org/SDL/blob/main/docs/README-ios.md
  *
  * This functions is also accessible using the macro
  * SDL_iOSSetAnimationCallback() since SDL 2.0.4.
@@ -195,7 +222,7 @@
  *
  * \sa SDL_iPhoneSetEventPump
  */
-extern DECLSPEC int SDLCALL SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam);
+extern DECLSPEC int SDLCALL SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (SDLCALL *callback)(void*), void *callbackParam);
 
 #define SDL_iOSSetEventPump(enabled) SDL_iPhoneSetEventPump(enabled)
 
@@ -532,7 +559,7 @@
 extern DECLSPEC const char * SDLCALL SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType);
 
 /**
- * Detects the device family of WinRT plattform at runtime.
+ * Detects the device family of WinRT platform at runtime.
  *
  * \returns a value from the SDL_WinRT_DeviceFamily enum.
  *
@@ -564,11 +591,32 @@
 extern DECLSPEC void SDLCALL SDL_OnApplicationDidChangeStatusBarOrientation(void);
 #endif
 
+/* Functions used only by GDK */
+#if defined(__GDK__)
+typedef struct XTaskQueueObject * XTaskQueueHandle;
+
+/**
+ * Gets a reference to the global async task queue handle for GDK,
+ * initializing if needed.
+ *
+ * Once you are done with the task queue, you should call
+ * XTaskQueueCloseHandle to reduce the reference count to avoid a resource
+ * leak.
+ *
+ * \param outTaskQueue a pointer to be filled in with task queue handle.
+ * \returns 0 if success, -1 if any error occurs.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC int SDLCALL SDL_GDKGetTaskQueue(XTaskQueueHandle * outTaskQueue);
+
+#endif
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_system_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_syswm.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_syswm.h
@@ -28,10 +28,10 @@
 #ifndef SDL_syswm_h_
 #define SDL_syswm_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
-#include "SDL_video.h"
-#include "SDL_version.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_video.h>
+#include <SDL2/SDL_version.h>
 
 /**
  *  \brief SDL_syswm.h
@@ -108,7 +108,7 @@
 #endif
 
 #if defined(SDL_VIDEO_DRIVER_VIVANTE)
-#include "SDL_egl.h"
+#include <SDL2/SDL_egl.h>
 #endif
 
 #if defined(SDL_VIDEO_DRIVER_OS2)
@@ -122,7 +122,7 @@
 #endif
 
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -379,7 +379,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_syswm_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_thread.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_thread.h
@@ -28,14 +28,14 @@
  *  Header for the SDL thread management routines.
  */
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
 
 /* Thread synchronization primitives */
-#include "SDL_atomic.h"
-#include "SDL_mutex.h"
+#include <SDL2/SDL_atomic.h>
+#include <SDL2/SDL_mutex.h>
 
-#if defined(__WIN32__)
+#if defined(__WIN32__) || defined(__GDK__)
 #include <process.h> /* _beginthreadex() and _endthreadex() */
 #endif
 #if defined(__OS2__) /* for _beginthread() and _endthread() */
@@ -46,7 +46,7 @@
 #endif
 #endif
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -88,7 +88,7 @@
 typedef int (SDLCALL * SDL_ThreadFunction) (void *data);
 
 
-#if defined(__WIN32__)
+#if defined(__WIN32__) || defined(__GDK__)
 /**
  *  \file SDL_thread.h
  *
@@ -129,7 +129,7 @@
                  pfnSDL_CurrentEndThread pfnEndThread);
 
 extern DECLSPEC SDL_Thread *SDLCALL
-SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
+SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn,
                  const char *name, const size_t stacksize, void *data,
                  pfnSDL_CurrentBeginThread pfnBeginThread,
                  pfnSDL_CurrentEndThread pfnEndThread);
@@ -457,7 +457,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_thread_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_timer.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_timer.h
@@ -28,10 +28,10 @@
  *  Header for the SDL time management routines.
  */
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -215,7 +215,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_timer_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_touch.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_touch.h
@@ -28,11 +28,11 @@
 #ifndef SDL_touch_h_
 #define SDL_touch_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
-#include "SDL_video.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_error.h>
+#include <SDL2/SDL_video.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -143,7 +143,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_touch_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_types.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_types.h
@@ -26,4 +26,4 @@
  */
 
 /* DEPRECATED */
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_version.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_version.h
@@ -28,9 +28,9 @@
 #ifndef SDL_version_h_
 #define SDL_version_h_
 
-#include "SDL_stdinc.h"
+#include <SDL2/SDL_stdinc.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -58,8 +58,8 @@
 /* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
 */
 #define SDL_MAJOR_VERSION   2
-#define SDL_MINOR_VERSION   0
-#define SDL_PATCHLEVEL      22
+#define SDL_MINOR_VERSION   24
+#define SDL_PATCHLEVEL      1
 
 /**
  * Macro to determine SDL version program was compiled against.
@@ -83,6 +83,8 @@
     (x)->patch = SDL_PATCHLEVEL;                    \
 }
 
+/* TODO: Remove this whole block in SDL 3 */
+#if SDL_MAJOR_VERSION < 3
 /**
  *  This macro turns the version numbers into a numeric value:
  *  \verbatim
@@ -90,6 +92,11 @@
     \endverbatim
  *
  *  This assumes that there will never be more than 100 patchlevels.
+ *
+ *  In versions higher than 2.9.0, the minor version overflows into
+ *  the thousands digit: for example, 2.23.0 is encoded as 4300,
+ *  and 2.255.99 would be encoded as 25799.
+ *  This macro will not be available in SDL 3.x.
  */
 #define SDL_VERSIONNUM(X, Y, Z)                     \
     ((X)*1000 + (Y)*100 + (Z))
@@ -96,15 +103,24 @@
 
 /**
  *  This is the version number macro for the current SDL version.
+ *
+ *  In versions higher than 2.9.0, the minor version overflows into
+ *  the thousands digit: for example, 2.23.0 is encoded as 4300.
+ *  This macro will not be available in SDL 3.x.
+ *
+ *  Deprecated, use SDL_VERSION_ATLEAST or SDL_VERSION instead.
  */
 #define SDL_COMPILEDVERSION \
     SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL)
+#endif /* SDL_MAJOR_VERSION < 3 */
 
 /**
  *  This macro will evaluate to true if compiled with SDL at least X.Y.Z.
  */
 #define SDL_VERSION_ATLEAST(X, Y, Z) \
-    (SDL_COMPILEDVERSION >= SDL_VERSIONNUM(X, Y, Z))
+    ((SDL_MAJOR_VERSION >= X) && \
+     (SDL_MAJOR_VERSION > X || SDL_MINOR_VERSION >= Y) && \
+     (SDL_MAJOR_VERSION > X || SDL_MINOR_VERSION > Y || SDL_PATCHLEVEL >= Z))
 
 /**
  * Get the version of SDL that is linked against your program.
@@ -181,7 +197,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_version_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_video.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_video.h
@@ -28,12 +28,12 @@
 #ifndef SDL_video_h_
 #define SDL_video_h_
 
-#include "SDL_stdinc.h"
-#include "SDL_pixels.h"
-#include "SDL_rect.h"
-#include "SDL_surface.h"
+#include <SDL2/SDL_stdinc.h>
+#include <SDL2/SDL_pixels.h>
+#include <SDL2/SDL_rect.h>
+#include <SDL2/SDL_surface.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -248,7 +248,8 @@
     SDL_GL_FRAMEBUFFER_SRGB_CAPABLE,
     SDL_GL_CONTEXT_RELEASE_BEHAVIOR,
     SDL_GL_CONTEXT_RESET_NOTIFICATION,
-    SDL_GL_CONTEXT_NO_ERROR
+    SDL_GL_CONTEXT_NO_ERROR,
+    SDL_GL_FLOATBUFFERS
 } SDL_GLattr;
 
 typedef enum
@@ -444,6 +445,15 @@
  * A failure of this function usually means that either no DPI information is
  * available or the `displayIndex` is out of range.
  *
+ * **WARNING**: This reports the DPI that the hardware reports, and it is not
+ * always reliable! It is almost always better to use SDL_GetWindowSize() to
+ * find the window size, which might be in logical points instead of pixels,
+ * and then SDL_GL_GetDrawableSize(), SDL_Vulkan_GetDrawableSize(),
+ * SDL_Metal_GetDrawableSize(), or SDL_GetRendererOutputSize(), and compare
+ * the two values to get an actual scaling value between the two. We will be
+ * rethinking how high-dpi details should be managed in SDL3 to make things
+ * more consistent, reliable, and clear.
+ *
  * \param displayIndex the index of the display from which DPI information
  *                     should be queried
  * \param ddpi a pointer filled in with the diagonal DPI of the display; may
@@ -588,6 +598,35 @@
 extern DECLSPEC SDL_DisplayMode * SDLCALL SDL_GetClosestDisplayMode(int displayIndex, const SDL_DisplayMode * mode, SDL_DisplayMode * closest);
 
 /**
+ * Get the index of the display containing a point
+ *
+ * \param point the point to query
+ * \returns the index of the display containing the point or a negative error
+ *          code on failure; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GetDisplayBounds
+ * \sa SDL_GetNumVideoDisplays
+ */
+extern DECLSPEC int SDLCALL SDL_GetPointDisplayIndex(const SDL_Point * point);
+
+/**
+ * Get the index of the display primarily containing a rect
+ *
+ * \param rect the rect to query
+ * \returns the index of the display entirely containing the rect or closest
+ *          to the center of the rect on success or a negative error code on
+ *          failure; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GetDisplayBounds
+ * \sa SDL_GetNumVideoDisplays
+ */
+extern DECLSPEC int SDLCALL SDL_GetRectDisplayIndex(const SDL_Rect * rect);
+
+/**
  * Get the index of the display associated with a window.
  *
  * \param window the window to query
@@ -697,7 +736,10 @@
  * in pixels may differ from its size in screen coordinates on platforms with
  * high-DPI support (e.g. iOS and macOS). Use SDL_GetWindowSize() to query the
  * client area's size in screen coordinates, and SDL_GL_GetDrawableSize() or
- * SDL_GetRendererOutputSize() to query the drawable size in pixels.
+ * SDL_GetRendererOutputSize() to query the drawable size in pixels. Note that
+ * when this flag is set, the drawable size can vary after the window is
+ * created and should be queried after major window events such as when the
+ * window is resized or moved between displays.
  *
  * If the window is set fullscreen, the width and height parameters `w` and
  * `h` will not be used. However, invalid size parameters (e.g. too large) may
@@ -2009,14 +2051,9 @@
  * retry the call with 1 for the interval.
  *
  * Adaptive vsync is implemented for some glX drivers with
- * GLX_EXT_swap_control_tear:
+ * GLX_EXT_swap_control_tear, and for some Windows drivers with
+ * WGL_EXT_swap_control_tear.
  *
- * https://www.opengl.org/registry/specs/EXT/glx_swap_control_tear.txt
- *
- * and for some Windows drivers with WGL_EXT_swap_control_tear:
- *
- * https://www.opengl.org/registry/specs/EXT/wgl_swap_control_tear.txt
- *
  * Read more on the Khronos wiki:
  * https://www.khronos.org/opengl/wiki/Swap_Interval#Adaptive_Vsync
  *
@@ -2082,7 +2119,7 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_video_h_ */
 
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_vulkan.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_vulkan.h
@@ -28,9 +28,9 @@
 #ifndef SDL_vulkan_h_
 #define SDL_vulkan_h_
 
-#include "SDL_video.h"
+#include <SDL2/SDL_video.h>
 
-#include "begin_code.h"
+#include <SDL2/begin_code.h>
 /* Set up for C function definitions, even when using C++ */
 #ifdef __cplusplus
 extern "C" {
@@ -210,6 +210,6 @@
 #ifdef __cplusplus
 }
 #endif
-#include "close_code.h"
+#include <SDL2/close_code.h>
 
 #endif /* SDL_vulkan_h_ */
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/begin_code.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/begin_code.h
@@ -34,7 +34,7 @@
 #define _begin_code_h
 
 #ifndef SDL_DEPRECATED
-#  if (__GNUC__ >= 4)  /* technically, this arrived in gcc 3.1, but oh well. */
+#  if defined(__GNUC__) && (__GNUC__ >= 4)  /* technically, this arrived in gcc 3.1, but oh well. */
 #    define SDL_DEPRECATED __attribute__((deprecated))
 #  else
 #    define SDL_DEPRECATED
@@ -51,7 +51,7 @@
 
 /* Some compilers use a special export keyword */
 #ifndef DECLSPEC
-# if defined(__WIN32__) || defined(__WINRT__) || defined(__CYGWIN__)
+# if defined(__WIN32__) || defined(__WINRT__) || defined(__CYGWIN__) || defined(__GDK__)
 #  ifdef DLL_EXPORT
 #   define DECLSPEC __declspec(dllexport)
 #  else
@@ -74,7 +74,7 @@
 
 /* By default SDL uses the C calling convention */
 #ifndef SDLCALL
-#if (defined(__WIN32__) || defined(__WINRT__)) && !defined(__GNUC__)
+#if (defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)) && !defined(__GNUC__)
 #define SDLCALL __cdecl
 #elif defined(__OS2__) || defined(__EMX__)
 #define SDLCALL _System
--- /dev/null
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/CMake/sdl2-config-version.cmake
@@ -1,0 +1,48 @@
+# based on the files generated by CMake's write_basic_package_version_file
+
+# SDL2 CMake version configuration file:
+# This file is meant to be placed in Resources/CMake of a SDL2 framework
+
+if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/../../Headers/SDL_version.h")
+    message(AUTHOR_WARNING "Could not find SDL_version.h. This script is meant to be placed in the Resources/CMake directory of SDL2.framework")
+    return()
+endif()
+
+file(READ "${CMAKE_CURRENT_LIST_DIR}/../../Headers/SDL_version.h" _sdl_version_h)
+string(REGEX MATCH "#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)" _sdl_major_re "${_sdl_version_h}")
+set(_sdl_major "${CMAKE_MATCH_1}")
+string(REGEX MATCH "#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)" _sdl_minor_re "${_sdl_version_h}")
+set(_sdl_minor "${CMAKE_MATCH_1}")
+string(REGEX MATCH "#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)" _sdl_patch_re "${_sdl_version_h}")
+set(_sdl_patch "${CMAKE_MATCH_1}")
+if(_sdl_major_re AND _sdl_minor_re AND _sdl_patch_re)
+    set(PACKAGE_VERSION "${_sdl_major}.${_sdl_minor}.${_sdl_patch}")
+else()
+    message(AUTHOR_WARNING "Could not extract version from SDL_version.h.")
+    return()
+endif()
+
+if(PACKAGE_FIND_VERSION_RANGE)
+    # Package version must be in the requested version range
+    if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
+        OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
+        OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
+        set(PACKAGE_VERSION_COMPATIBLE FALSE)
+    else()
+        set(PACKAGE_VERSION_COMPATIBLE TRUE)
+    endif()
+else()
+    if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+        set(PACKAGE_VERSION_COMPATIBLE FALSE)
+    else()
+        set(PACKAGE_VERSION_COMPATIBLE TRUE)
+        if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
+            set(PACKAGE_VERSION_EXACT TRUE)
+        endif()
+    endif()
+endif()
+
+# if the using project doesn't have CMAKE_SIZEOF_VOID_P set, fail.
+if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "")
+    set(PACKAGE_VERSION_UNSUITABLE TRUE)
+endif()
--- /dev/null
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/CMake/sdl2-config.cmake
@@ -1,0 +1,69 @@
+# SDL2 CMake configuration file:
+# This file is meant to be placed in Resources/CMake of a SDL2 framework
+
+# INTERFACE_LINK_OPTIONS needs CMake 3.12
+cmake_minimum_required(VERSION 3.12)
+
+include(FeatureSummary)
+set_package_properties(SDL2 PROPERTIES
+    URL "https://www.libsdl.org/"
+    DESCRIPTION "low level access to audio, keyboard, mouse, joystick, and graphics hardware"
+)
+
+# Copied from `configure_package_config_file`
+macro(set_and_check _var _file)
+    set(${_var} "${_file}")
+    if(NOT EXISTS "${_file}")
+        message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
+    endif()
+endmacro()
+
+# Copied from `configure_package_config_file`
+macro(check_required_components _NAME)
+    foreach(comp ${${_NAME}_FIND_COMPONENTS})
+        if(NOT ${_NAME}_${comp}_FOUND)
+            if(${_NAME}_FIND_REQUIRED_${comp})
+                set(${_NAME}_FOUND FALSE)
+            endif()
+        endif()
+    endforeach()
+endmacro()
+
+set(SDL2_FOUND TRUE)
+
+string(REGEX REPLACE "SDL2\\.framework.*" "SDL2.framework" SDL2_FRAMEWORK_PATH "${CMAKE_CURRENT_LIST_DIR}")
+string(REGEX REPLACE "SDL2\\.framework.*" "" SDL2_FRAMEWORK_PARENT_PATH "${CMAKE_CURRENT_LIST_DIR}")
+
+# For compatibility with autotools sdl2-config.cmake, provide SDL2_* variables.
+
+set_and_check(SDL2_PREFIX       "${SDL2_FRAMEWORK_PATH}")
+set_and_check(SDL2_EXEC_PREFIX  "${SDL2_FRAMEWORK_PATH}")
+set_and_check(SDL2_INCLUDE_DIR  "${SDL2_FRAMEWORK_PATH}/Headers")
+set(SDL2_INCLUDE_DIRS           "${SDL2_INCLUDE_DIR}")
+set_and_check(SDL2_BINDIR       "${SDL2_FRAMEWORK_PATH}")
+set_and_check(SDL2_LIBDIR       "${SDL2_FRAMEWORK_PATH}")
+
+set(SDL2_LIBRARIES "SDL2::SDL2")
+
+# All targets are created, even when some might not be requested though COMPONENTS.
+# This is done for compatibility with CMake generated SDL2-target.cmake files.
+
+if(NOT TARGET SDL2::SDL2)
+    add_library(SDL2::SDL2 INTERFACE IMPORTED)
+    set_target_properties(SDL2::SDL2
+        PROPERTIES
+            INTERFACE_COMPILE_OPTIONS "SHELL:-F \"${SDL2_FRAMEWORK_PARENT_PATH}\""
+            INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}"
+            INTERFACE_LINK_OPTIONS "SHELL:-F \"${SDL2_FRAMEWORK_PARENT_PATH}\";SHELL:-framework SDL2"
+            COMPATIBLE_INTERFACE_BOOL "SDL2_SHARED"
+            INTERFACE_SDL2_SHARED "ON"
+    )
+endif()
+set(SDL2_SDL2_FOUND TRUE)
+
+if(NOT TARGET SDL2::SDL2main)
+    add_library(SDL2::SDL2main INTERFACE IMPORTED)
+endif()
+set(SDL2_SDL2main_FOUND TRUE)
+
+check_required_components(SDL2)
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/Info.plist
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/Info.plist
@@ -3,7 +3,7 @@
 <plist version="1.0">
 <dict>
 	<key>BuildMachineOSBuild</key>
-	<string>21E258</string>
+	<string>21G83</string>
 	<key>CFBundleDevelopmentRegion</key>
 	<string>English</string>
 	<key>CFBundleExecutable</key>
@@ -19,7 +19,7 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.0.22</string>
+	<string>2.24.1</string>
 	<key>CFBundleSignature</key>
 	<string>SDLX</string>
 	<key>CFBundleSupportedPlatforms</key>
@@ -27,11 +27,11 @@
 		<string>MacOSX</string>
 	</array>
 	<key>CFBundleVersion</key>
-	<string>2.0.22</string>
+	<string>2.24.1</string>
 	<key>DTCompiler</key>
 	<string>com.apple.compilers.llvm.clang.1_0</string>
 	<key>DTPlatformBuild</key>
-	<string>13E500a</string>
+	<string>14A400</string>
 	<key>DTPlatformName</key>
 	<string>macosx</string>
 	<key>DTPlatformVersion</key>
@@ -41,10 +41,10 @@
 	<key>DTSDKName</key>
 	<string>macosx12.3</string>
 	<key>DTXcode</key>
-	<string>1331</string>
+	<string>1401</string>
 	<key>DTXcodeBuild</key>
-	<string>13E500a</string>
+	<string>14A400</string>
 	<key>LSMinimumSystemVersion</key>
-	<string>10.6</string>
+	<string>10.9</string>
 </dict>
 </plist>
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/ReadMe.txt
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/ReadMe.txt
@@ -18,7 +18,19 @@
 Copy the SDL2.framework to /Library/Frameworks
 
 You may alternatively install it in <Your home directory>/Library/Frameworks 
-if your access privileges are not high enough. 
+if your access privileges are not high enough.
+
+
+Use in CMake projects:
+SDL2.framework can be used in CMake projects using the following pattern:
+```
+find_package(SDL2 REQUIRED COMPONENTS SDL2)
+add_executable(my_game ${MY_SOURCES})
+target_link_libraries(my_game PRIVATE SDL2::SDL2)
+```
+If SDL2.framework is installed in a non-standard location,
+please refer to the following link for ways to configure CMake:
+https://cmake.org/cmake/help/latest/command/find_package.html#config-mode-search-procedure
 
 
 Additional References:
binary files a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/default.metallib b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/default.metallib differ
binary files a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/SDL2 b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/SDL2 differ
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/_CodeSignature/CodeResources
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/_CodeSignature/CodeResources
@@ -4,9 +4,17 @@
 <dict>
 	<key>files</key>
 	<dict>
+		<key>Resources/CMake/sdl2-config-version.cmake</key>
+		<data>
+		GOmfPsl6+zUzjRroR1OeRUu1Do0=
+		</data>
+		<key>Resources/CMake/sdl2-config.cmake</key>
+		<data>
+		XSGoflduFZf82qGl/+WskdKOBw0=
+		</data>
 		<key>Resources/Info.plist</key>
 		<data>
-		OxWHBbdJFecUEehMjei2Rc0U5Fs=
+		G5afrcjIQY7IyFa2ddwCUvyFlPc=
 		</data>
 		<key>Resources/License.txt</key>
 		<data>
@@ -14,11 +22,11 @@
 		</data>
 		<key>Resources/ReadMe.txt</key>
 		<data>
-		JbxWZUxpvG/D7Yb/DvLh6Aunla0=
+		04Gl3MPa3Etx4qtkaftLHaPqBVU=
 		</data>
 		<key>Resources/default.metallib</key>
 		<data>
-		50m0avYLiIBc6a4gWqXN3tnFlpU=
+		4l5HIH0YrJO09WMMo9BAQG+BSjY=
 		</data>
 	</dict>
 	<key>files2</key>
@@ -27,11 +35,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			aTrG+5Kp2RqNz3APjcnTl3w2C4w=
+			AglD0HQ7wpywki02o+5BHIzEnL0=
 			</data>
 			<key>hash2</key>
 			<data>
-			9NawzRgLDm4UI/rDFKG++T8PnU8hiR5JbYyd6V3Mx7k=
+			rEJ7JEx5CQypooSpXSwzBg0rnDQ0Y7Ctkcgr6WARMso=
 			</data>
 		</dict>
 		<key>Headers/SDL_assert.h</key>
@@ -38,11 +46,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			uEY4hdTMrMozRTKHUFPLDb509Sg=
+			B9H6Q9JU0i9oid03T1/Ca86gZUU=
 			</data>
 			<key>hash2</key>
 			<data>
-			U3NT+iYQLyMuyL8C9sROyGEfnWZ5SGDnW2zvPxfWAKE=
+			uqj30tfXL8YY+MVK9XMh/XKClSKrCsikaNhPIt2HSYM=
 			</data>
 		</dict>
 		<key>Headers/SDL_atomic.h</key>
@@ -49,11 +57,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			D60+kC9hIWIjMdqJJ6YFVv8aOb0=
+			S7vGRTzBHVXKyXwYhhvUpfME4bs=
 			</data>
 			<key>hash2</key>
 			<data>
-			2fZn1kBYHhoKRoWwNUHlCWEDYp1KHMSJpCfmEqj415M=
+			yyqMgvtuNLSklwq2qM62TTuiLks55E6BNKOB08e6EzQ=
 			</data>
 		</dict>
 		<key>Headers/SDL_audio.h</key>
@@ -60,11 +68,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			7xIqZ2CJnqsLqa0yju2jGLvXIT8=
+			y0WyGUpd2J2rVMxjUi3zQZoj9ok=
 			</data>
 			<key>hash2</key>
 			<data>
-			dZi1DsT1rqMBCQaMyiUIg0VhL2Bimi21vToZVSHzoHg=
+			UYQL32SIkpxyWOGt7YsCsrwbchOvuBsgcFhTnyFcC/I=
 			</data>
 		</dict>
 		<key>Headers/SDL_bits.h</key>
@@ -71,11 +79,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			mxLXvUwNKaUNhzM4fR4Y8QlzvLU=
+			6MCXzkSXZ4Ba7/9ksdUPcPxqpLc=
 			</data>
 			<key>hash2</key>
 			<data>
-			E7lG+cfFwP0OtULzcOnUsdgz/uauYrGflxSD53S4pU8=
+			moRKyE7GpCyBzoyt2Eib7jqJ/ZMO1vTCWSjtHxP3Few=
 			</data>
 		</dict>
 		<key>Headers/SDL_blendmode.h</key>
@@ -82,11 +90,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			5Pz0CTC9TqwrzCBl01YH4gZrs9Y=
+			R0DC+lE1tBOALESAuGbbBcDXF24=
 			</data>
 			<key>hash2</key>
 			<data>
-			ZAgsP5xqXQisFDAE3DWRWGvUmP30Q0FqKtXhU9j9Pag=
+			RenGdg0rma2j6y9cRvHsTayslInVYfxWvAS3fGUv+Aw=
 			</data>
 		</dict>
 		<key>Headers/SDL_clipboard.h</key>
@@ -93,11 +101,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			xjb4xlgQVYsfmVMNWFBEnGFShaU=
+			b+5HV8QB/rNcY8Xz71ajJZhr9FY=
 			</data>
 			<key>hash2</key>
 			<data>
-			9jLWKNeHEqSrI9kVnhwtxekbH8eEwa64WdJ+rc4wROY=
+			XVgTrx+C/8H9Hrh/SRD4u4/rsx5MeBiKb2Orzx6fKVI=
 			</data>
 		</dict>
 		<key>Headers/SDL_config.h</key>
@@ -104,11 +112,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			Olzb505P1HBEz25McJhmwDQxMts=
+			6XTkjBo2D+0gCdBLcSva+glQ00M=
 			</data>
 			<key>hash2</key>
 			<data>
-			byh+rm0uGGxRtARYzR/iUxLMCj+UXtIQwZpqzWTbCHU=
+			VIvoehwuIKTef6WBop2Nd0NS05vrTj3rIQMzU50wCuo=
 			</data>
 		</dict>
 		<key>Headers/SDL_config_macosx.h</key>
@@ -115,11 +123,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			7Q5qbaae3QXLwQU6Jn3CSRazYk4=
+			OzmTF1uiICIhlC7h32zwOn5PqWE=
 			</data>
 			<key>hash2</key>
 			<data>
-			trVZMzZEKJS6fxOXwpzcplE8cTK6acnbtwd4xZBkkd4=
+			d/5n13ACXAeYbzU8JL6aHOfY8s5OHyT6+E1jI9bGK64=
 			</data>
 		</dict>
 		<key>Headers/SDL_copying.h</key>
@@ -137,11 +145,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			AiFK26oC3vrUqQcTktLi2pyL/KQ=
+			OxKz9tarv+BN6HZcd11A9kgKjC4=
 			</data>
 			<key>hash2</key>
 			<data>
-			Oo1qVxCq+dkxk9lEf0v0qwPmjbCeLATLH4VxG2ybMQg=
+			LJ2E3SmiAFu5mqI6xxqZ14u5zBWps8OXrbDY4LEQiq0=
 			</data>
 		</dict>
 		<key>Headers/SDL_endian.h</key>
@@ -148,11 +156,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			hjZnlLj/BhnYauMLnPFLqv5ld+8=
+			3SKom++C+iyjKSaAzELahcbZb9w=
 			</data>
 			<key>hash2</key>
 			<data>
-			UCdvUbA4LSqN8Agy5/Q6+flinRwg6e74eukmB8sT6EU=
+			itvFDymfM/B7KSiRLqeXPtmP1Pae7Hr6PKV536yb19k=
 			</data>
 		</dict>
 		<key>Headers/SDL_error.h</key>
@@ -159,11 +167,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			HMOGfdi3z3S5yWDfup5j0fB2Whg=
+			49T3z69eEOBmcFSD+a3fLxkRZOI=
 			</data>
 			<key>hash2</key>
 			<data>
-			Rw8EpFYjBZZtdwW3dMHoX7bp6M5ME28mab1Mwsxski8=
+			opYHpNi3KkdFqGsd3UAYaRbjKh6kPnu16gD/ZZQ/jt8=
 			</data>
 		</dict>
 		<key>Headers/SDL_events.h</key>
@@ -170,11 +178,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			b+C5YW7mW4CdkoYFIbkdxfghfd0=
+			BdXEyKTMfk5GqMJXjX9BS8BnKtE=
 			</data>
 			<key>hash2</key>
 			<data>
-			vGErGGPAOzP1ZoIRYWQZaWC7bP03jagORHaFJftUEiI=
+			DV1SmLmr37ujp5UDAeTugWPgIQjvC1OoEIbgPxnbkxo=
 			</data>
 		</dict>
 		<key>Headers/SDL_filesystem.h</key>
@@ -181,11 +189,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			npTjrmVuSB1Irv4s1UpopzGfftY=
+			PoeYaqU+WGFkNISl6SWsnlL8rwQ=
 			</data>
 			<key>hash2</key>
 			<data>
-			eUiPHMpZBPqmnG3+uO/o9jYN7Y7uED8WEbp+m6zfz+0=
+			zVudQ4vBqMuXpQQnzZFPN98wlxfFh3JbsuqtpL5a2h8=
 			</data>
 		</dict>
 		<key>Headers/SDL_gamecontroller.h</key>
@@ -192,11 +200,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			Qwyjs/bcCUzZvFafnydTTGb3940=
+			sVD98kanhzhCejv4HtOc2nLqEok=
 			</data>
 			<key>hash2</key>
 			<data>
-			ojhssavzsyV6wvnGfBKuPGyTxr0MAZg+VDGWA8Gmilc=
+			9vFNNLtx9sV+5MgN8s2yADYmorHfIpP4da9R00YkpGk=
 			</data>
 		</dict>
 		<key>Headers/SDL_gesture.h</key>
@@ -203,22 +211,33 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			krxPa6d/MfEO9u2sdU+IH+kYjlA=
+			eOm09gklTuHk4CAnY8+N+AOWU1w=
 			</data>
 			<key>hash2</key>
 			<data>
-			n8WGIrwBlLDWdm6lb+MttHwLGZ81sAfjcNHQqIASrPg=
+			3Jzx8qKPiLBEeimWYGEMjqACvDfAm8j8qVyKZPyot6o=
 			</data>
 		</dict>
+		<key>Headers/SDL_guid.h</key>
+		<dict>
+			<key>hash</key>
+			<data>
+			crNLOtYvZUPZiAe8ZhVvIlKHL1k=
+			</data>
+			<key>hash2</key>
+			<data>
+			8faGizimrTUdyyQeGyHX3YXB92lt5jgs6kJpGEpBoKY=
+			</data>
+		</dict>
 		<key>Headers/SDL_haptic.h</key>
 		<dict>
 			<key>hash</key>
 			<data>
-			CMynNInlayPz9QbCwUNg5CX2yuA=
+			2P/RhAx7yVVau0ImN4IRu0PKJwM=
 			</data>
 			<key>hash2</key>
 			<data>
-			rlNd/QPn0tUkNZZd5utc0gAVf9chIA7MOkAbDOwPZa0=
+			Irx+pJE/K0azzSlTpm9Rst1n2EmNLTpbLY3kmpEinJ0=
 			</data>
 		</dict>
 		<key>Headers/SDL_hidapi.h</key>
@@ -225,11 +244,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			/AZ5o6pLOz6tNDzNR3sjxOUtNM8=
+			gerk57ttnkfcx6wYtwW4C8Utt60=
 			</data>
 			<key>hash2</key>
 			<data>
-			8T9nnGMMORDWOYLT/0SpqwsXiS2iqTz8Khv5PWWnscQ=
+			KYySNLgkVh6cIAiPYvDk/Yk2SvQafFytdHZOKvxzZOw=
 			</data>
 		</dict>
 		<key>Headers/SDL_hints.h</key>
@@ -236,11 +255,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			MNIKfPtJ4SewBtPWpU/h6TOtwSQ=
+			xYbJKIk1b/dU070K46elN3+mRgE=
 			</data>
 			<key>hash2</key>
 			<data>
-			aXw7nEIct7VTCTjuJNiNNRR6k/Itx+PRZLqNEtTKG2U=
+			CGPQWyZQWAIltmta5ogO3yTbp8bsLA65wBotBwl+0ME=
 			</data>
 		</dict>
 		<key>Headers/SDL_joystick.h</key>
@@ -247,11 +266,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			GH2e05dwSwQ8iwknMqCRTWR/MbE=
+			bvqXmRQEmT+7pu66OUIAgcF/qdU=
 			</data>
 			<key>hash2</key>
 			<data>
-			1++nAdLqleg2ivlLLskLor6ZJt6G/a2z1xaQxdpBI4Y=
+			XAw62auzvMWnTxik4mFxfz1k1dRT0k0JslXzaN2mYZs=
 			</data>
 		</dict>
 		<key>Headers/SDL_keyboard.h</key>
@@ -258,11 +277,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			w8EdoupVBrDxx7IWS/DMFudkT7A=
+			daaK2d9/FS98QIeRbwHDjK6MbM4=
 			</data>
 			<key>hash2</key>
 			<data>
-			LtiaG0lVgcH29e+os6cGweWKblrxXFVb4EvP9/kzVWM=
+			BOPhdmyBg4iHctggySFsXHD+2dk0qPQ1glPpc56gEoI=
 			</data>
 		</dict>
 		<key>Headers/SDL_keycode.h</key>
@@ -269,11 +288,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			k6pi1TtFgDy8Fev/sx+9HPBIVo8=
+			L6VgO8ptH7uIWMYxqiYDitWP2+0=
 			</data>
 			<key>hash2</key>
 			<data>
-			bpTuOCjY6lRQciH9AMwuUxb613Ui0GfKiNPTaOfiECM=
+			o+cvRpzlGHktvrWgdp69oT8gP310gr6qMuoz/bkvsJU=
 			</data>
 		</dict>
 		<key>Headers/SDL_loadso.h</key>
@@ -280,11 +299,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			AghElM6gDnY4Dnlbot+vyYnJSrA=
+			BnfRn8au8VfS8nOYd+Og6CqxQtQ=
 			</data>
 			<key>hash2</key>
 			<data>
-			jk0DV61sgGnNfeaCAXNgZVAKjHsjhOf9ZdTuTRYAkcs=
+			ViHwtMagclIe0iTK9fUbYuesvQ1nv8rC+9675X5dk3Y=
 			</data>
 		</dict>
 		<key>Headers/SDL_locale.h</key>
@@ -291,11 +310,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			YT2d/us0oU2vhka1X8YrQQ+ugZA=
+			B7JrCP37jV9Gs+1YoxkyXgaA3/0=
 			</data>
 			<key>hash2</key>
 			<data>
-			mRms4gf60gOySskWyStSn3QIjtFMeXdgoy4Ft2xgWOw=
+			NfBH1vQU0RfPYtW0AzShJFmv8MulTUzc/kAQZ9C6ygw=
 			</data>
 		</dict>
 		<key>Headers/SDL_log.h</key>
@@ -302,11 +321,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			PT7enVGL1sm/zYmzZW0KPjl6+DY=
+			aaLQi9U7ijhEeR6nQB97Eb5kLcY=
 			</data>
 			<key>hash2</key>
 			<data>
-			WxgnkpwyPN/S59ykRY+yhtPTnwS9K04cIAVnuniO+1g=
+			HiRdEa7+l/wQ6D1HrCHHIIWuTmbSu/TDzwJZPE4T414=
 			</data>
 		</dict>
 		<key>Headers/SDL_main.h</key>
@@ -313,11 +332,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			7wE/XJU9i7D8dE38GunD5LHSxR8=
+			Qi/WIvr8HU0GJprv7Fs6yfpNR5A=
 			</data>
 			<key>hash2</key>
 			<data>
-			A12oFUcYcvrjD7x99eknjooVxZW7nku1C9CvlG7dAGw=
+			VrF7Og9RQm8oM1rSzdhI/s1IjZsL8N0lNbo1yNKaEfo=
 			</data>
 		</dict>
 		<key>Headers/SDL_messagebox.h</key>
@@ -324,11 +343,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			lnOIwfBGqyynpECAR37S2IEV/ng=
+			Jyd+Z0oJkOyu7GqxrGoj92kX33E=
 			</data>
 			<key>hash2</key>
 			<data>
-			n44B79BylebQ9O8zUL0hetppllkcICK3+RY/v9/mfu8=
+			b/2BVaUV14/zSF4P4vqsBKHdmHO39bcQh+Iw5cIjiUs=
 			</data>
 		</dict>
 		<key>Headers/SDL_metal.h</key>
@@ -335,11 +354,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			yP5RcpTgmEI5xYVUhmsSXzNcpMo=
+			lgw/jPhvwM+nsqA0HITlLaESI1Y=
 			</data>
 			<key>hash2</key>
 			<data>
-			jICsu4yIr5tUTA15x3BzYA25xK/3wIzMavVBzM2RzIw=
+			8e2u8Lp9cp5tnfxLkwSsyerOA213Z/Con+WQe/U+QYI=
 			</data>
 		</dict>
 		<key>Headers/SDL_misc.h</key>
@@ -346,11 +365,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			a4ATMtgjBBMX7Mj07UyVQIq/c8A=
+			GDQyA6cRKZi3FJ3qPXMgIG19Xic=
 			</data>
 			<key>hash2</key>
 			<data>
-			7mlsKhE10BEM5snv4NZ/mp6OxAD28AwrUyR5lRk/luw=
+			ouIje4tauHjysbz3ObtyFzAB6lTCyhdwb4ndhQ3Z9n4=
 			</data>
 		</dict>
 		<key>Headers/SDL_mouse.h</key>
@@ -357,11 +376,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			1tRjTl1mdjS6QZOVNwEmzcQAnZY=
+			nrOK2z4t0YZ5ivxuTWB+9cXUf68=
 			</data>
 			<key>hash2</key>
 			<data>
-			loX9Ql/ErNSvCCSGK1aUnrgpPEQTn26IM6jhsEV/96M=
+			a1uWINzkYwydY2X/EhrWYcmHb2VG1Jy3C5nU6xOJAnk=
 			</data>
 		</dict>
 		<key>Headers/SDL_mutex.h</key>
@@ -368,11 +387,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			xfNSAwUg5y/cL1N2vmcaKCPCb/o=
+			aG58/w/wU0G8N8tgCdD8ecbbbe4=
 			</data>
 			<key>hash2</key>
 			<data>
-			OmVrUzuXpVJ6ifz7twnDcCT37Sk9lCpqP5zgaCc/QtA=
+			XUDMtaFm4qzh0iFhMP4Gnl9H7BDRtZnfFZx6UVvw6uQ=
 			</data>
 		</dict>
 		<key>Headers/SDL_name.h</key>
@@ -390,11 +409,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			SUV9OqGz7Dq4k0jSR2gus91fNec=
+			7MOKOotpNv44gQkv/pUbTkn8IoE=
 			</data>
 			<key>hash2</key>
 			<data>
-			RX5C4ZnVnU5EkxhGic4alEb4pCx6bBavRT0swlytQCo=
+			zkUzBymyrkFMTK7R21v1NrPrq1gm+FRVcWQ+BUYXbjo=
 			</data>
 		</dict>
 		<key>Headers/SDL_opengl_glext.h</key>
@@ -412,11 +431,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			mM8fr98GwoT5B7v9Wxp1GdDiBts=
+			gNgYlz+/uLgvjec6r0AW7Be2DJI=
 			</data>
 			<key>hash2</key>
 			<data>
-			RuQLSak6d50GlBLg+BjoESrSI1/knMjN2q3KrmLEawA=
+			gpV8CPolshDeFDmSwWdoE1szEa7jY6uW06q61w+0g8k=
 			</data>
 		</dict>
 		<key>Headers/SDL_opengles2.h</key>
@@ -423,11 +442,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			gKfjFA77n02Jf43mivhqK0Ujy8s=
+			JAC+taTpU61KVFADpZvYguHPY/A=
 			</data>
 			<key>hash2</key>
 			<data>
-			OP4GffL10Z5RCHQ+Aj9v8dKnAlpyWHoukZxeQAbq6kA=
+			4VPaduWoVpL5jy0A9S+tAoRXm0of4K+lqTZ2HRlDNT8=
 			</data>
 		</dict>
 		<key>Headers/SDL_opengles2_gl2.h</key>
@@ -478,11 +497,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			LRzcADu41sQrKf10qqp2LWW3XeA=
+			APvnWU71OTgg8nF2ZBdVu+N0OGo=
 			</data>
 			<key>hash2</key>
 			<data>
-			seo4cKvPIVhKUg5BzcoOMtlXuHwK+4za+sld2oDhgQw=
+			6VtEW9W48E5QT0eLhrzHm6TM2ZuskMlgjcaAwsilSlY=
 			</data>
 		</dict>
 		<key>Headers/SDL_platform.h</key>
@@ -489,11 +508,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			5galYZ+iWxBC3tUY+85l/rodb7o=
+			i6mueiGp/xhX/L+32oRz5Lq1h5I=
 			</data>
 			<key>hash2</key>
 			<data>
-			2HaGAlD+jfbrSQUbdh2ikhMJIIgaSyZYY4Hj8Qw8nK8=
+			+bUBkFH5eTYbCwRAQKwdm9F9wyVoV+fCFCnjgc6LXyI=
 			</data>
 		</dict>
 		<key>Headers/SDL_power.h</key>
@@ -500,11 +519,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			eUUuz7NJwdtXoPz4TwWD/t3t/hY=
+			CZt1YqOCoPff+ZX5nsgeLs2abiM=
 			</data>
 			<key>hash2</key>
 			<data>
-			k64vrXeP8FelgvSUDMg4ZLSZGurq61yU87ww6/5mM+8=
+			WuENeZEjbiPGXwmzKPi9End4ZRDqxD7gCGDnrgDjgJc=
 			</data>
 		</dict>
 		<key>Headers/SDL_quit.h</key>
@@ -511,11 +530,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			Iid+EH+i3+DPXxFt3ai7nkYXpdA=
+			tPbozXmJ7atsNAXI2sOnYySxxE0=
 			</data>
 			<key>hash2</key>
 			<data>
-			ov2UI4cI1IsyYq8qk7//RwrmY5ObAhp7KkRT0cp8XVM=
+			2OKt3rHgSNG9eTiP7SP0r7oy3zP+xN2i4s6r9i2FLOg=
 			</data>
 		</dict>
 		<key>Headers/SDL_rect.h</key>
@@ -522,11 +541,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			ztC9bPrMYIWHuuIv6KDDe+k0mis=
+			iHOu4GrnG9wq51NGY+KM2d+2M0g=
 			</data>
 			<key>hash2</key>
 			<data>
-			Nw4VuuH6sfXJ6SmFAAxWkXZNwpSyM93M0NhDcmrINfw=
+			Tntu1hV6+rDYjtkylyY+L1sksaom8tHOa/2CWh+sgtg=
 			</data>
 		</dict>
 		<key>Headers/SDL_render.h</key>
@@ -533,11 +552,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			LYUqbTHT+nxZVu/W7ZLKDjtBnVI=
+			99vR7BI+q1DOT92PKbDwd0aJC9U=
 			</data>
 			<key>hash2</key>
 			<data>
-			OLdAKEsl5+dofY5kGScL0SH22Qm56tenSq/r75YHJlw=
+			/sE6eLwCW6hgGvZVO5t6tqwveFueUOM1AhBYEVvLAhk=
 			</data>
 		</dict>
 		<key>Headers/SDL_revision.h</key>
@@ -544,11 +563,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			OmV6TNE1P8Dm+ekO7PlOPkvpJJM=
+			gJvueJVaGjBAoAUZ/ZZDSlXPmzk=
 			</data>
 			<key>hash2</key>
 			<data>
-			N8c2dyfn8XOV6qOfJ3wvKHDejG3snUbYdTt3G3/xhUQ=
+			GDPtrgtgxZaH6s2Tg8aNSgKCEYdL5Dyz4FTbKb5GiT0=
 			</data>
 		</dict>
 		<key>Headers/SDL_rwops.h</key>
@@ -555,11 +574,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			0UYLGZe0oyql92rwo5sk2Mv5JVo=
+			L/Twsg6Wmiwo1H5Qs8STE8WIR24=
 			</data>
 			<key>hash2</key>
 			<data>
-			P4RMdCXF/9K953m6Q+eqVXRCkVzVAV+hXbOoe3e4A6M=
+			km34IYEvTAj4qaziyAtJzgUinazvYYMTaAF2iFAKo9w=
 			</data>
 		</dict>
 		<key>Headers/SDL_scancode.h</key>
@@ -566,11 +585,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			sx6YjImUkAdRAX7V1DIAuwxkh/c=
+			VwbcuI+yrOTXtol5lZyennpTAAQ=
 			</data>
 			<key>hash2</key>
 			<data>
-			OL3RNQD2X96+kxsU0yRH4apSx/tKhi3BxRl52OFAYSk=
+			yaEmKrGcD3svKPTqjQbhjFsq7d5AezJIARLOnsVnyFk=
 			</data>
 		</dict>
 		<key>Headers/SDL_sensor.h</key>
@@ -577,11 +596,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			61q6aLU6n7+kNN09SObFJeO/9wA=
+			cAqB17JLRyFN5n8MAJrIkY1AqBw=
 			</data>
 			<key>hash2</key>
 			<data>
-			XmYmMVG61fzgJfj77mGROTywuMWsNgRLG597bhz+peY=
+			uBC/ANStES2g4wtWn7Mk/4MJeHp+wr7wEfurKfzv3dc=
 			</data>
 		</dict>
 		<key>Headers/SDL_shape.h</key>
@@ -588,11 +607,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			qj0IUzY/c0BL/X9SgIT0fF3jLkE=
+			UWs6SO78LJYdrBlGs1tY10DrJUI=
 			</data>
 			<key>hash2</key>
 			<data>
-			HTVFVnU5fT3NJ77xPGLsTExAsiEcJ9WJryO/zLZJL6c=
+			CFJEICmokjpIcOYx1hTgGJ8fqLjaj+k9VuxREOUDJaA=
 			</data>
 		</dict>
 		<key>Headers/SDL_stdinc.h</key>
@@ -599,11 +618,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			EYOOaliKN3mXAL5afejG9kTy5+k=
+			93tr2t6dqOrONrDaedDp7NDK0qc=
 			</data>
 			<key>hash2</key>
 			<data>
-			6od6OtLyHwzdV1pX2zr4Kzcet0I8NKfiB0Kv+Ml69Go=
+			WOsgS2T3ZGPbJYxPyjK1f0Alehu9S7qmCaamjeOtw1w=
 			</data>
 		</dict>
 		<key>Headers/SDL_surface.h</key>
@@ -610,11 +629,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			RdyyRQbhpIDBkrNOPDJ290MEc18=
+			bc5QzhwXbUo4XnD7q4NOSWOuTxs=
 			</data>
 			<key>hash2</key>
 			<data>
-			k58BNGZc93dbvyP4oyMEHL7LTMCncEHSm7EdcR878w4=
+			xouGGI808iRhAh/0XTNJv2QTIUi3LPrZW5oHvGDm/7E=
 			</data>
 		</dict>
 		<key>Headers/SDL_system.h</key>
@@ -621,11 +640,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			S6sTGCcO3+vzldjaK1MKpAdpUwA=
+			s6lznhqSlL+KFtBJSEELBCTTp1U=
 			</data>
 			<key>hash2</key>
 			<data>
-			UDYoiSAVLHeQO4b2Ed+RnZFLklEJAsddB0wwBbrlVXw=
+			AlgtfPI6N0Jukp6N7fmTnNV3AzBzEBj5HZREFJSkMmY=
 			</data>
 		</dict>
 		<key>Headers/SDL_syswm.h</key>
@@ -632,11 +651,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			c/yTWIUac7ruA/MxHCtFrpY99iY=
+			oxVccR9E/ARZqqPl+BjVMKNdDNw=
 			</data>
 			<key>hash2</key>
 			<data>
-			u8ZMeDHauQkZOq0xta38z4KOR3Z+X1Bw/Gq6ldUm8S8=
+			LRcM/Fhcqwv6Qf3YhgaLGkkEuFqXFTvl6pWfaQCNw9g=
 			</data>
 		</dict>
 		<key>Headers/SDL_thread.h</key>
@@ -643,11 +662,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			9IQdMCX5R/BYopjk3MQIKacM0zg=
+			5xZpdbtxabSCqxFchsbPpUHLNQ0=
 			</data>
 			<key>hash2</key>
 			<data>
-			eZr1S4adstfHOatN7ohlUl+LnVN+hXUn7ezBiX2acpQ=
+			4fpEGwWz/MZXi0gbsOZzM4CclNzbsUUBso62NcHZs0o=
 			</data>
 		</dict>
 		<key>Headers/SDL_timer.h</key>
@@ -654,11 +673,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			hqlDXe01g/p0GJqAIyCnovQfuv0=
+			Ltnz4OrvTc2eABw8uX/0L/nuca4=
 			</data>
 			<key>hash2</key>
 			<data>
-			GQrzt2L9IDziXBftqfsx1pi9dZV/WdTOfMIWceiiQDo=
+			W+hRt3f94ZHPIpQ4xN7D/U0OVtTTZBAA9Nphtq8fgeg=
 			</data>
 		</dict>
 		<key>Headers/SDL_touch.h</key>
@@ -665,11 +684,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			7uNU9A4qHZQB6CKh7zOjZt1w2cc=
+			rwC4gDU7l5kY0ZZEIhd7RT3axUU=
 			</data>
 			<key>hash2</key>
 			<data>
-			4TL6Yoim9zWJo4xXKZd/MZsrUIrNUvlZFpEuoMtOIlU=
+			DVFA8C77fiVhyFFtqV/lglia5PShpk967pt+huaItwo=
 			</data>
 		</dict>
 		<key>Headers/SDL_types.h</key>
@@ -676,11 +695,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			JL3QiRD2vzD7eFr8QljR1v7v8lU=
+			ARZgD/WKM8LbXYcplBCyws5jmmo=
 			</data>
 			<key>hash2</key>
 			<data>
-			kIAt1eckF9O/iA04SnvC8H5cGzOldVcPrteXVyGB3wo=
+			vvFj+McRdgHRX9HrooW/E7jX5C74rxEwVv18wMyvSC0=
 			</data>
 		</dict>
 		<key>Headers/SDL_version.h</key>
@@ -687,11 +706,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			do5+x9XfCNHA4lphY05v8LLcu7s=
+			A9pTspEqTiDa5Jo5uKp0lRdX8jo=
 			</data>
 			<key>hash2</key>
 			<data>
-			i3TeLMhNerHPGUcZ7iHbxfBiDH0IxtBvejyZWWdtkOU=
+			maEtnUY+anHONL0tYQVIhjvxe4bQ8GEd8NzqfLyr8NE=
 			</data>
 		</dict>
 		<key>Headers/SDL_video.h</key>
@@ -698,11 +717,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			60Zzr8X2wpuq+vFcn77/RNTVGYY=
+			uJc4I4G8WWjQewCsj9laubKnfks=
 			</data>
 			<key>hash2</key>
 			<data>
-			Uzv2NcHWzsVBKVEJWlIPzEGu0hSLQIP8MM8xN98LNwE=
+			argj1/xE3Y/fcUyhn1aF8GGrCxfWV9j8+KbXwMzZRD8=
 			</data>
 		</dict>
 		<key>Headers/SDL_vulkan.h</key>
@@ -709,11 +728,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			YzU8hEv6jByapIvIAasOdqkAyQU=
+			k22upiGXgz0TzSKkWtDwaKrV2fw=
 			</data>
 			<key>hash2</key>
 			<data>
-			PqC117S9gbnKmKCBf991rQDJ7N2ak+47yGX/gEdOG8c=
+			kg2f48mMRh4+Ev5cnsEDDyQqf6YbP7YqWNhykRYzgDo=
 			</data>
 		</dict>
 		<key>Headers/begin_code.h</key>
@@ -720,11 +739,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			A52Lh/nQ4BliCI+RMHIt9xSD6Fs=
+			u4PDdbvfemkyR1H1QsODd6pLFRA=
 			</data>
 			<key>hash2</key>
 			<data>
-			KDdUdsUtYxmo0ZyQLNwOHuWTKFaJnujcoeF6edzp4SE=
+			mOMdpMYdVHyciBhBNbcuPQFKemkQLlxtdYNQI3z2snE=
 			</data>
 		</dict>
 		<key>Headers/close_code.h</key>
@@ -738,15 +757,37 @@
 			9JEAM14hpDRV6tDnQvfIFtBJQXHOEJSONje5q/PKlTo=
 			</data>
 		</dict>
+		<key>Resources/CMake/sdl2-config-version.cmake</key>
+		<dict>
+			<key>hash</key>
+			<data>
+			GOmfPsl6+zUzjRroR1OeRUu1Do0=
+			</data>
+			<key>hash2</key>
+			<data>
+			YeQ8SoXGqMam3mk/39htvQ5fF5Twd16X5JPfl7/hSuk=
+			</data>
+		</dict>
+		<key>Resources/CMake/sdl2-config.cmake</key>
+		<dict>
+			<key>hash</key>
+			<data>
+			XSGoflduFZf82qGl/+WskdKOBw0=
+			</data>
+			<key>hash2</key>
+			<data>
+			oO7paOWdt4AGUK6i7ifbCbWdp4I741YtJf3U2SIi9ro=
+			</data>
+		</dict>
 		<key>Resources/Info.plist</key>
 		<dict>
 			<key>hash</key>
 			<data>
-			OxWHBbdJFecUEehMjei2Rc0U5Fs=
+			G5afrcjIQY7IyFa2ddwCUvyFlPc=
 			</data>
 			<key>hash2</key>
 			<data>
-			ScLuGB7K21JNtYbbGu7tXZiTvB3bCi8bFdDLJGAMcOs=
+			x80g0iIVcnoeE4ew8iJZBg8GD0oM9s7EhHkplaKUqz8=
 			</data>
 		</dict>
 		<key>Resources/License.txt</key>
@@ -764,11 +805,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			JbxWZUxpvG/D7Yb/DvLh6Aunla0=
+			04Gl3MPa3Etx4qtkaftLHaPqBVU=
 			</data>
 			<key>hash2</key>
 			<data>
-			pOpMHiFjj3pIWQqZ5KDvYNyp0twU7vCZmLwAQJLVkT4=
+			OjTqSEaeNJpJyrrZIzKimvTn011CW6ucNulPPxUwgL0=
 			</data>
 		</dict>
 		<key>Resources/default.metallib</key>
@@ -775,11 +816,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			50m0avYLiIBc6a4gWqXN3tnFlpU=
+			4l5HIH0YrJO09WMMo9BAQG+BSjY=
 			</data>
 			<key>hash2</key>
 			<data>
-			w8jS3DIw3CKDRfJsmiA4MWFVPhdpi2zi+WEO1Zfw8+8=
+			mG4gq0ZWuiydHgb5Xh0OvlnGHDkCdvaqQKnD5G1m7xc=
 			</data>
 		</dict>
 	</dict>
--- a/release/other/protracker.ini
+++ b/release/other/protracker.ini
@@ -252,7 +252,7 @@
 ; Audio output frequency
 ;        Syntax: Number, in hertz
 ; Default value: 48000
-;       Comment: Ranges from 44100 to 192000. Also applies to MOD2WAV.
+;       Comment: Ranges from 44100 to 192000. Does not apply to MOD2WAV.
 ;
 FREQUENCY=48000
 
@@ -263,6 +263,13 @@
 ;         the frequency used for your audio input device (for sampling).
 ;
 SAMPLINGFREQ=44100
+
+; MOD2WAV output frequency
+;        Syntax: Number, in hertz
+; Default value: 44100
+;       Comment: Ranges from 44100 to 192000.
+;
+MOD2WAVFREQUENCY=44100
 
 ; Filter model (Amiga model)
 ;        Syntax: A500 or A1200
binary files a/release/win32/SDL2.dll b/release/win32/SDL2.dll differ
--- a/release/win32/protracker.ini
+++ b/release/win32/protracker.ini
@@ -252,7 +252,7 @@
 ; Audio output frequency
 ;        Syntax: Number, in hertz
 ; Default value: 48000
-;       Comment: Ranges from 44100 to 192000. Also applies to MOD2WAV.
+;       Comment: Ranges from 44100 to 192000. Does not apply to MOD2WAV.
 ;
 FREQUENCY=48000
 
@@ -263,6 +263,13 @@
 ;         the frequency used for your audio input device (for sampling).
 ;
 SAMPLINGFREQ=44100
+
+; MOD2WAV output frequency
+;        Syntax: Number, in hertz
+; Default value: 44100
+;       Comment: Ranges from 44100 to 192000.
+;
+MOD2WAVFREQUENCY=44100
 
 ; Filter model (Amiga model)
 ;        Syntax: A500 or A1200
binary files a/release/win64/SDL2.dll b/release/win64/SDL2.dll differ
--- a/release/win64/protracker.ini
+++ b/release/win64/protracker.ini
@@ -252,7 +252,7 @@
 ; Audio output frequency
 ;        Syntax: Number, in hertz
 ; Default value: 48000
-;       Comment: Ranges from 44100 to 192000. Also applies to MOD2WAV.
+;       Comment: Ranges from 44100 to 192000. Does not apply to MOD2WAV.
 ;
 FREQUENCY=48000
 
@@ -263,6 +263,13 @@
 ;         the frequency used for your audio input device (for sampling).
 ;
 SAMPLINGFREQ=44100
+
+; MOD2WAV output frequency
+;        Syntax: Number, in hertz
+; Default value: 44100
+;       Comment: Ranges from 44100 to 192000.
+;
+MOD2WAVFREQUENCY=44100
 
 ; Filter model (Amiga model)
 ;        Syntax: A500 or A1200
binary files a/src/gfx/bmp/bigyesnodialog.bmp /dev/null differ
binary files a/src/gfx/bmp/clear.bmp /dev/null differ
binary files a/src/gfx/bmp/mod2wav.bmp /dev/null differ
binary files a/src/gfx/bmp/pat2smpdialog.bmp /dev/null differ
binary files a/src/gfx/bmp/yesnodialog.bmp /dev/null differ
--- a/src/gfx/pt2_gfx_clear.c
+++ /dev/null
@@ -1,40 +1,0 @@
-#include <stdint.h>
-
-// Final unpack length: 4056
-// Decoded length: 1014 (first four bytes of buffer)
-const uint8_t clearDialogPackedBMP[525] =
-{
-	0x00,0x00,0x03,0xF6,0xCC,0x18,0x55,0x56,0xCC,0x18,0x55,0x5B,0x5A,0xCC,0x17,0xAA,
-	0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,
-	0x5A,0xAF,0xCC,0x06,0xFF,0xFA,0xAA,0xCC,0x0C,0xFF,0xEA,0xAF,0x5A,0xAE,0xCC,0x06,
-	0xAA,0xA6,0xAA,0xEA,0xCC,0x0B,0xAA,0x9A,0xAF,0x5A,0xAE,0xCC,0x06,0xAA,0xA6,0xAA,
-	0xEA,0xCC,0x0B,0xAA,0x9A,0xAF,0x5A,0xAE,0xA5,0x56,0x95,0x69,0x69,0x69,0x55,0xA6,
-	0xAA,0xEA,0x55,0x69,0x56,0x9A,0xA6,0x55,0x69,0x6A,0xA5,0x55,0xA5,0x56,0x9A,0xAF,
-	0x5A,0xAE,0x97,0xFF,0x5F,0x59,0x59,0x75,0xFF,0xE6,0xAA,0xE9,0x7F,0xF5,0xF5,0x96,
-	0x97,0x5F,0x59,0x7A,0xA5,0xFF,0xD7,0xFF,0x9A,0xAF,0x5A,0xAE,0xA5,0x5A,0x5E,0x5D,
-	0x55,0x75,0xD5,0xA6,0xAA,0xEA,0x55,0xA5,0x55,0xD5,0x57,0x55,0x7D,0x7A,0xA5,0x5A,
-	0xA5,0x5A,0x9A,0xAF,0x5A,0xAE,0xAB,0xD6,0x5E,0x5D,0x75,0x75,0xE5,0xE6,0xAA,0xEA,
-	0xBD,0x65,0xF5,0xD7,0xD7,0x5F,0xF9,0x7A,0xA5,0xFE,0xAB,0xD6,0x9A,0xAF,0x5A,0xAE,
-	0x95,0x5F,0x95,0x7D,0x79,0x79,0x55,0xE6,0xAA,0xE9,0x55,0xF5,0xE5,0xD7,0x97,0x5E,
-	0xA9,0x55,0x65,0x55,0x95,0x5F,0x9A,0xAF,0x5A,0xAE,0xAF,0xFE,0xAF,0xFA,0xFA,0xFA,
-	0xFF,0xE6,0xAA,0xEA,0xFF,0xEB,0xEB,0xEF,0xAF,0xBE,0xAA,0xFF,0xFB,0xFF,0xEF,0xFE,
-	0x9A,0xAF,0x5A,0xAE,0xCC,0x06,0xAA,0xA6,0xAA,0xEA,0xCC,0x0B,0xAA,0x9A,0xAF,0x5A,
-	0xA9,0xCC,0x06,0x55,0x56,0xAA,0x95,0xCC,0x0B,0x55,0x5A,0xAF,0x5A,0xCC,0x17,0xAA,
-	0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,
-	0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xAF,0xCC,0x06,0xFF,0xFA,0xAA,0xCC,0x0C,0xFF,0xEA,
-	0xAF,0x5A,0xAE,0xCC,0x06,0xAA,0xA6,0xAA,0xEA,0xCC,0x0B,0xAA,0x9A,0xAF,0x5A,0xAE,
-	0xCC,0x06,0xAA,0xA6,0xAA,0xEA,0xCC,0x0B,0xAA,0x9A,0xAF,0x5A,0xAE,0xAA,0x95,0x69,
-	0x6A,0xA5,0xAA,0xAA,0xA6,0xAA,0xEA,0xA9,0x56,0xA5,0x5A,0x5A,0x5A,0x55,0xA5,0x55,
-	0x96,0xAA,0xAA,0x9A,0xAF,0x5A,0xAE,0xAA,0x5F,0x59,0x7A,0xA5,0xEA,0xAA,0xA6,0xAA,
-	0xEA,0xA5,0xF5,0x97,0xD6,0x56,0x5D,0x7D,0x65,0xFF,0xD7,0xAA,0xAA,0x9A,0xAF,0x5A,
-	0xAE,0xAA,0x55,0x5D,0x7A,0xA5,0xEA,0xAA,0xA6,0xAA,0xEA,0xA5,0xEB,0xD5,0x57,0x55,
-	0x5D,0x7A,0xF5,0x5A,0x97,0xAA,0xAA,0x9A,0xAF,0x5A,0xAE,0xAA,0x5F,0x5D,0x7A,0xA5,
-	0xEA,0xAA,0xA6,0xAA,0xEA,0xA5,0xE5,0x97,0xD7,0x5D,0x5D,0x79,0x65,0xFE,0x97,0xAA,
-	0xAA,0x9A,0xAF,0x5A,0xAE,0xAA,0x5E,0x5D,0x55,0x65,0x55,0xAA,0xA6,0xAA,0xEA,0xA9,
-	0x57,0xD7,0x97,0x5E,0x5E,0x55,0xF5,0x55,0x95,0x56,0xAA,0x9A,0xAF,0x5A,0xAE,0xAA,
-	0xBE,0xBE,0xFF,0xFB,0xFF,0xEA,0xA6,0xAA,0xEA,0xAA,0xFF,0xAF,0xAF,0xBE,0xBE,0xBF,
-	0xEB,0xFF,0xEF,0xFF,0xAA,0x9A,0xAF,0x5A,0xAE,0xCC,0x06,0xAA,0xA6,0xAA,0xEA,0xCC,
-	0x0B,0xAA,0x9A,0xAF,0x5A,0xA9,0xCC,0x06,0x55,0x56,0xAA,0x95,0xCC,0x0B,0x55,0x5A,
-	0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,
-	0x5A,0xCC,0x17,0xAA,0xAF,0x6F,0xCC,0x18,0xFF,0xBF,0xCC,0x18,0xFF
-};
--- a/src/gfx/pt2_gfx_mod2wav.c
+++ /dev/null
@@ -1,45 +1,0 @@
-#include <stdint.h>
-
-// Final unpack length: 9216
-// Decoded length: 2304 (first four bytes of buffer)
-const uint8_t mod2wavPackedBMP[607] =
-{
-	0x00,0x00,0x09,0x00,0xCC,0x2E,0x55,0x56,0xCC,0x2E,0x55,0x5B,0x5A,0xCC,0x2D,0xAA,
-	0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,
-	0x5A,0xCC,0x08,0xAA,0x95,0x5A,0x55,0x59,0x69,0x65,0x56,0x95,0x56,0x55,0x6A,0x55,
-	0xA5,0xA5,0xA5,0x56,0xAA,0xA9,0xAA,0x69,0x56,0x95,0x5A,0x5A,0x59,0x6A,0xA5,0x55,
-	0xCC,0x08,0xAA,0xAF,0x5A,0xCC,0x08,0xAA,0x97,0xD6,0x5F,0xFD,0x59,0x75,0xF5,0x97,
-	0xFF,0x5F,0x5A,0x97,0xE5,0x65,0xD7,0xFF,0xAA,0xA9,0x69,0x75,0xF5,0x97,0xD6,0x5E,
-	0x5D,0x7A,0xA5,0xFF,0xEA,0xCC,0x07,0xAA,0xAF,0x5A,0xCC,0x04,0xAA,0xA9,0x55,0xAA,
-	0xAA,0x95,0x5F,0x55,0xA9,0x55,0x75,0xE5,0xD5,0x6A,0x55,0x7E,0x97,0xA5,0x55,0xD7,
-	0x56,0xAA,0xA9,0x55,0x75,0xE5,0xD7,0x97,0x5E,0x5D,0x7A,0xA5,0x5A,0xAA,0xAA,0x55,
-	0x6A,0xCC,0x04,0xAA,0xAF,0x5A,0xCC,0x05,0xAA,0xFF,0xEA,0xAA,0x97,0x5E,0x5F,0xE9,
-	0x75,0x75,0xE5,0xD7,0xFA,0x5D,0x7A,0x97,0xA5,0xD5,0xD7,0x97,0xAA,0xA9,0x7D,0x75,
-	0xE5,0xD7,0x97,0x5E,0x5D,0x7A,0xA5,0xFE,0xAA,0xAA,0xBF,0xFA,0xCC,0x04,0xAA,0xAF,
-	0x5A,0xCC,0x08,0xAA,0x97,0x96,0x55,0x59,0x79,0x75,0x57,0xD5,0x56,0x5E,0x5A,0x55,
-	0xA5,0xE5,0xE5,0x57,0xAA,0xA9,0x79,0x79,0x57,0xD5,0x5F,0x95,0x7D,0x55,0x65,0x55,
-	0xCC,0x08,0xAA,0xAF,0x5A,0xCC,0x08,0xAA,0xAF,0xAF,0xBF,0xFE,0xFA,0xFB,0xFF,0xAF,
-	0xFF,0xBE,0xBE,0xBF,0xEB,0xEB,0xEB,0xFF,0xAA,0xAA,0xFA,0xFA,0xFF,0xAF,0xFE,0xAF,
-	0xFA,0xFF,0xFB,0xFF,0xEA,0xCC,0x07,0xAA,0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,0x5A,0xCC,
-	0x2D,0xAA,0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,0x5A,0xA5,0xCC,0x2B,0x55,0x5A,0xAF,0x5A,
-	0xA5,0xCC,0x2B,0x55,0x5A,0xAF,0x5A,0xA5,0xCC,0x2B,0x55,0x5A,0xAF,0x5A,0xA5,0xCC,
-	0x2B,0x55,0x5A,0xAF,0x5A,0xA5,0xCC,0x2B,0x55,0x5A,0xAF,0x5A,0xA5,0xCC,0x2B,0x55,
-	0x5A,0xAF,0x5A,0xA5,0xCC,0x2B,0x55,0x5A,0xAF,0x5A,0xA5,0xCC,0x2B,0x55,0x5A,0xAF,
-	0x5A,0xA5,0xCC,0x2B,0x55,0x5A,0xAF,0x5A,0xA5,0xCC,0x2B,0x55,0x5A,0xAF,0x5A,0xA5,
-	0xCC,0x2B,0x55,0x5A,0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,0x5A,
-	0xCC,0x2D,0xAA,0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,0x5A,0xCC,
-	0x0F,0xAA,0xBF,0xCC,0x0B,0xFF,0xFA,0xCC,0x0F,0xAA,0xAF,0x5A,0xCC,0x0F,0xAA,0xBA,
-	0xCC,0x0B,0xAA,0xA6,0xCC,0x0F,0xAA,0xAF,0x5A,0xCC,0x0F,0xAA,0xBA,0xCC,0x0B,0xAA,
-	0xA6,0xCC,0x0F,0xAA,0xAF,0x5A,0xCC,0x0F,0xAA,0xBA,0xAA,0x55,0xA9,0x56,0x96,0x96,
-	0x95,0x69,0x55,0x65,0xAA,0xAA,0xA6,0xCC,0x0F,0xAA,0xAF,0x5A,0xCC,0x0F,0xAA,0xBA,
-	0xA9,0x7D,0x65,0xF5,0x95,0x97,0x5F,0x59,0x7F,0xF5,0xEA,0xAA,0xA6,0xCC,0x0F,0xAA,
-	0xAF,0x5A,0xCC,0x0F,0xAA,0xBA,0xA9,0x7A,0xF5,0x55,0xD5,0x57,0x5E,0xBD,0x56,0xA5,
-	0xEA,0xAA,0xA6,0xCC,0x0F,0xAA,0xAF,0x5A,0xCC,0x0F,0xAA,0xBA,0xA9,0x79,0x65,0xF5,
-	0xD7,0x57,0x5E,0x59,0x7F,0xA5,0xEA,0xAA,0xA6,0xCC,0x0F,0xAA,0xAF,0x5A,0xCC,0x0F,
-	0xAA,0xBA,0xAA,0x55,0xF5,0xE5,0xD7,0x97,0x95,0x7D,0x55,0x65,0x55,0xAA,0xA6,0xCC,
-	0x0F,0xAA,0xAF,0x5A,0xCC,0x0F,0xAA,0xBA,0xAA,0xBF,0xEB,0xEB,0xEF,0xAF,0xAF,0xFA,
-	0xFF,0xFB,0xFF,0xEA,0xA6,0xCC,0x0F,0xAA,0xAF,0x5A,0xCC,0x0F,0xAA,0xBA,0xCC,0x0B,
-	0xAA,0xA6,0xCC,0x0F,0xAA,0xAF,0x5A,0xCC,0x0F,0xAA,0xA5,0xCC,0x0B,0x55,0x56,0xCC,
-	0x0F,0xAA,0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,0x5A,0xCC,0x2D,
-	0xAA,0xAF,0x5A,0xCC,0x2D,0xAA,0xAF,0x6F,0xCC,0x2E,0xFF,0xBF,0xCC,0x2E,0xFF
-};
--- a/src/gfx/pt2_gfx_pat2smp_dialog.c
+++ /dev/null
@@ -1,40 +1,0 @@
-#include <stdint.h>
-
-// Final unpack length: 4056
-// Decoded length: 1014 (first four bytes of buffer)
-const uint8_t pat2SmpDialogPackedBMP[520] =
-{
-	0x00,0x00,0x03,0xF6,0xCC,0x18,0x55,0x56,0xCC,0x18,0x55,0x5B,0x5A,0xCC,0x17,0xAA,
-	0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,
-	0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xAA,0x55,0x6A,0x55,0xA9,
-	0x56,0x96,0x96,0xAA,0xAA,0x55,0xA5,0xA5,0xA5,0x5A,0x5A,0xAA,0x55,0xA5,0x55,0x96,
-	0x96,0xA5,0xAA,0xAF,0x5A,0xAA,0x5F,0x5A,0x97,0xE5,0xF5,0x97,0x5F,0xAA,0xA9,0x7D,
-	0x65,0xE5,0xD7,0xD6,0x5E,0xAA,0x97,0xEB,0x5F,0xD7,0x97,0xA5,0xEA,0xAF,0x5A,0xAA,
-	0x55,0x7E,0x97,0xA5,0xEB,0xD5,0x7E,0xAA,0xA9,0x76,0x75,0xE5,0xD5,0x57,0x5E,0xAA,
-	0x97,0xAA,0x5E,0xA5,0x5F,0xAB,0xEA,0xAF,0x5A,0xAA,0x5F,0xFA,0x97,0xA5,0xE5,0x97,
-	0x5A,0xAA,0xA9,0x75,0xB5,0xE5,0xD7,0xD7,0x5E,0xAA,0x97,0xAA,0x5E,0xA9,0x7E,0xA5,
-	0xAA,0xAF,0x5A,0xAA,0x5E,0xAA,0x55,0xA9,0x57,0xD7,0x96,0xAA,0xAA,0x59,0x69,0x57,
-	0xD7,0x97,0x55,0x5A,0x55,0xAA,0x5E,0xA9,0x7A,0xA5,0xEA,0xAF,0x5A,0xAA,0xBE,0xAA,
-	0xBF,0xEA,0xFF,0xAF,0xAF,0xAA,0xAA,0xBE,0xFA,0xFF,0xAF,0xAF,0xBF,0xFE,0xBF,0xEA,
-	0xBE,0xAA,0xFA,0xAB,0xEA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,
-	0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,
-	0xCC,0x17,0xAA,0xAF,0x5A,0xAA,0xCC,0x03,0xFF,0xEA,0xAA,0xCC,0x03,0xFF,0xFA,0xAA,
-	0xBF,0xCC,0x08,0xFF,0xAA,0xAF,0x5A,0xAA,0xEA,0xAA,0xAA,0xAA,0x9A,0xAA,0xEA,0xAA,
-	0xAA,0xAA,0xA6,0xAA,0xBA,0xCC,0x08,0xAA,0x6A,0xAF,0x5A,0xAA,0xEA,0xAA,0xAA,0xAA,
-	0x9A,0xAA,0xEA,0xAA,0xAA,0xAA,0xA6,0xAA,0xBA,0xCC,0x08,0xAA,0x6A,0xAF,0x5A,0xAA,
-	0xE9,0x69,0x69,0x56,0x9A,0xAA,0xE9,0x6A,0xA9,0x56,0xA6,0xAA,0xBA,0x95,0x69,0x55,
-	0xA9,0x56,0x95,0x5A,0x55,0x5A,0x6A,0xAF,0x5A,0xAA,0xE9,0x79,0x7A,0x5F,0x9A,0xAA,
-	0xE9,0x7A,0xA5,0xF5,0xA6,0xAA,0xBA,0x5F,0x59,0x7D,0x65,0xF5,0x97,0xD6,0xB5,0xFE,
-	0x6A,0xAF,0x5A,0xAA,0xE9,0x55,0x7A,0x5E,0x9A,0xAA,0xE9,0x7A,0xA5,0xE5,0xE6,0xAA,
-	0xBA,0x55,0x5D,0x55,0xF5,0xE5,0xD5,0x5F,0xA5,0xEA,0x6A,0xAF,0x5A,0xAA,0xE9,0x7D,
-	0x7A,0x5E,0x9A,0xAA,0xE9,0x7A,0xA5,0xE5,0xE6,0xAA,0xBA,0x5F,0x5D,0x7D,0x65,0xE5,
-	0xD7,0x5E,0xA5,0xEA,0x6A,0xAF,0x5A,0xAA,0xE9,0x79,0x79,0x56,0x9A,0xAA,0xE9,0x55,
-	0x69,0x57,0xE6,0xAA,0xBA,0x5E,0x5D,0x55,0xF9,0x57,0xD7,0x96,0xA5,0xEA,0x6A,0xAF,
-	0x5A,0xAA,0xEA,0xFA,0xFA,0xFF,0x9A,0xAA,0xEA,0xFF,0xFA,0xFF,0xA6,0xAA,0xBA,0xBE,
-	0xBE,0xFF,0xEA,0xFF,0xAF,0xAF,0xAB,0xEA,0x6A,0xAF,0x5A,0xAA,0xEA,0xAA,0xAA,0xAA,
-	0x9A,0xAA,0xEA,0xAA,0xAA,0xAA,0xA6,0xAA,0xBA,0xCC,0x08,0xAA,0x6A,0xAF,0x5A,0xAA,
-	0x95,0x55,0x55,0x55,0x5A,0xAA,0x95,0x55,0x55,0x55,0x56,0xAA,0xA5,0xCC,0x08,0x55,
-	0x6A,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,
-	0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,
-	0x6F,0xCC,0x18,0xFF,0xBF,0xCC,0x18,0xFF
-};
--- a/src/gfx/pt2_gfx_yes_no_dialog.c
+++ /dev/null
@@ -1,68 +1,0 @@
-#include <stdint.h>
-
-// Final unpack length: 4056
-// Decoded length: 1014 (first four bytes of buffer)
-const uint8_t yesNoDialogPackedBMP[476] =
-{
-	0x00,0x00,0x03,0xF6,0xCC,0x18,0x55,0x56,0xCC,0x18,0x55,0x5B,0x5A,0xCC,0x17,0xAA,
-	0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,
-	0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xAA,0x55,0xA5,0x56,0x95,
-	0x56,0xAA,0xA9,0x69,0x69,0x56,0x96,0x96,0xAA,0xAA,0x55,0x65,0xA5,0x95,0x5A,0x55,
-	0x59,0x55,0xAA,0xAF,0x5A,0xA9,0x7D,0x65,0xF5,0x97,0xFF,0xAA,0xA9,0x79,0x75,0xF5,
-	0x97,0x97,0xAA,0xA9,0x7F,0xF5,0xE5,0xD7,0xD6,0x5F,0xFE,0xFD,0x6A,0xAF,0x5A,0xA9,
-	0x55,0x75,0x57,0xD5,0x6A,0xAA,0xAA,0x55,0xF5,0xE5,0xD7,0x97,0xAA,0xAA,0x55,0xA5,
-	0xE5,0xD5,0x5F,0x55,0xAA,0x95,0xFA,0xAF,0x5A,0xA9,0x7D,0x75,0xD7,0x97,0xFA,0xAA,
-	0xAA,0x97,0xE5,0xE5,0xD7,0x97,0xAA,0xAA,0xBD,0x65,0xE5,0xD7,0x5E,0x5F,0xEA,0xAF,
-	0xEA,0xAF,0x5A,0xA9,0x79,0x75,0xE5,0x95,0x56,0xAA,0xAA,0x97,0xA9,0x57,0xE5,0x5F,
-	0xAA,0xA9,0x55,0xF9,0x57,0xD7,0x96,0x55,0x5A,0x96,0xAA,0xAF,0x5A,0xAA,0xFA,0xFB,
-	0xEB,0xEF,0xFF,0xAA,0xAA,0xAF,0xAA,0xFF,0xAB,0xFE,0xAA,0xAA,0xFF,0xEA,0xFF,0xAF,
-	0xAF,0xBF,0xFE,0xAF,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,
-	0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,
-	0xCC,0x17,0xAA,0xAF,0x5A,0xAA,0xAB,0xCC,0x05,0xFF,0xCC,0x08,0xAA,0xAF,0xCC,0x03,
-	0xFF,0xAA,0xAA,0xAF,0x5A,0xAA,0xAB,0xCC,0x05,0xAA,0x6A,0xCC,0x07,0xAA,0xAE,0xCC,
-	0x03,0xAA,0x6A,0xAA,0xAF,0x5A,0xAA,0xAB,0xCC,0x05,0xAA,0x6A,0xCC,0x07,0xAA,0xAE,
-	0xCC,0x03,0xAA,0x6A,0xAA,0xAF,0x5A,0xAA,0xAB,0xA5,0xA5,0x95,0x56,0x95,0x5A,0x6A,
-	0xCC,0x07,0xAA,0xAE,0x96,0x96,0x95,0x6A,0x6A,0xAA,0xAF,0x5A,0xAA,0xAB,0xA5,0xE5,
-	0xD7,0xFF,0x5F,0xFE,0x6A,0xCC,0x07,0xAA,0xAE,0x95,0x97,0x5F,0x5A,0x6A,0xAA,0xAF,
-	0x5A,0xAA,0xAB,0xA9,0x57,0xD5,0x5A,0x95,0x6A,0x6A,0xCC,0x07,0xAA,0xAE,0x95,0x57,
-	0x5E,0x5E,0x6A,0xAA,0xAF,0x5A,0xAA,0xAB,0xAA,0x5F,0x97,0xFE,0xAF,0x5A,0x6A,0xCC,
-	0x07,0xAA,0xAE,0x97,0x57,0x5E,0x5E,0x6A,0xAA,0xAF,0x5A,0xAA,0xAB,0xAA,0x5E,0x95,
-	0x56,0x55,0x7E,0x6A,0xCC,0x07,0xAA,0xAE,0x97,0x97,0x95,0x7E,0x6A,0xAA,0xAF,0x5A,
-	0xAA,0xAB,0xAA,0xBE,0xAF,0xFF,0xBF,0xFA,0x6A,0xCC,0x07,0xAA,0xAE,0xAF,0xAF,0xAF,
-	0xFA,0x6A,0xAA,0xAF,0x5A,0xAA,0xAB,0xCC,0x05,0xAA,0x6A,0xCC,0x07,0xAA,0xAE,0xCC,
-	0x03,0xAA,0x6A,0xAA,0xAF,0x5A,0xAA,0xAA,0xCC,0x05,0x55,0x6A,0xCC,0x07,0xAA,0xA9,
-	0xCC,0x03,0x55,0x6A,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,
-	0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,0xCC,0x17,0xAA,0xAF,0x5A,
-	0xCC,0x17,0xAA,0xAF,0x6F,0xCC,0x18,0xFF,0xBF,0xCC,0x18,0xFF
-};
-
-// Final unpack length: 11000
-// Decoded length: 2750 (first four bytes of buffer)
-const uint8_t bigYesNoDialogPackedBMP[472] =
-{
-	0x00,0x00,0x0A,0xBE,0xCC,0x30,0x55,0x56,0xCC,0x30,0x55,0x5B,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,
-	0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,
-	0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,
-	0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,
-	0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,
-	0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,
-	0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,
-	0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,
-	0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,
-	0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x0C,
-	0xAA,0xAB,0xCC,0x05,0xFF,0xCC,0x08,0xAA,0xAF,0xCC,0x03,0xFF,0xCC,0x0D,0xAA,0xAF,0x5A,0xCC,0x0C,0xAA,
-	0xAB,0xCC,0x05,0xAA,0x6A,0xCC,0x07,0xAA,0xAE,0xCC,0x03,0xAA,0x6A,0xCC,0x0C,0xAA,0xAF,0x5A,0xCC,0x0C,
-	0xAA,0xAB,0xCC,0x05,0xAA,0x6A,0xCC,0x07,0xAA,0xAE,0xCC,0x03,0xAA,0x6A,0xCC,0x0C,0xAA,0xAF,0x5A,0xCC,
-	0x0C,0xAA,0xAB,0xA5,0xA5,0x95,0x56,0x95,0x5A,0x6A,0xCC,0x07,0xAA,0xAE,0x96,0x96,0x95,0x6A,0x6A,0xCC,
-	0x0C,0xAA,0xAF,0x5A,0xCC,0x0C,0xAA,0xAB,0xA5,0xE5,0xD7,0xFF,0x5F,0xFE,0x6A,0xCC,0x07,0xAA,0xAE,0x95,
-	0x97,0x5F,0x5A,0x6A,0xCC,0x0C,0xAA,0xAF,0x5A,0xCC,0x0C,0xAA,0xAB,0xA9,0x57,0xD5,0x5A,0x95,0x6A,0x6A,
-	0xCC,0x07,0xAA,0xAE,0x95,0x57,0x5E,0x5E,0x6A,0xCC,0x0C,0xAA,0xAF,0x5A,0xCC,0x0C,0xAA,0xAB,0xAA,0x5F,
-	0x97,0xFE,0xAF,0x5A,0x6A,0xCC,0x07,0xAA,0xAE,0x97,0x57,0x5E,0x5E,0x6A,0xCC,0x0C,0xAA,0xAF,0x5A,0xCC,
-	0x0C,0xAA,0xAB,0xAA,0x5E,0x95,0x56,0x55,0x7E,0x6A,0xCC,0x07,0xAA,0xAE,0x97,0x97,0x95,0x7E,0x6A,0xCC,
-	0x0C,0xAA,0xAF,0x5A,0xCC,0x0C,0xAA,0xAB,0xAA,0xBE,0xAF,0xFF,0xBF,0xFA,0x6A,0xCC,0x07,0xAA,0xAE,0xAF,
-	0xAF,0xAF,0xFA,0x6A,0xCC,0x0C,0xAA,0xAF,0x5A,0xCC,0x0C,0xAA,0xAB,0xCC,0x05,0xAA,0x6A,0xCC,0x07,0xAA,
-	0xAE,0xCC,0x03,0xAA,0x6A,0xCC,0x0C,0xAA,0xAF,0x5A,0xCC,0x0D,0xAA,0xCC,0x05,0x55,0x6A,0xCC,0x07,0xAA,
-	0xA9,0xCC,0x03,0x55,0x6A,0xCC,0x0C,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,0xCC,0x2F,0xAA,0xAF,0x5A,
-	0xCC,0x2F,0xAA,0xAF,0x6F,0xCC,0x30,0xFF,0xBF,0xCC,0x30,0xFF
-};
-
--- /dev/null
+++ b/src/pt2_amigafilters.c
@@ -1,0 +1,397 @@
+/* Amiga 500 / Amiga 1200 filter implementation.
+**
+** Route:
+** Paula output -> low-pass filter -> LED filter (if turned on) -> high-pass filter (centering of waveform)
+*/
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "pt2_structs.h"
+#include "pt2_audio.h"
+#include "pt2_paula.h"
+#include "pt2_rcfilter.h"
+#include "pt2_math.h"
+#include "pt2_textout.h"
+
+typedef struct ledFilter_t
+{
+	double LIn1, LIn2, LOut1, LOut2;
+	double RIn1, RIn2, ROut1, ROut2;
+	double a1, a2, a3, b1, b2;
+} ledFilter_t;
+
+static int32_t filterModel;
+static bool ledFilterEnabled, useA1200LowPassFilter;
+static rcFilter_t filterLoA500, filterHiA500, filterLoA1200, filterHiA1200;
+static ledFilter_t filterLED;
+
+static void processFiltersA1200_NoLED(double *dBufferL, double *dBufferR, int32_t numSamples);
+static void processFiltersA1200_LED(double *dBufferL, double *dBufferR, int32_t numSamples);
+static void processFiltersA500_NoLED(double *dBufferL, double *dBufferR, int32_t numSamples);
+static void processFiltersA500_LED(double *dBufferL, double *dBufferR, int32_t numSamples);
+
+void (*processAmigaFilters)(double *, double *, int32_t);
+
+// --------------------------------------------------------
+// Crude LED filter implementation
+// --------------------------------------------------------
+
+void clearLEDFilterState(ledFilter_t *f)
+{
+	f->LIn1 = f->LIn2 = f->LOut1 = f->LOut2 = 0.0;
+	f->RIn1 = f->RIn2 = f->ROut1 = f->ROut2 = 0.0;
+}
+
+static void calcLEDFilterCoeffs(double sr, double hz, double qfactor, ledFilter_t *filter)
+{
+	const double c = 1.0 / pt2_tan((PT2_PI * hz) / sr);
+	const double r = 1.0 / qfactor;
+
+	filter->a1 = 1.0 / (1.0 + r * c + c * c);
+	filter->a2 = 2.0 * filter->a1;
+	filter->a3 = filter->a1;
+	filter->b1 = 2.0 * (1.0 - c*c) * filter->a1;
+	filter->b2 = (1.0 - r * c + c * c) * filter->a1;
+}
+
+static void LEDFilter(ledFilter_t *f, const double *in, double *out)
+{
+	const double LOut = (f->a1 * in[0]) + (f->a2 * f->LIn1) + (f->a3 * f->LIn2) - (f->b1 * f->LOut1) - (f->b2 * f->LOut2);
+	const double ROut = (f->a1 * in[1]) + (f->a2 * f->RIn1) + (f->a3 * f->RIn2) - (f->b1 * f->ROut1) - (f->b2 * f->ROut2);
+
+	// shift states
+
+	f->LIn2 = f->LIn1;
+	f->LIn1 = in[0];
+	f->LOut2 = f->LOut1;
+	f->LOut1 = LOut;
+
+	f->RIn2 = f->RIn1;
+	f->RIn1 = in[1];
+	f->ROut2 = f->ROut1;
+	f->ROut1 = ROut;
+
+	// set output
+	out[0] = LOut;
+	out[1] = ROut;
+}
+
+// --------------------------------------------------------
+// --------------------------------------------------------
+
+void setupAmigaFilters(double dAudioFreq)
+{
+	/* Amiga 500/1200 filter emulation
+	**
+	** aciddose:
+	** First comes a static low-pass 6dB formed by the supply current
+	** from the Paula's mixture of channels A+B / C+D into the opamp with
+	** 0.1uF capacitor and 360 ohm resistor feedback in inverting mode biased by
+	** dac vRef (used to center the output).
+	**
+	** R = 360 ohm
+	** C = 0.1uF
+	** Low Hz = 4420.97~ = 1 / (2pi * 360 * 0.0000001)
+	**
+	** Under spice simulation the circuit yields -3dB = 4400Hz.
+	** In the Amiga 1200, the low-pass cutoff is ~34kHz, so the
+	** static low-pass filter is disabled in the mixer in A1200 mode.
+	**
+	** Next comes a bog-standard Sallen-Key filter ("LED") with:
+	** R1 = 10K ohm
+	** R2 = 10K ohm
+	** C1 = 6800pF
+	** C2 = 3900pF
+	** Q ~= 1/sqrt(2)
+	**
+	** This filter is optionally bypassed by an MPF-102 JFET chip when
+	** the LED filter is turned off.
+	**
+	** Under spice simulation the circuit yields -3dB = 2800Hz.
+	** 90 degrees phase = 3000Hz (so, should oscillate at 3kHz!)
+	**
+	** The buffered output of the Sallen-Key passes into an RC high-pass with:
+	** R = 1.39K ohm (1K ohm + 390 ohm)
+	** C = 22uF (also C = 330nF, for improved high-frequency)
+	**
+	** High Hz = 5.2~ = 1 / (2pi * 1390 * 0.000022)
+	** Under spice simulation the circuit yields -3dB = 5.2Hz.
+	**
+	** 8bitbubsy:
+	** Keep in mind that many of the Amiga schematics that are floating around on
+	** the internet have wrong RC values! They were most likely very early schematics
+	** that didn't change before production (or changes that never reached production).
+	** This has been confirmed by measuring the components on several Amiga motherboards.
+	**
+	** Correct values for A500, >rev3 (?) (A500_R6.pdf):
+	** - 1-pole RC 6dB/oct low-pass: R=360 ohm, C=0.1uF
+	** - Sallen-key low-pass ("LED"): R1/R2=10k ohm, C1=6800pF, C2=3900pF
+	** - 1-pole RC 6dB/oct high-pass: R=1390 ohm (1000+390), C=22.33uF (22+0.33)
+	**
+	** Correct values for A1200, all revs (A1200_R2.pdf):
+	** - 1-pole RC 6dB/oct low-pass: R=680 ohm, C=6800pF
+	** - Sallen-key low-pass ("LED"): R1/R2=10k ohm, C1=6800pF, C2=3900pF (same as A500)
+	** - 1-pole RC 6dB/oct high-pass: R=1390 ohm (1000+390), C=22uF
+	*/
+	double R, C, R1, R2, C1, C2, cutoff, qfactor;
+
+	if (audio.oversamplingFlag)
+		dAudioFreq *= 2.0; // 2x oversampling
+
+	const bool audioWasntLocked = !audio.locked;
+	if (audioWasntLocked)
+		lockAudio();
+
+	// A500 1-pole (6db/oct) static RC low-pass filter:
+	R = 360.0; // R321 (360 ohm)
+	C = 1e-7;  // C321 (0.1uF)
+	cutoff = 1.0 / (PT2_TWO_PI * R * C); // ~4420.971Hz
+	calcRCFilterCoeffs(dAudioFreq, cutoff, &filterLoA500);
+
+	// (optional) A1200 1-pole (6db/oct) static RC low-pass filter:
+	R = 680.0;  // R321 (680 ohm)
+	C = 6.8e-9; // C321 (6800pF)
+	cutoff = 1.0 / (PT2_TWO_PI * R * C); // ~34419.322Hz
+
+	useA1200LowPassFilter = false;
+	if (dAudioFreq/2.0 > cutoff)
+	{
+		calcRCFilterCoeffs(dAudioFreq, cutoff, &filterLoA1200);
+		useA1200LowPassFilter = true;
+	}
+
+	// Sallen-Key low-pass filter ("LED" filter, same values on A500/A1200):
+	R1 = 10000.0; // R322 (10K ohm)
+	R2 = 10000.0; // R323 (10K ohm)
+	C1 = 6.8e-9;  // C322 (6800pF)
+	C2 = 3.9e-9;  // C323 (3900pF)
+	cutoff = 1.0 / (PT2_TWO_PI * pt2_sqrt(R1 * R2 * C1 * C2)); // ~3090.533Hz
+	qfactor = pt2_sqrt(R1 * R2 * C1 * C2) / (C2 * (R1 + R2)); // ~0.660225
+	calcLEDFilterCoeffs(dAudioFreq, cutoff, qfactor, &filterLED);
+
+	// A500 1-pole (6dB/oct) static RC high-pass filter:
+	R = 1390.0;   // R324 (1K ohm) + R325 (390 ohm)
+	C = 2.233e-5; // C334 (22uF) + C335 (0.33uF)
+	cutoff = 1.0 / (PT2_TWO_PI * R * C); // ~5.128Hz
+	calcRCFilterCoeffs(dAudioFreq, cutoff, &filterHiA500);
+
+	// A1200 1-pole (6dB/oct) static RC high-pass filter:
+	R = 1390.0; // R324 (1K ohm resistor) + R325 (390 ohm resistor)
+	C = 2.2e-5; // C334 (22uF capacitor)
+	cutoff = 1.0 / (PT2_TWO_PI * R * C); // ~5.205Hz
+	calcRCFilterCoeffs(dAudioFreq, cutoff, &filterHiA1200);
+
+	if (audioWasntLocked)
+		unlockAudio();
+}
+
+void resetAmigaFilterStates(void)
+{
+	const bool audioWasntLocked = !audio.locked;
+	if (audioWasntLocked)
+		lockAudio();
+
+	clearRCFilterState(&filterLoA500);
+	clearRCFilterState(&filterLoA1200);
+	clearRCFilterState(&filterHiA500);
+	clearRCFilterState(&filterHiA1200);
+	clearLEDFilterState(&filterLED);
+
+	if (audioWasntLocked)
+		unlockAudio();
+}
+
+static void processFiltersA1200_NoLED(double *dBufferL, double *dBufferR, int32_t numSamples)
+{
+	if (useA1200LowPassFilter)
+	{
+		for (int32_t i = 0; i < numSamples; i++)
+		{
+			double dOut[2];
+
+			dOut[0] = dBufferL[i];
+			dOut[1] = dBufferR[i];
+
+			// low-pass filter
+			RCLowPassFilterStereo(&filterLoA1200, dOut, dOut);
+
+			// high-pass RC filter
+			RCHighPassFilterStereo(&filterHiA1200, dOut, dOut);
+
+			dBufferL[i] = dOut[0];
+			dBufferR[i] = dOut[1];
+		}
+	}
+	else
+	{
+		for (int32_t i = 0; i < numSamples; i++)
+		{
+			double dOut[2];
+
+			dOut[0] = dBufferL[i];
+			dOut[1] = dBufferR[i];
+
+			// high-pass RC filter
+			RCHighPassFilterStereo(&filterHiA1200, dOut, dOut);
+
+			dBufferL[i] = dOut[0];
+			dBufferR[i] = dOut[1];
+		}
+	}
+}
+
+static void processFiltersA1200_LED(double *dBufferL, double *dBufferR, int32_t numSamples)
+{
+	if (useA1200LowPassFilter)
+	{
+		for (int32_t i = 0; i < numSamples; i++)
+		{
+			double dOut[2];
+
+			dOut[0] = dBufferL[i];
+			dOut[1] = dBufferR[i];
+
+			// low-pass filter
+			RCLowPassFilterStereo(&filterLoA1200, dOut, dOut);
+
+			// "LED" Sallen-Key filter
+			LEDFilter(&filterLED, dOut, dOut);
+
+			// high-pass RC filter
+			RCHighPassFilterStereo(&filterHiA1200, dOut, dOut);
+
+			dBufferL[i] = dOut[0];
+			dBufferR[i] = dOut[1];
+		}
+	}
+	else
+	{
+		for (int32_t i = 0; i < numSamples; i++)
+		{
+			double dOut[2];
+
+			dOut[0] = dBufferL[i];
+			dOut[1] = dBufferR[i];
+
+			// "LED" Sallen-Key filter
+			LEDFilter(&filterLED, dOut, dOut);
+
+			// high-pass RC filter
+			RCHighPassFilterStereo(&filterHiA1200, dOut, dOut);
+
+			dBufferL[i] = dOut[0];
+			dBufferR[i] = dOut[1];
+		}
+	}
+}
+
+static void processFiltersA500_NoLED(double *dBufferL, double *dBufferR, int32_t numSamples)
+{
+	for (int32_t i = 0; i < numSamples; i++)
+	{
+		double dOut[2];
+
+		dOut[0] = dBufferL[i];
+		dOut[1] = dBufferR[i];
+
+		// low-pass RC filter
+		RCLowPassFilterStereo(&filterLoA500, dOut, dOut);
+
+		// high-pass RC filter
+		RCHighPassFilterStereo(&filterHiA500, dOut, dOut);
+
+		dBufferL[i] = dOut[0];
+		dBufferR[i] = dOut[1];
+	}
+}
+
+static void processFiltersA500_LED(double *dBufferL, double *dBufferR, int32_t numSamples)
+{
+	for (int32_t i = 0; i < numSamples; i++)
+	{
+		double dOut[2];
+
+		dOut[0] = dBufferL[i];
+		dOut[1] = dBufferR[i];
+
+		// low-pass RC filter
+		RCLowPassFilterStereo(&filterLoA500, dOut, dOut);
+
+		// "LED" Sallen-Key filter
+		LEDFilter(&filterLED, dOut, dOut);
+
+		// high-pass RC filter
+		RCHighPassFilterStereo(&filterHiA500, dOut, dOut);
+
+		dBufferL[i] = dOut[0];
+		dBufferR[i] = dOut[1];
+	}
+}
+
+static void updateAmigaFilterFunctions(void)
+{
+	if (filterModel == FILTERMODEL_A500)
+	{
+		if (ledFilterEnabled)
+			processAmigaFilters = processFiltersA500_LED;
+		else
+			processAmigaFilters = processFiltersA500_NoLED;
+	}
+	else // A1200
+	{
+		if (ledFilterEnabled)
+			processAmigaFilters = processFiltersA1200_LED;
+		else
+			processAmigaFilters = processFiltersA1200_NoLED;
+	}
+}
+
+void setAmigaFilterModel(uint8_t model)
+{
+	const bool audioWasntLocked = !audio.locked;
+	if (audioWasntLocked)
+		lockAudio();
+
+	filterModel = model;
+	updateAmigaFilterFunctions();
+
+	if (audioWasntLocked)
+		unlockAudio();
+}
+
+void setLEDFilter(bool state)
+{
+	if (ledFilterEnabled == state)
+		return; // same state as before!
+
+	const bool audioWasntLocked = !audio.locked;
+	if (audioWasntLocked)
+		lockAudio();
+
+	clearLEDFilterState(&filterLED);
+	ledFilterEnabled = editor.useLEDFilter;
+	updateAmigaFilterFunctions();
+
+	if (audioWasntLocked)
+		unlockAudio();
+}
+
+void toggleAmigaFilterModel(void)
+{
+	const bool audioWasntLocked = !audio.locked;
+	if (audioWasntLocked)
+		lockAudio();
+
+	resetAmigaFilterStates();
+
+	filterModel ^= 1;
+	updateAmigaFilterFunctions();
+
+	if (audioWasntLocked)
+		unlockAudio();
+
+	if (filterModel == FILTERMODEL_A500)
+		displayMsg("AUDIO: AMIGA 500");
+	else
+		displayMsg("AUDIO: AMIGA 1200");
+}
--- /dev/null
+++ b/src/pt2_amigafilters.h
@@ -1,0 +1,12 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+void setupAmigaFilters(double dAudioFreq);
+void resetAmigaFilterStates(void);
+void setAmigaFilterModel(uint8_t amigaModel);
+void setLEDFilter(bool state);
+void toggleAmigaFilterModel(void);
+
+void (*processAmigaFilters)(double *, double *, int32_t);
--- /dev/null
+++ b/src/pt2_askbox.c
@@ -1,0 +1,450 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include "pt2_textout.h"
+#include "pt2_visuals.h"
+#include "pt2_mouse.h"
+#include "pt2_structs.h"
+#include "pt2_sync.h"
+#include "pt2_keyboard.h"
+#include "pt2_diskop.h"
+#include "pt2_mod2wav.h"
+#include "pt2_pat2smp.h"
+#include "pt2_askbox.h"
+
+#define INIT_BUTTONS(num, abortRetVal, defRetVal) \
+d.numButtons = num; \
+d.abortReturnValue = abortRetVal; \
+d.defaultReturnValue = defRetVal;
+
+#define SET_DIALOG(xx, yy, ww, hh) \
+d.x = xx; \
+d.y = yy; \
+d.w = ww; \
+d.h = hh;
+
+#define SET_BUTTON(i, invert, label, key, retVal, xx1, xx2, yy1, yy2) \
+strcpy(d.buttons[i].text, label); \
+d.buttons[i].repeat = false; \
+d.buttons[i].inverted = invert; \
+d.buttons[i].callback = NULL; \
+d.buttons[i].keyBinding = key; \
+d.buttons[i].returnValue = retVal; \
+d.buttons[i].clickableWidth = 0; \
+d.buttons[i].x1 = xx1; \
+d.buttons[i].x2 = xx2; \
+d.buttons[i].y1 = yy1; \
+d.buttons[i].y2 = yy2;
+
+#define SET_CALLBACK_BUTTON(i, label, func, clickWidth, xx1, xx2, yy1, yy2, doRepeat) \
+strcpy(d.buttons[i].text, label); \
+d.buttons[i].repeat = true; \
+d.buttons[i].inverted = false; \
+d.buttons[i].callback = func; \
+d.buttons[i].clickableWidth = clickWidth; \
+d.buttons[i].x1 = xx1; \
+d.buttons[i].x2 = xx2; \
+d.buttons[i].y1 = yy1; \
+d.buttons[i].y2 = yy2;
+
+typedef struct choice_t
+{
+	void (*callback)(void);
+	bool inverted, repeat;
+	int16_t x1, y1, x2, y2, clickableWidth;
+	SDL_Keycode keyBinding;
+	int16_t returnValue;
+	char text[32];
+} button_t;
+
+typedef struct dialog_t
+{
+	bool bigDialog;
+	int16_t x, y, w, h, numButtons, defaultReturnValue, abortReturnValue;
+	button_t buttons[16];
+} dialog_t;
+
+typedef struct askBoxData_t // for thread-safe version of askBox()
+{
+	volatile bool active;
+	uint32_t dialogType, returnValue;
+	const char *statusText;
+} askBoxData_t;
+
+static int32_t buttonToRepeat = -1;
+static askBoxData_t askBoxData;
+
+static void drawDialog(dialog_t *d)
+{
+	// render dialog
+	drawFramework3(d->x, d->y, d->w, d->h);
+
+	// render buttons
+	for (int32_t i = 0; i < d->numButtons; i++)
+	{
+		button_t *b = &d->buttons[i];
+		if (b->inverted)
+			drawButton2(b->x1, b->y1, (b->x2 - b->x1) + 1, (b->y2 - b->y1) + 1, b->text);
+		else
+			drawButton1(b->x1, b->y1, (b->x2 - b->x1) + 1, (b->y2 - b->y1) + 1, b->text);
+	}
+}
+
+void removeAskBox(void)
+{
+	ui.disableVisualizer = false;
+	ui.askBoxShown = false;
+
+	if (ui.diskOpScreenShown)
+	{
+		diskOpRenderFileList();
+	}
+	else if (ui.posEdScreenShown)
+	{
+		renderPosEdScreen();
+		ui.updatePosEd = true;
+	}
+	else if (ui.editOpScreenShown)
+	{
+		renderEditOpScreen();
+	}
+	else if (ui.aboutScreenShown)
+	{
+		renderAboutScreen();
+	}
+	else
+	{
+		if (ui.visualizerMode == VISUAL_QUADRASCOPE)
+			renderQuadrascopeBg();
+		else if (ui.visualizerMode == VISUAL_SPECTRUM)
+			renderSpectrumAnalyzerBg();
+
+		updateVisualizer(); // will draw one frame of the visualizer in use
+	}
+}
+
+void handleThreadedAskBox(void) // rain from main input/video loop
+{
+	if (askBoxData.active)
+	{
+		askBoxData.returnValue = askBox(askBoxData.dialogType, askBoxData.statusText);
+		askBoxData.active = false;
+	}
+}
+
+uint32_t askBoxThreadSafe(uint32_t dialogType, const char *statusText)
+{
+	if (!editor.mainLoopOngoing)
+		return 0; // main loop was not even started yet, bail out.
+
+	// block multiple calls before they are completed (for safety)
+	while (askBoxData.active)
+		SDL_Delay(1000 / VBLANK_HZ); // accuracy is not important here
+
+	askBoxData.dialogType = dialogType;
+	askBoxData.statusText = statusText;
+	askBoxData.active = true;
+
+	while (askBoxData.active)
+		SDL_Delay(1000 / VBLANK_HZ); // accuracy is not important here
+
+	return askBoxData.returnValue;
+}
+
+uint32_t askBox(uint32_t dialogType, const char *statusText)
+{
+	uint32_t returnValue = 0;
+	dialog_t d;
+
+	assert(dialogType < ASKBOX_NUM);
+	if (dialogType >= ASKBOX_NUM)
+		return ASKBOX_NO;
+
+	editor.errorMsgActive = false;
+	editor.errorMsgBlock = false;
+	editor.errorMsgCounter = 0;
+
+	editor.blockMarkFlag = false;
+	ui.introTextShown = false; // kludge :-)
+	ui.disableVisualizer = true;
+	ui.askBoxShown = true;
+
+	SDL_EventState(SDL_DROPFILE, SDL_DISABLE);
+
+	// setup dialog based on type
+	switch (dialogType)
+	{
+		default:
+		case ASKBOX_YES_NO:
+		{
+			// input: x, y, width, height
+			SET_DIALOG(160, 51, 104, 39);
+
+			// input: number of buttons, abort return-value (esc / right mouse button), default return-value (enter/return)
+			INIT_BUTTONS(2, ASKBOX_NO, ASKBOX_YES);
+
+			// input: button number, inverted type, keybinding, return-value, x1, x2, y1, y2
+			SET_BUTTON(0, true, "YES", SDLK_y, ASKBOX_YES, 171, 196, 71, 81);
+			SET_BUTTON(1, true, "NO",  SDLK_n, ASKBOX_NO,  234, 252, 71, 81);
+
+			drawDialog(&d);
+
+			textOut2(166, 59, "ARE YOU SURE?");
+		}
+		break;
+
+		case ASKBOX_CLEAR:
+		{
+			SET_DIALOG(160, 51, 104, 39);
+			INIT_BUTTONS(4, ASKBOX_CLEAR_CANCEL, ASKBOX_CLEAR_CANCEL);
+			SET_BUTTON(0, true, "SONG",    SDLK_o, ASKBOX_CLEAR_SONG,    166, 198, 57, 67);
+			SET_BUTTON(1, true, "SAMPLES", SDLK_s, ASKBOX_CLEAR_SAMPLES, 204, 257, 57, 67);
+			SET_BUTTON(2, true, "ALL",     SDLK_a, ASKBOX_CLEAR_ALL,     166, 198, 73, 83);
+			SET_BUTTON(3, true, "CANCEL",  SDLK_c, ASKBOX_CLEAR_CANCEL,  204, 257, 73, 83);
+			drawDialog(&d);
+		}
+		break;
+
+		case ASKBOX_PAT2SMP:
+		{
+			SET_DIALOG(120, 44, 200, 55);
+			INIT_BUTTONS(10, 0, 1);
+	
+			SET_BUTTON(0, false, "RENDER TO SAMPLE", SDLK_r, 1, 124, 246, 84, 94);
+			SET_BUTTON(1, false, "EXIT",             SDLK_e, 0, 258, 315, 84, 94);
+
+			// input: button number, text, keybinding, return-value, x1, x2, y1, y2, repeat button
+			SET_CALLBACK_BUTTON(2, ARROW_UP_STR,   pat2SmpNoteUp,       0, 191, 201, 48, 58, true);
+			SET_CALLBACK_BUTTON(3, ARROW_DOWN_STR, pat2SmpNoteDown,     0, 202, 212, 48, 58, true);
+			SET_CALLBACK_BUTTON(4, ARROW_UP_STR,   pat2SmpStartRowUp,   0, 294, 304, 48, 58, true);
+			SET_CALLBACK_BUTTON(5, ARROW_DOWN_STR, pat2SmpStartRowDown, 0, 305, 315, 48, 58, true);
+			SET_CALLBACK_BUTTON(6, ARROW_UP_STR,   pat2SmpFinetuneUp,   0, 191, 201, 59, 69, true);
+			SET_CALLBACK_BUTTON(7, ARROW_DOWN_STR, pat2SmpFinetuneDown, 0, 202, 212, 59, 69, true);
+			SET_CALLBACK_BUTTON(8, ARROW_UP_STR,   pat2SmpRowsUp,       0, 294, 304, 59, 69, true);
+			SET_CALLBACK_BUTTON(9, ARROW_DOWN_STR, pat2SmpRowsDown,     0, 305, 315, 59, 69, true);
+
+			drawDialog(&d);
+
+			drawFramework1(163, 48, 28, 11);
+			drawFramework1(274, 48, 20, 11);
+			drawFramework1(163, 59, 28, 11);
+			drawFramework1(274, 59, 20, 11);
+
+			pat2SmpDrawNote();
+			pat2SmpDrawStartRow();
+			pat2SmpDrawRows();
+			pat2SmpDrawFinetune();
+			pat2SmpCalculateFreq();
+
+			textOut2(127, 50, "NOTE");
+			textOut2(217, 50, "ROW BEG.");
+			textOut2(124, 61, "FTUNE");
+			textOut2(223, 61, "# ROWS");
+			textOut2(124, 74, "FREQ.");
+		}
+		break;
+
+		case ASKBOX_DOWNSAMPLE: // sample loader (AIFF/WAV w/ rate >22kHz)
+		{
+			SET_DIALOG(120, 44, 200, 55);
+			INIT_BUTTONS(2, ASKBOX_NO, ASKBOX_YES);
+			SET_BUTTON(0, true, "YES", SDLK_y, ASKBOX_YES, 179, 204, 83, 93);
+			SET_BUTTON(1, true, "NO",  SDLK_n, ASKBOX_NO,  242, 260, 83, 93);
+			drawDialog(&d);
+
+			textOut2(133, 49, "THE SAMPLE'S FREQUENCY IS");
+			textOut2(154, 57, "HIGH (ABOVE 22KHZ).");
+			textOut2(133, 65, "DO YOU WANT TO DOWNSAMPLE");
+			textOut2(156, 73, "BEFORE LOADING IT?");
+		}
+		break;
+
+		case ASKBOX_MOD2WAV:
+		{
+			SET_DIALOG(138, 44, 165, 55);
+			INIT_BUTTONS(7, ASKBOX_NO, ASKBOX_YES);
+
+			SET_BUTTON(0, false, "RENDER TO WAV", SDLK_r, ASKBOX_YES, 142, 246, 84, 94);
+			SET_BUTTON(1, false, "EXIT",          SDLK_e, ASKBOX_NO,  257, 298, 84, 94);
+
+			SET_CALLBACK_BUTTON(2, " ",            toggleMod2WavFadeout, 152, 142, 151, 48, 56, false);
+			SET_CALLBACK_BUTTON(3, ARROW_UP_STR,   mod2WavFadeoutUp,       0, 277, 287, 59, 69, true);
+			SET_CALLBACK_BUTTON(4, ARROW_DOWN_STR, mod2WavFadeoutDown,     0, 288, 298, 59, 69, true);
+			SET_CALLBACK_BUTTON(5, ARROW_UP_STR,   mod2WavLoopCountUp,     0, 277, 287, 70, 80, true);
+			SET_CALLBACK_BUTTON(6, ARROW_DOWN_STR, mod2WavLoopCountDown,   0, 288, 298, 70, 80, true);
+
+			drawDialog(&d);
+
+			drawFramework1(257, 59, 20, 11);
+			drawFramework1(257, 70, 20, 11);
+
+			textOut2(154, 50, "FADE OUT END OF SONG");
+			textOut2(142, 62, "FADEOUT SECONDS");
+			textOut2(142, 73, "SONG LOOP COUNT");
+
+			mod2WavDrawFadeoutToggle();
+			mod2WavDrawFadeoutSeconds();
+			mod2WavDrawLoopCount();
+		}
+	}
+
+	pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
+	if (statusText != NULL)
+		setStatusMessage(statusText, NO_CARRY);
+
+	mouse.leftButtonPressed = false;
+	mouse.buttonWaiting = false;
+	mouse.buttonWaitCounter = 0;
+	mouse.repeatCounter = 0;
+
+	// main loop here
+	// XXX: if you change anything in the main rendering loop, make sure it goes in here too (if needed)
+
+	bool loopRunning = true;
+	while (loopRunning)
+	{
+		SDL_Event event;
+
+		sinkVisualizerBars();
+		updateChannelSyncBuffer();
+		readMouseXY();
+
+		while (SDL_PollEvent(&event))
+		{
+			if (event.type == SDL_WINDOWEVENT)
+			{
+				if (event.window.event == SDL_WINDOWEVENT_HIDDEN)
+					video.windowHidden = true;
+				else if (event.window.event == SDL_WINDOWEVENT_SHOWN)
+					video.windowHidden = false;
+
+				// reset vblank end time if we minimize window
+				if (event.window.event == SDL_WINDOWEVENT_MINIMIZED || event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
+					hpc_ResetEndTime(&video.vblankHpc);
+			}
+			else if (event.type == SDL_KEYDOWN)
+			{
+				SDL_Keycode key = event.key.keysym.sym;
+
+				// abort (escape key)
+				if (key == SDLK_ESCAPE)
+				{
+					returnValue = d.abortReturnValue;
+
+					loopRunning = false;
+					break;
+				}
+
+				// default action (return/enter key)
+				if (key == SDLK_RETURN || key == SDLK_KP_ENTER)
+				{
+					returnValue = d.defaultReturnValue;
+
+					loopRunning = false;
+					break;
+				}
+
+				// test keybindings
+				for (int32_t i = 0; i < d.numButtons; i++)
+				{
+					button_t *b = &d.buttons[i];
+					if (b->callback == NULL && key == b->keyBinding)
+					{
+						returnValue = b->returnValue;
+
+						loopRunning = false;
+						break;
+					}
+				}
+			}
+			else if (event.type == SDL_MOUSEBUTTONDOWN)
+			{
+				if (event.button.button == SDL_BUTTON_LEFT)
+				{
+					mouse.leftButtonPressed = true;
+					mouse.buttonWaiting = true;
+					mouse.repeatCounter = 0;
+				}
+
+				// abort (right mouse button)
+				if (event.button.button == SDL_BUTTON_RIGHT)
+				{
+					returnValue = d.abortReturnValue;
+
+					loopRunning = false;
+					break;
+				}
+
+				// test buttons
+				if (event.button.button == SDL_BUTTON_LEFT)
+				{
+					for (int32_t i = 0; i < d.numButtons; i++)
+					{
+						button_t *b = &d.buttons[i];
+
+						const int32_t x2 = (b->clickableWidth > 0) ? (b->x1 + b->clickableWidth) : b->x2;
+						if (mouse.x >= b->x1 && mouse.x <= x2 && mouse.y >= b->y1 && mouse.y <= b->y2)
+						{
+							if (b->callback != NULL)
+							{
+								b->callback();
+								if (b->repeat)
+								{
+									buttonToRepeat = i;
+								}
+							}
+							else
+							{
+								returnValue = b->returnValue;
+
+								loopRunning = false;
+								break;
+							}
+						}
+					}
+				}
+			}
+			else if (event.type == SDL_MOUSEBUTTONUP)
+			{
+				mouse.buttonWaitCounter = 0;
+				mouse.buttonWaiting = false;
+				buttonToRepeat = -1;
+
+				if (event.button.button == SDL_BUTTON_LEFT)
+					mouse.leftButtonPressed = false;
+			}
+		}
+
+		if (!mouse.buttonWaiting && buttonToRepeat > -1)
+		{
+			button_t *b = &d.buttons[buttonToRepeat];
+
+			if (++mouse.repeatCounter >= 3)
+			{
+				const int32_t x2 = (b->clickableWidth > 0) ? (b->x1 + b->clickableWidth) : b->x2;
+				if (mouse.x >= b->x1 && mouse.x <= x2 && mouse.y >= b->y1 && mouse.y <= b->y2)
+				{
+					if (b->callback != NULL)
+						b->callback();
+				}
+
+				mouse.repeatCounter = 0;
+			}
+		}
+
+		updateMouseCounters();
+		renderFrame2();
+		flipFrame();
+	}
+
+	mouse.leftButtonPressed = false;
+	mouse.buttonWaiting = false;
+	mouse.buttonWaitCounter = 0;
+	mouse.repeatCounter = 0;
+
+	removeAskBox();
+	pointerSetPreviousMode();
+	setPrevStatusMessage();
+
+	SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
+	return returnValue;
+}
--- /dev/null
+++ b/src/pt2_askbox.h
@@ -1,0 +1,31 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+enum
+{
+	// dialog types
+	ASKBOX_YES_NO = 0,
+	ASKBOX_CLEAR = 1,
+	ASKBOX_PAT2SMP = 2,
+	ASKBOX_DOWNSAMPLE = 3,
+	ASKBOX_MOD2WAV = 4,
+	ASKBOX_NUM,
+
+	// buttons
+
+	ASKBOX_YES = 1,
+	ASKBOX_NO = 0,
+
+	ASKBOX_CLEAR_SONG = 0,
+	ASKBOX_CLEAR_SAMPLES = 1,
+	ASKBOX_CLEAR_ALL = 2,
+	ASKBOX_CLEAR_CANCEL = 3
+};
+
+void breakAskBoxLoop(uint32_t _returnValue);
+void handleThreadedAskBox(void);
+uint32_t askBoxThreadSafe(uint32_t dialogType, const char *statusText);
+uint32_t askBox(uint32_t dialogType, const char *statusText);
+void removeAskBox(void);
--- a/src/pt2_audio.c
+++ b/src/pt2_audio.c
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdbool.h>
+#include <math.h>
 #include <SDL2/SDL.h>
 #ifdef _WIN32
 #include <io.h>
@@ -17,110 +18,35 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <limits.h>
-#include "pt2_math.h"
 #include "pt2_audio.h"
-#include "pt2_header.h"
 #include "pt2_helpers.h"
-#include "pt2_blep.h"
 #include "pt2_config.h"
-#include "pt2_tables.h"
 #include "pt2_textout.h"
-#include "pt2_visuals.h"
 #include "pt2_scopes.h"
-#include "pt2_mod2wav.h"
-#include "pt2_pat2smp.h"
 #include "pt2_sync.h"
-#include "pt2_structs.h"
-#include "pt2_rcfilter.h"
-#include "pt2_ledfilter.h"
 #include "pt2_downsample2x.h"
-#include "pt2_hpc.h"
+#include "pt2_replayer.h"
+#include "pt2_paula.h"
+#include "pt2_amigafilters.h"
 
-#define STEREO_NORM_FACTOR 0.5 /* cumulative mid/side normalization factor (1/sqrt(2))*(1/sqrt(2)) */
+// cumulative mid/side normalization factor (1/sqrt(2))*(1/sqrt(2))
+#define STEREO_NORM_FACTOR 0.5
 
 #define INITIAL_DITHER_SEED 0x12345000
 
-static volatile bool ledFilterEnabled;
-static volatile uint8_t filterModel;
-static bool amigaPanFlag, useA1200LowPassFilter;
+static uint8_t panningMode;
 static int32_t randSeed = INITIAL_DITHER_SEED, stereoSeparation = 100;
 static uint32_t audLatencyPerfValInt, audLatencyPerfValFrac;
 static uint64_t tickTime64, tickTime64Frac;
-static double *dMixBufferL, *dMixBufferR, *dMixBufferLUnaligned, *dMixBufferRUnaligned;
+static double *dMixBufferL, *dMixBufferR;
 static double dPrngStateL, dPrngStateR, dSideFactor;
-static blep_t blep[AMIGA_VOICES];
-static rcFilter_t filterLoA500, filterHiA500, filterLoA1200, filterHiA1200;
-static ledFilter_t filterLED;
 static SDL_AudioDeviceID dev;
 
-static void processFiltersA1200_NoLED(int32_t numSamples);
-static void processFiltersA1200_LED(int32_t numSamples);
-static void processFiltersA500_NoLED(int32_t numSamples);
-static void processFiltersA500_LED(int32_t numSamples);
-static void (*processFiltersFunc)(int32_t);
-
 // for audio/video syncing
 static uint32_t tickTimeLen, tickTimeLenFrac;
 
-// globalized
-audio_t audio;
-paulaVoice_t paula[AMIGA_VOICES];
+audio_t audio; // globalized
 
-bool intMusic(void); // defined in pt2_replayer.c
-
-static void updateFilterFunc(void)
-{
-	if (filterModel == FILTERMODEL_A500)
-	{
-		if (ledFilterEnabled)
-			processFiltersFunc = processFiltersA500_LED;
-		else
-			processFiltersFunc = processFiltersA500_NoLED;
-	}
-	else // A1200
-	{
-		if (ledFilterEnabled)
-			processFiltersFunc = processFiltersA1200_LED;
-		else
-			processFiltersFunc = processFiltersA1200_NoLED;
-	}
-}
-
-void setLEDFilter(bool state, bool doLockAudio)
-{
-	if (ledFilterEnabled == state)
-		return; // same state as before!
-
-	const bool audioWasntLocked = !audio.locked;
-	if (doLockAudio && audioWasntLocked)
-		lockAudio();
-
-	clearLEDFilterState(&filterLED);
-
-	editor.useLEDFilter = state;
-	ledFilterEnabled = editor.useLEDFilter;
-	updateFilterFunc();
-
-	if (doLockAudio && audioWasntLocked)
-		unlockAudio();
-}
-
-void toggleLEDFilter(void)
-{
-	const bool audioWasntLocked = !audio.locked;
-	if (audioWasntLocked)
-		lockAudio();
-
-	clearLEDFilterState(&filterLED);
-
-	editor.useLEDFilter ^= 1;
-	ledFilterEnabled = editor.useLEDFilter;
-	updateFilterFunc();
-
-	if (audioWasntLocked)
-		unlockAudio();
-}
-
 static void calcAudioLatencyVars(int32_t audioBufferSize, int32_t audioFreq)
 {
 	double dInt, dFrac;
@@ -167,356 +93,6 @@
 	audio.locked = false;
 }
 
-void mixerUpdateLoops(void) // updates Paula loop (+ scopes)
-{
-	const bool audioWasntLocked = !audio.locked;
-	if (audioWasntLocked)
-		lockAudio();
-
-	for (int32_t i = 0; i < AMIGA_VOICES; i++)
-	{
-		const moduleChannel_t *ch = &song->channels[i];
-		if (ch->n_samplenum == editor.currSample)
-		{
-			const moduleSample_t *s = &song->samples[editor.currSample];
-
-			paulaSetData(i, ch->n_start + s->loopStart);
-			paulaSetLength(i, (uint16_t)(s->loopLength >> 1));
-		}
-	}
-
-	if (audioWasntLocked)
-		unlockAudio();
-}
-
-void mixerKillVoice(int32_t ch)
-{
-	const bool audioWasntLocked = !audio.locked;
-	if (audioWasntLocked)
-		lockAudio();
-
-	memset(&paula[ch], 0, sizeof (paulaVoice_t));
-	memset(&blep[ch], 0, sizeof (blep_t));
-
-	stopScope(ch); // it should be safe to clear the scope now
-	memset(&scope[ch], 0, sizeof (scope_t));
-
-	if (audioWasntLocked)
-		unlockAudio();
-}
-
-void turnOffVoices(void)
-{
-	const bool audioWasntLocked = !audio.locked;
-	if (audioWasntLocked)
-		lockAudio();
-
-	for (int32_t i = 0; i < AMIGA_VOICES; i++)
-		mixerKillVoice(i);
-
-	clearRCFilterState(&filterLoA500);
-	clearRCFilterState(&filterLoA1200);
-	clearRCFilterState(&filterHiA500);
-	clearRCFilterState(&filterHiA1200);
-	clearLEDFilterState(&filterLED);
-
-	resetAudioDithering();
-
-	editor.tuningFlag = false;
-
-	if (audioWasntLocked)
-		unlockAudio();
-}
-
-void resetCachedMixerPeriod(void)
-{
-	paulaVoice_t *v = paula;
-	for (int32_t i = 0; i < AMIGA_VOICES; i++, v++)
-	{
-		v->oldPeriod = -1;
-		v->dOldVoiceDelta = 0.0;
-		v->dOldVoiceDeltaMul = 1.0;
-	}
-}
-
-// the following routines are only called from the mixer thread.
-
-void paulaSetPeriod(int32_t ch, uint16_t period)
-{
-	double dPeriodToDeltaDiv;
-	paulaVoice_t *v = &paula[ch];
-
-	int32_t realPeriod = period;
-	if (realPeriod == 0)
-		realPeriod = 1+65535; // confirmed behavior on real Amiga
-	else if (realPeriod < 113)
-		realPeriod = 113; // close to what happens on real Amiga (and needed for BLEP synthesis)
-
-	if (editor.songPlaying)
-	{
-		v->syncPeriod = realPeriod;
-		v->syncFlags |= SET_SCOPE_PERIOD;
-	}
-	else
-	{
-		scopeSetPeriod(ch, realPeriod);
-	}
-
-	// if the new period was the same as the previous period, use cached delta
-	if (realPeriod != v->oldPeriod)
-	{
-		v->oldPeriod = realPeriod;
-
-		// this period is not cached, calculate mixer deltas
-
-		// during PAT2SMP, use different audio output rates
-		if (editor.isSMPRendering)
-			dPeriodToDeltaDiv = editor.pat2SmpHQ ? (PAULA_PAL_CLK / PAT2SMP_HI_FREQ) : (PAULA_PAL_CLK / PAT2SMP_LO_FREQ);
-		else
-			dPeriodToDeltaDiv = audio.dPeriodToDeltaDiv;
-
-		v->dOldVoiceDelta = dPeriodToDeltaDiv / realPeriod;
-
-		if (audio.oversamplingFlag || editor.isSMPRendering)
-			v->dOldVoiceDelta *= 0.5; // /2 since we do 2x oversampling
-
-		// for BLEP synthesis (prevents division in inner mix loop)
-		v->dOldVoiceDeltaMul = 1.0 / v->dOldVoiceDelta;
-	}
-
-	// to be read on next sampling step (or on DMA restart)
-	v->AUD_PER_delta = v->dOldVoiceDelta;
-	v->AUD_PER_deltamul = v->dOldVoiceDeltaMul;
-
-	// set BLEP stuff
-	if (v->dLastDelta    == 0.0) v->dLastDelta    = v->AUD_PER_delta;
-	if (v->dLastDeltaMul == 0.0) v->dLastDeltaMul = v->AUD_PER_deltamul;
-}
-
-void paulaSetVolume(int32_t ch, uint16_t vol)
-{
-	paulaVoice_t *v = &paula[ch];
-
-	int32_t realVol = vol;
-
-	// this is what WinUAE does
-	realVol &= 127;
-	if (realVol > 64)
-		realVol = 64;
-	// ------------------------
-
-	// multiplying by this also scales the sample from -128..127 -> -1.0 .. ~0.99
-	v->AUD_VOL = realVol * (1.0 / (128.0 * 64.0));
-
-	if (editor.songPlaying)
-	{
-		v->syncVolume = (uint8_t)realVol;
-		v->syncFlags |= SET_SCOPE_VOLUME;
-	}
-	else
-	{
-		scope[ch].volume = (uint8_t)realVol;
-	}
-}
-
-void paulaSetLength(int32_t ch, uint16_t len)
-{
-	paulaVoice_t *v = &paula[ch];
-
-	v->AUD_LEN = len;
-
-	if (editor.songPlaying)
-		v->syncFlags |= SET_SCOPE_LENGTH;
-	else
-		scope[ch].newLength = len*2;
-}
-
-void paulaSetData(int32_t ch, const int8_t *src)
-{
-	paulaVoice_t *v = &paula[ch];
-
-	if (src == NULL)
-		src = &song->sampleData[config.reservedSampleOffset]; // 128K reserved sample
-
-	v->AUD_LC = src;
-
-	if (editor.songPlaying)
-		v->syncFlags |= SET_SCOPE_DATA;
-	else
-		scope[ch].newData = src;
-}
-
-void paulaStopDMA(int32_t ch)
-{
-	paulaVoice_t *v = &paula[ch];
-
-	v->DMA_active = false;
-
-	if (editor.songPlaying)
-		v->syncFlags |= STOP_SCOPE;
-	else
-		scope[ch].active = false;
-}
-
-void paulaStartDMA(int32_t ch)
-{
-	paulaVoice_t *v = &paula[ch];
-
-	if (v->AUD_LC == NULL)
-		v->AUD_LC = &song->sampleData[config.reservedSampleOffset]; // 128K reserved sample
-
-	/* This is not really accurate to what happens on Paula
-	** during DMA start, but it's good enough.
-	*/
-
-	v->dDelta = v->AUD_PER_delta;
-	v->location = v->AUD_LC;
-	v->lengthCounter = v->AUD_LEN;
-
-	// pre-fill AUDxDAT buffer
-	v->AUD_DAT[0] = *v->location++;
-	v->AUD_DAT[1] = *v->location++;
-	v->sampleCounter = 2;
-
-	// set current sample point
-	v->dSample = v->AUD_DAT[0] * v->AUD_VOL;
-
-	// progress AUD_DAT buffer
-	v->AUD_DAT[0] = v->AUD_DAT[1];
-	v->sampleCounter--;
-
-	// set BLEP stuff
-	v->dDeltaMul = v->AUD_PER_deltamul;
-	v->dLastPhase = 0.0;
-	v->dLastDelta = v->dDelta;
-	v->dLastDeltaMul = v->dDeltaMul;
-	v->dBlepOffset = 0.0;
-
-	v->dPhase = 0.0;
-	v->DMA_active = true;
-
-	if (editor.songPlaying)
-	{
-		v->syncTriggerData = v->AUD_LC;
-		v->syncTriggerLength = v->AUD_LEN * 2;
-		v->syncFlags |= TRIGGER_SCOPE;
-	}
-	else
-	{
-		scope_t *s = &scope[ch];
-		s->newData = v->AUD_LC;
-		s->newLength = v->AUD_LEN * 2;
-		scopeTrigger(ch);
-	}
-}
-
-void toggleFilterModel(void)
-{
-	const bool audioWasntLocked = !audio.locked;
-	if (audioWasntLocked)
-		lockAudio();
-
-	clearRCFilterState(&filterLoA500);
-	clearRCFilterState(&filterLoA1200);
-	clearRCFilterState(&filterHiA500);
-	clearRCFilterState(&filterHiA1200);
-	clearLEDFilterState(&filterLED);
-
-	filterModel ^= 1;
-	updateFilterFunc();
-
-	if (filterModel == FILTERMODEL_A500)
-		displayMsg("AUDIO: AMIGA 500");
-	else
-		displayMsg("AUDIO: AMIGA 1200");
-
-	if (audioWasntLocked)
-		unlockAudio();
-}
-
-void mixChannels(int32_t numSamples)
-{
-	double *dMixBufSelect[AMIGA_VOICES] = { dMixBufferL, dMixBufferR, dMixBufferR, dMixBufferL };
-
-	memset(dMixBufferL, 0, numSamples * sizeof (double));
-	memset(dMixBufferR, 0, numSamples * sizeof (double));
-
-	paulaVoice_t *v = paula;
-	blep_t *bSmp = blep;
-
-	for (int32_t i = 0; i < AMIGA_VOICES; i++, v++, bSmp++)
-	{
-		/* We only need to test for a NULL-pointer once.
-		** When pointers are messed with in the tracker, the mixer
-		** is temporarily forced offline, and its voice pointers are
-		** cleared to prevent expired pointer addresses.
-		*/
-		if (!v->DMA_active || v->location == NULL || v->AUD_LC == NULL)
-			continue;
-
-		double *dMixBuf = dMixBufSelect[i]; // what output channel to mix into (L, R, R, L)
-		for (int32_t j = 0; j < numSamples; j++)
-		{
-			double dSmp = v->dSample;
-			if (dSmp != bSmp->dLastValue)
-			{
-				if (v->dLastDelta > v->dLastPhase)
-					blepAdd(bSmp, v->dBlepOffset, bSmp->dLastValue - dSmp);
-
-				bSmp->dLastValue = dSmp;
-			}
-
-			if (bSmp->samplesLeft > 0)
-				dSmp = blepRun(bSmp, dSmp);
-
-			dMixBuf[j] += dSmp;
-
-			v->dPhase += v->dDelta;
-			if (v->dPhase >= 1.0) // deltas can't be >= 1.0, so this is safe
-			{
-				v->dPhase -= 1.0;
-
-				// set BLEP stuff
-				v->dLastPhase = v->dPhase;
-				v->dLastDelta = v->dDelta;
-				v->dLastDeltaMul = v->dDeltaMul;
-				v->dBlepOffset = v->dLastPhase * v->dLastDeltaMul;
-
-				// Paula only updates period (delta) during period refetching (this stage)
-				v->dDelta = v->AUD_PER_delta;
-				v->dDeltaMul = v->AUD_PER_deltamul;
-
-				if (v->sampleCounter == 0)
-				{
-					// it's time to read new samples from DMA
-
-					if (--v->lengthCounter == 0)
-					{
-						v->lengthCounter = v->AUD_LEN;
-						v->location = v->AUD_LC;
-					}
-
-					// fill DMA data buffer
-					v->AUD_DAT[0] = *v->location++;
-					v->AUD_DAT[1] = *v->location++;
-					v->sampleCounter = 2;
-				}
-
-				/* Pre-compute current sample point.
-				** Output volume is only read from AUDxVOL at this stage,
-				** and we don't emulate volume PWM anyway, so we can
-				** pre-multiply by volume here.
-				*/
-				v->dSample = v->AUD_DAT[0] * v->AUD_VOL; // -128..127 * 0.0 .. 1.0
-
-				// progress AUD_DAT buffer
-				v->AUD_DAT[0] = v->AUD_DAT[1];
-				v->sampleCounter--;
-			}
-		}
-	}
-}
-
 void resetAudioDithering(void)
 {
 	randSeed = INITIAL_DITHER_SEED;
@@ -532,133 +108,6 @@
 	return randSeed;
 }
 
-static void processFiltersA1200_NoLED(int32_t numSamples)
-{
-	if (useA1200LowPassFilter)
-	{
-		for (int32_t i = 0; i < numSamples; i++)
-		{
-			double dOut[2];
-
-			dOut[0] = dMixBufferL[i];
-			dOut[1] = dMixBufferR[i];
-
-			// low-pass filter
-			RCLowPassFilterStereo(&filterLoA1200, dOut, dOut);
-
-			// high-pass RC filter
-			RCHighPassFilterStereo(&filterHiA1200, dOut, dOut);
-
-			dMixBufferL[i] = dOut[0];
-			dMixBufferR[i] = dOut[1];
-		}
-	}
-	else
-	{
-		for (int32_t i = 0; i < numSamples; i++)
-		{
-			double dOut[2];
-
-			dOut[0] = dMixBufferL[i];
-			dOut[1] = dMixBufferR[i];
-
-			// high-pass RC filter
-			RCHighPassFilterStereo(&filterHiA1200, dOut, dOut);
-
-			dMixBufferL[i] = dOut[0];
-			dMixBufferR[i] = dOut[1];
-		}
-	}
-}
-
-static void processFiltersA1200_LED(int32_t numSamples)
-{
-	if (useA1200LowPassFilter)
-	{
-		for (int32_t i = 0; i < numSamples; i++)
-		{
-			double dOut[2];
-
-			dOut[0] = dMixBufferL[i];
-			dOut[1] = dMixBufferR[i];
-
-			// low-pass filter
-			RCLowPassFilterStereo(&filterLoA1200, dOut, dOut);
-
-			// "LED" Sallen-Key filter
-			LEDFilter(&filterLED, dOut, dOut);
-
-			// high-pass RC filter
-			RCHighPassFilterStereo(&filterHiA1200, dOut, dOut);
-
-			dMixBufferL[i] = dOut[0];
-			dMixBufferR[i] = dOut[1];
-		}
-	}
-	else
-	{
-		for (int32_t i = 0; i < numSamples; i++)
-		{
-			double dOut[2];
-
-			dOut[0] = dMixBufferL[i];
-			dOut[1] = dMixBufferR[i];
-
-			// "LED" Sallen-Key filter
-			LEDFilter(&filterLED, dOut, dOut);
-
-			// high-pass RC filter
-			RCHighPassFilterStereo(&filterHiA1200, dOut, dOut);
-
-			dMixBufferL[i] = dOut[0];
-			dMixBufferR[i] = dOut[1];
-		}
-	}
-}
-
-static void processFiltersA500_NoLED(int32_t numSamples)
-{
-	for (int32_t i = 0; i < numSamples; i++)
-	{
-		double dOut[2];
-
-		dOut[0] = dMixBufferL[i];
-		dOut[1] = dMixBufferR[i];
-
-		// low-pass RC filter
-		RCLowPassFilterStereo(&filterLoA500, dOut, dOut);
-
-		// high-pass RC filter
-		RCHighPassFilterStereo(&filterHiA500, dOut, dOut);
-
-		dMixBufferL[i] = dOut[0];
-		dMixBufferR[i] = dOut[1];
-	}
-}
-
-static void processFiltersA500_LED(int32_t numSamples)
-{
-	for (int32_t i = 0; i < numSamples; i++)
-	{
-		double dOut[2];
-
-		dOut[0] = dMixBufferL[i];
-		dOut[1] = dMixBufferR[i];
-
-		// low-pass RC filter
-		RCLowPassFilterStereo(&filterLoA500, dOut, dOut);
-
-		// "LED" Sallen-Key filter
-		LEDFilter(&filterLED, dOut, dOut);
-
-		// high-pass RC filter
-		RCHighPassFilterStereo(&filterHiA500, dOut, dOut);
-
-		dMixBufferL[i] = dOut[0];
-		dMixBufferR[i] = dOut[1];
-	}
-}
-
 #define NORM_FACTOR 2.0 /* nominally correct, but can clip from high-pass filter overshoot */
 
 static inline void processMixedSamplesAmigaPanning(int32_t i, int16_t *out)
@@ -670,8 +119,8 @@
 	double dR = dMixBufferR[i];
 
 	// normalize w/ phase-inversion (A500/A1200 has a phase-inverted audio signal)
-	dL *= NORM_FACTOR * (-INT16_MAX / (double)AMIGA_VOICES);
-	dR *= NORM_FACTOR * (-INT16_MAX / (double)AMIGA_VOICES);
+	dL *= NORM_FACTOR * (-INT16_MAX / (double)PAULA_VOICES);
+	dR *= NORM_FACTOR * (-INT16_MAX / (double)PAULA_VOICES);
 
 	// left channel - 1-bit triangular dithering (high-pass filtered)
 	dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
@@ -707,8 +156,8 @@
 	dR = dMid - dSide;
 
 	// normalize w/ phase-inversion (A500/A1200 has a phase-inverted audio signal)
-	dL *= NORM_FACTOR * (-INT16_MAX / (double)AMIGA_VOICES);
-	dR *= NORM_FACTOR * (-INT16_MAX / (double)AMIGA_VOICES);
+	dL *= NORM_FACTOR * (-INT16_MAX / (double)PAULA_VOICES);
+	dR *= NORM_FACTOR * (-INT16_MAX / (double)PAULA_VOICES);
 
 	// left channel - 1-bit triangular dithering (high-pass filtered)
 	dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
@@ -739,8 +188,8 @@
 	dR = decimate2x_R(dMixBufferR[offset1], dMixBufferR[offset2]);
 
 	// normalize w/ phase-inversion (A500/A1200 has a phase-inverted audio signal)
-	dL *= NORM_FACTOR * (-INT16_MAX / (double)AMIGA_VOICES);
-	dR *= NORM_FACTOR * (-INT16_MAX / (double)AMIGA_VOICES);
+	dL *= NORM_FACTOR * (-INT16_MAX / (double)PAULA_VOICES);
+	dR *= NORM_FACTOR * (-INT16_MAX / (double)PAULA_VOICES);
 
 	// left channel - 1-bit triangular dithering (high-pass filtered)
 	dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
@@ -779,8 +228,8 @@
 	dR = dMid - dSide;
 
 	// normalize w/ phase-inversion (A500/A1200 has a phase-inverted audio signal)
-	dL *= NORM_FACTOR * (-INT16_MAX / (double)AMIGA_VOICES);
-	dR *= NORM_FACTOR * (-INT16_MAX / (double)AMIGA_VOICES);
+	dL *= NORM_FACTOR * (-INT16_MAX / (double)PAULA_VOICES);
+	dR *= NORM_FACTOR * (-INT16_MAX / (double)PAULA_VOICES);
 
 	// left channel - 1-bit triangular dithering (high-pass filtered)
 	dPrng = random32() * (0.5 / INT32_MAX); // -0.5..0.5
@@ -801,94 +250,60 @@
 
 void outputAudio(int16_t *target, int32_t numSamples)
 {
-	if (editor.isSMPRendering)
+	if (audio.oversamplingFlag) // 2x oversampling
 	{
-		// render to sample (PAT2SMP)
+		// mix and filter channels (at 2x rate)
+		paulaGenerateSamples(dMixBufferL, dMixBufferR, numSamples*2);
+		processAmigaFilters(dMixBufferL, dMixBufferR, numSamples*2);
 
-		int32_t samplesTodo = numSamples;
-		if (editor.pat2SmpPos+samplesTodo > config.maxSampleLength)
-			samplesTodo = config.maxSampleLength-editor.pat2SmpPos;
-
-		// mix channels (with 2x oversampling, PAT2SMP needs it)
-		mixChannels(samplesTodo*2);
-
-		double *dOutStream = &editor.dPat2SmpBuf[editor.pat2SmpPos];
-		for (int32_t i = 0; i < samplesTodo; i++)
+		// downsample, normalize and dither
+		int16_t out[2];
+		int16_t *outStream = target;
+		if (stereoSeparation == 100)
 		{
-			// 2x downsampling (decimation)
-			double dL, dR;
-			const uint32_t offset1 = (i << 1) + 0;
-			const uint32_t offset2 = (i << 1) + 1;
-			dL = decimate2x_L(dMixBufferL[offset1], dMixBufferL[offset2]);
-			dR = decimate2x_R(dMixBufferR[offset1], dMixBufferR[offset2]);
-
-			dOutStream[i] = (dL + dR) * 0.5; // normalized to -128..127 later
+			for (int32_t i = 0; i < numSamples; i++)
+			{
+				processMixedSamplesAmigaPanning_2x(i, out);
+				*outStream++ = out[0];
+				*outStream++ = out[1];
+			}
 		}
-
-		editor.pat2SmpPos += samplesTodo;
-		if (editor.pat2SmpPos >= config.maxSampleLength)
+		else
 		{
-			editor.smpRenderingDone = true;
-			updateWindowTitle(MOD_IS_MODIFIED);
+			for (int32_t i = 0; i < numSamples; i++)
+			{
+				processMixedSamples_2x(i, out);
+				*outStream++ = out[0];
+				*outStream++ = out[1];
+			}
 		}
 	}
 	else
 	{
-		if (audio.oversamplingFlag) // 2x oversampling
-		{
-			// mix and filter channels (at 2x rate)
-			mixChannels(numSamples*2);
-			processFiltersFunc(numSamples*2);
+		// mix and filter channels
+		paulaGenerateSamples(dMixBufferL, dMixBufferR, numSamples);
+		processAmigaFilters(dMixBufferL, dMixBufferR, numSamples);
 
-			// downsample, normalize and dither
-			int16_t out[2];
-			int16_t *outStream = target;
-			if (stereoSeparation == 100)
+		// normalize and dither
+		int16_t out[2];
+		int16_t *outStream = target;
+		if (stereoSeparation == 100)
+		{
+			for (int32_t i = 0; i < numSamples; i++)
 			{
-				for (int32_t i = 0; i < numSamples; i++)
-				{
-					processMixedSamplesAmigaPanning_2x(i, out);
-					*outStream++ = out[0];
-					*outStream++ = out[1];
-				}
+				processMixedSamplesAmigaPanning(i, out);
+				*outStream++ = out[0];
+				*outStream++ = out[1];
 			}
-			else
-			{
-				for (int32_t i = 0; i < numSamples; i++)
-				{
-					processMixedSamples_2x(i, out);
-					*outStream++ = out[0];
-					*outStream++ = out[1];
-				}
-			}
 		}
 		else
 		{
-			// mix and filter channels
-			mixChannels(numSamples);
-			processFiltersFunc(numSamples);
-
-			// normalize and dither
-			int16_t out[2];
-			int16_t *outStream = target;
-			if (stereoSeparation == 100)
+			for (int32_t i = 0; i < numSamples; i++)
 			{
-				for (int32_t i = 0; i < numSamples; i++)
-				{
-					processMixedSamplesAmigaPanning(i, out);
-					*outStream++ = out[0];
-					*outStream++ = out[1];
-				}
+				processMixedSamples(i, out);
+				*outStream++ = out[0];
+				*outStream++ = out[1];
 			}
-			else
-			{
-				for (int32_t i = 0; i < numSamples; i++)
-				{
-					processMixedSamples(i, out);
-					*outStream++ = out[0];
-					*outStream++ = out[1];
-				}
-			}
 		}
 	}
 }
@@ -905,24 +320,24 @@
 		tickTime64Frac = audLatencyPerfValFrac;
 	}
 
-	moduleChannel_t *c = song->channels;
+	moduleChannel_t *ch = song->channels;
 	paulaVoice_t *v = paula;
-	syncedChannel_t *s = chSyncData.channels;
+	syncedChannel_t *sc = chSyncData.channels;
 
-	for (int32_t i = 0; i < AMIGA_VOICES; i++, c++, s++, v++)
+	for (int32_t i = 0; i < PAULA_VOICES; i++, ch++, sc++, v++)
 	{
-		s->flags = v->syncFlags | c->syncFlags;
-		c->syncFlags = v->syncFlags = 0; // clear sync flags
+		sc->flags = v->syncFlags | ch->syncFlags;
+		ch->syncFlags = v->syncFlags = 0; // clear sync flags
 
-		s->volume = v->syncVolume;
-		s->period = v->syncPeriod;
-		s->triggerData = v->syncTriggerData;
-		s->triggerLength = v->syncTriggerLength;
-		s->newData = v->AUD_LC;
-		s->newLength = v->AUD_LEN * 2;
-		s->vuVolume = c->syncVuVolume;
-		s->analyzerVolume = c->syncAnalyzerVolume;
-		s->analyzerPeriod = c->syncAnalyzerPeriod;
+		sc->volume = v->syncVolume;
+		sc->period = v->syncPeriod;
+		sc->triggerData = v->syncTriggerData;
+		sc->triggerLength = v->syncTriggerLength;
+		sc->newData = v->AUD_LC;
+		sc->newLength = v->AUD_LEN * 2;
+		sc->vuVolume = ch->syncVuVolume;
+		sc->analyzerVolume = ch->syncAnalyzerVolume;
+		sc->analyzerPeriod = ch->syncAnalyzerPeriod;
 	}
 
 	chSyncData.timestamp = tickTime64;
@@ -930,9 +345,9 @@
 
 	tickTime64 += tickTimeLen;
 	tickTime64Frac += tickTimeLenFrac;
-	if (tickTime64Frac > 0xFFFFFFFF)
+	if (tickTime64Frac > UINT32_MAX)
 	{
-		tickTime64Frac &= 0xFFFFFFFF;
+		tickTime64Frac &= UINT32_MAX;
 		tickTime64++;
 	}
 }
@@ -939,7 +354,7 @@
 
 static void SDLCALL audioCallback(void *userdata, Uint8 *stream, int len)
 {
-	if (audio.forceSoundCardSilence) // during MOD2WAV
+	if (editor.mod2WavOngoing || editor.pat2SmpOngoing) // send silence to sound output device
 	{
 		memset(stream, 0, len);
 		return;
@@ -947,7 +362,7 @@
 
 	int16_t *streamOut = (int16_t *)stream;
 
-	int32_t samplesLeft = len >> 2;
+	uint32_t samplesLeft = (uint32_t)len >> 2;
 	while (samplesLeft > 0)
 	{
 		if (audio.tickSampleCounter64 <= 0)
@@ -963,124 +378,24 @@
 			audio.tickSampleCounter64 += audio.samplesPerTick64;
 		}
 
-		const int32_t remainingTick = (audio.tickSampleCounter64 + UINT32_MAX) >> 32; // ceil rounding (upwards)
+		const uint32_t remainingTickSamples = ((uint64_t)audio.tickSampleCounter64 + UINT32_MAX) >> 32; // ceil rounding (upwards)
 
-		int32_t samplesToMix = samplesLeft;
-		if (samplesToMix > remainingTick)
-			samplesToMix = remainingTick;
+		uint32_t samplesTodo = samplesLeft;
+		if (samplesTodo > remainingTickSamples)
+			samplesTodo = remainingTickSamples;
 
-		outputAudio(streamOut, samplesToMix);
-		streamOut += samplesToMix<<1;
+		outputAudio(streamOut, samplesTodo);
+		streamOut += samplesTodo << 1;
 
-		samplesLeft -= samplesToMix;
-		audio.tickSampleCounter64 -= (int64_t)samplesToMix << 32;
+		samplesLeft -= samplesTodo;
+		audio.tickSampleCounter64 -= (int64_t)samplesTodo << 32;
 	}
 
 	(void)userdata;
 }
 
-static void calculateFilterCoeffs(void)
+void audioSetStereoSeparation(uint8_t percentage) // 0..100 (percentage)
 {
-	/* Amiga 500/1200 filter emulation
-	**
-	** aciddose:
-	** First comes a static low-pass 6dB formed by the supply current
-	** from the Paula's mixture of channels A+B / C+D into the opamp with
-	** 0.1uF capacitor and 360 ohm resistor feedback in inverting mode biased by
-	** dac vRef (used to center the output).
-	**
-	** R = 360 ohm
-	** C = 0.1uF
-	** Low Hz = 4420.97~ = 1 / (2pi * 360 * 0.0000001)
-	**
-	** Under spice simulation the circuit yields -3dB = 4400Hz.
-	** In the Amiga 1200, the low-pass cutoff is ~34kHz, so the
-	** static low-pass filter is disabled in the mixer in A1200 mode.
-	**
-	** Next comes a bog-standard Sallen-Key filter ("LED") with:
-	** R1 = 10K ohm
-	** R2 = 10K ohm
-	** C1 = 6800pF
-	** C2 = 3900pF
-	** Q ~= 1/sqrt(2)
-	**
-	** This filter is optionally bypassed by an MPF-102 JFET chip when
-	** the LED filter is turned off.
-	**
-	** Under spice simulation the circuit yields -3dB = 2800Hz.
-	** 90 degrees phase = 3000Hz (so, should oscillate at 3kHz!)
-	**
-	** The buffered output of the Sallen-Key passes into an RC high-pass with:
-	** R = 1.39K ohm (1K ohm + 390 ohm)
-	** C = 22uF (also C = 330nF, for improved high-frequency)
-	**
-	** High Hz = 5.2~ = 1 / (2pi * 1390 * 0.000022)
-	** Under spice simulation the circuit yields -3dB = 5.2Hz.
-	**
-	** 8bitbubsy:
-	** Keep in mind that many of the Amiga schematics that are floating around on
-	** the internet have wrong RC values! They were most likely very early schematics
-	** that didn't change before production (or changes that never reached production).
-	** This has been confirmed by measuring the components on several Amiga motherboards.
-	**
-	** Correct values for A500, >rev3 (?) (A500_R6.pdf):
-	** - 1-pole RC 6dB/oct low-pass: R=360 ohm, C=0.1uF
-	** - Sallen-key low-pass ("LED"): R1/R2=10k ohm, C1=6800pF, C2=3900pF
-	** - 1-pole RC 6dB/oct high-pass: R=1390 ohm (1000+390), C=22.33uF (22+0.33)
-	**
-	** Correct values for A1200, all revs (A1200_R2.pdf):
-	** - 1-pole RC 6dB/oct low-pass: R=680 ohm, C=6800pF
-	** - Sallen-key low-pass ("LED"): R1/R2=10k ohm, C1=6800pF, C2=3900pF (same as A500)
-	** - 1-pole RC 6dB/oct high-pass: R=1390 ohm (1000+390), C=22uF
-	*/
-	double dAudioFreq = audio.outputRate;
-	double R, C, R1, R2, C1, C2, cutoff, qfactor;
-
-	if (audio.oversamplingFlag)
-		dAudioFreq *= 2.0; // 2x oversampling
-
-	// A500 1-pole (6db/oct) static RC low-pass filter:
-	R = 360.0; // R321 (360 ohm)
-	C = 1e-7;  // C321 (0.1uF)
-	cutoff = 1.0 / (PT2_TWO_PI * R * C); // ~4420.971Hz
-	calcRCFilterCoeffs(dAudioFreq, cutoff, &filterLoA500);
-
-	// (optional) A1200 1-pole (6db/oct) static RC low-pass filter:
-	R = 680.0;  // R321 (680 ohm)
-	C = 6.8e-9; // C321 (6800pF)
-	cutoff = 1.0 / (PT2_TWO_PI * R * C); // ~34419.322Hz
-
-	useA1200LowPassFilter = false;
-	if (dAudioFreq/2.0 > cutoff)
-	{
-		calcRCFilterCoeffs(dAudioFreq, cutoff, &filterLoA1200);
-		useA1200LowPassFilter = true;
-	}
-
-	// Sallen-Key low-pass filter ("LED" filter, same values on A500/A1200):
-	R1 = 10000.0; // R322 (10K ohm)
-	R2 = 10000.0; // R323 (10K ohm)
-	C1 = 6.8e-9;  // C322 (6800pF)
-	C2 = 3.9e-9;  // C323 (3900pF)
-	cutoff = 1.0 / (PT2_TWO_PI * pt2_sqrt(R1 * R2 * C1 * C2)); // ~3090.533Hz
-	qfactor = pt2_sqrt(R1 * R2 * C1 * C2) / (C2 * (R1 + R2)); // ~0.660225
-	calcLEDFilterCoeffs(dAudioFreq, cutoff, qfactor, &filterLED);
-
-	// A500 1-pole (6dB/oct) static RC high-pass filter:
-	R = 1390.0;   // R324 (1K ohm) + R325 (390 ohm)
-	C = 2.233e-5; // C334 (22uF) + C335 (0.33uF)
-	cutoff = 1.0 / (PT2_TWO_PI * R * C); // ~5.128Hz
-	calcRCFilterCoeffs(dAudioFreq, cutoff, &filterHiA500);
-
-	// A1200 1-pole (6dB/oct) static RC high-pass filter:
-	R = 1390.0; // R324 (1K ohm resistor) + R325 (390 ohm resistor)
-	C = 2.2e-5; // C334 (22uF capacitor)
-	cutoff = 1.0 / (PT2_TWO_PI * R * C); // ~5.205Hz
-	calcRCFilterCoeffs(dAudioFreq, cutoff, &filterHiA1200);
-}
-
-void mixerSetStereoSeparation(uint8_t percentage) // 0..100 (percentage)
-{
 	assert(percentage <= 100);
 
 	stereoSeparation = percentage;
@@ -1087,17 +402,12 @@
 	dSideFactor = (percentage / 100.0) * STEREO_NORM_FACTOR;
 }
 
-static double ciaBpm2Hz(int32_t bpm)
+void generateBpmTable(double dAudioFreq, bool vblankTimingFlag)
 {
-	if (bpm == 0)
-		return 0.0;
+	const bool audioWasntLocked = !audio.locked;
+	if (audioWasntLocked)
+		lockAudio();
 
-	const uint32_t ciaPeriod = 1773447 / bpm; // yes, PT truncates here
-	return (double)CIA_PAL_CLK / (ciaPeriod+1); // +1, CIA triggers on underflow
-}
-
-static void generateBpmTables(bool vblankTimingFlag)
-{
 	for (int32_t bpm = 32; bpm <= 255; bpm++)
 	{
 		double dBpmHz;
@@ -1107,16 +417,17 @@
 		else
 			dBpmHz = ciaBpm2Hz(bpm);
 
-		const double dSamplesPerTick      = audio.outputRate / dBpmHz;
-		const double dSamplesPerTick28kHz = PAT2SMP_HI_FREQ  / dBpmHz; // PAT2SMP hi quality
-		const double dSamplesPerTick20kHz = PAT2SMP_LO_FREQ  / dBpmHz; // PAT2SMP low quality
+		const double dSamplesPerTick = dAudioFreq / dBpmHz;
 
 		// convert to rounded 32.32 fixed-point
 		const int32_t i = bpm - 32;
-		audio.bpmTable[i]      = (int64_t)((dSamplesPerTick      * (UINT32_MAX+1.0)) + 0.5);
-		audio.bpmTable28kHz[i] = (int64_t)((dSamplesPerTick28kHz * (UINT32_MAX+1.0)) + 0.5);
-		audio.bpmTable20kHz[i] = (int64_t)((dSamplesPerTick20kHz * (UINT32_MAX+1.0)) + 0.5);
+		audio.samplesPerTickTable[i] = (int64_t)((dSamplesPerTick * (UINT32_MAX+1.0)) + 0.5);
 	}
+
+	audio.tickSampleCounter64 = 0;
+
+	if (audioWasntLocked)
+		unlockAudio();
 }
 
 static void generateTickLengthTable(bool vblankTimingFlag)
@@ -1148,7 +459,7 @@
 		lockAudio();
 
 	const bool vblankTimingMode = (editor.timingMode == TEMPO_MODE_VBLANK);
-	generateBpmTables(vblankTimingMode);
+	generateBpmTable(audio.outputRate, vblankTimingMode);
 	generateTickLengthTable(vblankTimingMode);
 
 	if (audioWasntLocked)
@@ -1189,46 +500,36 @@
 
 	audio.outputRate = have.freq;
 	audio.audioBufferSize = have.samples;
-	audio.dPeriodToDeltaDiv = (double)PAULA_PAL_CLK / audio.outputRate;
+	audio.oversamplingFlag = (audio.outputRate < 96000); // we do 2x oversampling if the audio output rate is below 96kHz
 
-	// we do 2x oversampling if the audio output rate is below 96kHz
-	audio.oversamplingFlag = (audio.outputRate < 96000);
+	const int32_t audioFrequency = audio.oversamplingFlag ? audio.outputRate*2 : audio.outputRate;
+	const uint32_t maxSamplesToMix = (int32_t)ceil(audioFrequency / (REPLAYER_MIN_BPM / 2.5));
 
-	updateReplayerTimingMode(); // also generates the BPM tables used below
+	dMixBufferL = (double *)malloc((maxSamplesToMix + 1) * sizeof (double));
+	dMixBufferR = (double *)malloc((maxSamplesToMix + 1) * sizeof (double));
 
-	const int32_t lowestBPM = 32;
-	const int32_t pat2SmpMaxSamples = (audio.bpmTable20kHz[lowestBPM-32] + (1LL + 31)) >> 32; // ceil (rounded upwards)
-	const int32_t renderMaxSamples = (audio.bpmTable[lowestBPM-32] + (1LL + 31)) >> 32; // ceil (rounded upwards)
-	const int32_t maxSamplesToMix = MAX(pat2SmpMaxSamples, renderMaxSamples) * 2; // *2 because PAT2SMP uses 2x oversampling all the time
-
-	dMixBufferLUnaligned = (double *)MALLOC_PAD(maxSamplesToMix * sizeof (double), 256);
-	dMixBufferRUnaligned = (double *)MALLOC_PAD(maxSamplesToMix * sizeof (double), 256);
-
-	if (dMixBufferLUnaligned == NULL || dMixBufferRUnaligned == NULL)
+	if (dMixBufferL == NULL || dMixBufferR == NULL)
 	{
+		// these two are free'd later
+
 		showErrorMsgBox("Out of memory!");
 		return false;
 	}
 
-	dMixBufferL = (double *)ALIGN_PTR(dMixBufferLUnaligned, 256);
-	dMixBufferR = (double *)ALIGN_PTR(dMixBufferRUnaligned, 256);
-
-	mixerSetStereoSeparation(config.stereoSeparation);
-
-	filterModel = config.filterModel;
-	ledFilterEnabled = false;
-	calculateFilterCoeffs();
-
-	audio.samplesPerTick64 = audio.bpmTable[125-32]; // BPM 125
-	audio.tickSampleCounter64 = 0; // zero tick sample counter so that it will instantly initiate a tick
-
+	paulaSetOutputFrequency(audio.outputRate, audio.oversamplingFlag);
+	audioSetStereoSeparation(config.stereoSeparation);
+	updateReplayerTimingMode(); // also generates the BPM table (audio.bpmTable)
+	setAmigaFilterModel(config.filterModel);
+	setLEDFilter(false);
+	setupAmigaFilters(audio.outputRate);
 	calcAudioLatencyVars(audio.audioBufferSize, audio.outputRate);
 
-	resetCachedMixerPeriod();
 	clearMixerDownsamplerStates();
 	audio.resetSyncTickTimeFlag = true;
 
-	updateFilterFunc();
+	audio.samplesPerTick64 = audio.samplesPerTickTable[125-32]; // BPM 125
+	audio.tickSampleCounter64 = 0; // zero tick sample counter so that it will instantly initiate a tick
+
 	SDL_PauseAudioDevice(dev, false);
 	return true;
 }
@@ -1242,39 +543,43 @@
 		dev = 0;
 	}
 
-	if (dMixBufferLUnaligned != NULL)
+	if (dMixBufferL != NULL)
 	{
-		free(dMixBufferLUnaligned);
-		dMixBufferLUnaligned = NULL;
+		free(dMixBufferL);
+		dMixBufferL = NULL;
 	}
 
-	if (dMixBufferRUnaligned != NULL)
+	if (dMixBufferR != NULL)
 	{
-		free(dMixBufferRUnaligned);
-		dMixBufferRUnaligned = NULL;
+		free(dMixBufferR);
+		dMixBufferR = NULL;
 	}
 }
 
 void toggleAmigaPanMode(void)
 {
+	panningMode = (panningMode + 1) % 3;
+
 	const bool audioWasntLocked = !audio.locked;
 	if (audioWasntLocked)
 		lockAudio();
 
-	amigaPanFlag ^= 1;
-	if (!amigaPanFlag)
-	{
-		mixerSetStereoSeparation(config.stereoSeparation);
-		displayMsg("AMIGA PANNING OFF");
-	}
+	if (panningMode == 0)
+		audioSetStereoSeparation(config.stereoSeparation);
+	else if (panningMode == 1)
+		audioSetStereoSeparation(0);
 	else
-	{
-		mixerSetStereoSeparation(100);
-		displayMsg("AMIGA PANNING ON");
-	}
+		audioSetStereoSeparation(100);
 
 	if (audioWasntLocked)
 		unlockAudio();
+
+	if (panningMode == 0)
+		displayMsg("CUSTOM PANNING");
+	else if (panningMode == 1)
+		displayMsg("CENTERED PANNING");
+	else
+		displayMsg("AMIGA PANNING");
 }
 
 uint16_t get16BitPeak(int16_t *sampleData, uint32_t sampleLength)
--- a/src/pt2_audio.h
+++ b/src/pt2_audio.h
@@ -2,18 +2,25 @@
 
 #include <stdint.h>
 #include <stdbool.h>
-#include "pt2_header.h" // AMIGA_VOICES
 
+// for the low-pass/high-pass filters in the SAMPLER screen
+#define FILTERS_BASE_FREQ (PAULA_PAL_CLK / 214.0)
+
+enum
+{
+	AUDIO_NO_OVERSAMPLING = 0,
+	AUDIO_2X_OVERSAMPLING = 1
+};
+
 typedef struct audio_t
 {
 	volatile bool locked, isSampling;
 
-	bool forceSoundCardSilence, oversamplingFlag;
+	bool ledFilterEnabled, oversamplingFlag;
 	
 	uint32_t outputRate, audioBufferSize;
 	int64_t tickSampleCounter64, samplesPerTick64;
-	int64_t bpmTable[256-32], bpmTable28kHz[256-32], bpmTable20kHz[256-32]; // 32.32 fixed-point
-	double dPeriodToDeltaDiv;
+	int64_t samplesPerTickTable[256-32]; // 32.32 fixed-point
 
 	// for audio sampling
 	bool rescanAudioDevicesSupported;
@@ -23,46 +30,10 @@
 	uint64_t tickLengthTable[224];
 } audio_t;
 
-typedef struct voice_t
-{
-	volatile bool DMA_active;
-
-	// internal values (don't modify directly!)
-	int8_t AUD_DAT[2]; // DMA data buffer
-	const int8_t *location; // current location
-	uint16_t lengthCounter; // current length
-	int32_t sampleCounter; // how many bytes left in AUD_DAT
-	double dSample; // current sample point
-
-	// registers modified by Paula functions
-	const int8_t *AUD_LC; // location
-	uint16_t AUD_LEN; // length (in words)
-	double AUD_PER_delta, AUD_PER_deltamul; // delta
-	double AUD_VOL; // volume
-
-	double dDelta, dPhase;
-
-	// for BLEP synthesis
-	double dLastDelta, dLastPhase, dLastDeltaMul, dBlepOffset, dDeltaMul;
-
-	// period cache
-	int32_t oldPeriod;
-	double dOldVoiceDelta, dOldVoiceDeltaMul;
-
-	// used for pt2_sync.c
-	uint8_t syncFlags;
-	uint8_t syncVolume;
-	int32_t syncPeriod;
-	int32_t syncTriggerLength;
-	const int8_t *syncTriggerData;
-} paulaVoice_t;
-
 void updateReplayerTimingMode(void);
-
 void setSyncTickTimeLen(uint32_t timeLen, uint32_t timeLenFrac);
-void resetCachedMixerPeriod(void);
 void resetAudioDithering(void);
-
+void generateBpmTable(double dAudioFreq, bool vblankTimingFlag);
 uint16_t get16BitPeak(int16_t *sampleData, uint32_t sampleLength);
 uint32_t get32BitPeak(int32_t *sampleData, uint32_t sampleLength);
 float getFloatPeak(float *fSampleData, uint32_t sampleLength);
@@ -71,24 +42,12 @@
 void normalize32BitTo8Bit(int32_t *sampleData, uint32_t sampleLength);
 void normalizeFloatTo8Bit(float *fSampleData, uint32_t sampleLength);
 void normalizeDoubleTo8Bit(double *dSampleData, uint32_t sampleLength);
-
-void setLEDFilter(bool state, bool doLockAudio);
-void toggleLEDFilter(void);
 void toggleAmigaPanMode(void);
-void toggleFilterModel(void);
-void paulaStopDMA(int32_t ch);
-void paulaStartDMA(int32_t ch);
-void paulaSetPeriod(int32_t ch, uint16_t period);
-void paulaSetVolume(int32_t ch, uint16_t vol);
-void paulaSetLength(int32_t ch, uint16_t len);
-void paulaSetData(int32_t ch, const int8_t *src);
 void lockAudio(void);
 void unlockAudio(void);
-void mixerUpdateLoops(void);
-void mixerKillVoice(int32_t ch);
-void turnOffVoices(void);
-void mixerSetStereoSeparation(uint8_t percentage);
+void audioSetStereoSeparation(uint8_t percentage);
 void outputAudio(int16_t *target, int32_t numSamples);
+bool setupAudio(void);
+void audioClose(void);
 
 extern audio_t audio; // pt2_audio.c
-extern paulaVoice_t paula[AMIGA_VOICES]; // pt2_audio.c
--- a/src/pt2_blep.h
+++ b/src/pt2_blep.h
@@ -3,6 +3,7 @@
 #pragma once
 
 #include <stdint.h>
+#include "pt2_paula.h" // PAULA_VOICES
 
 /* aciddose:
 ** information on blep variables
--- a/src/pt2_bmp.c
+++ b/src/pt2_bmp.c
@@ -11,13 +11,11 @@
 #include "pt2_bmp.h"
 #include "pt2_tables.h"
 
-uint32_t *aboutScreenBMP   = NULL, *clearDialogBMP     = NULL;
-uint32_t *diskOpScreenBMP  = NULL, *editOpModeCharsBMP = NULL, *mod2wavBMP         = NULL;
-uint32_t *editOpScreen1BMP = NULL, *editOpScreen2BMP   = NULL, *samplerVolumeBMP   = NULL;
-uint32_t *editOpScreen3BMP = NULL, *editOpScreen4BMP   = NULL, *spectrumVisualsBMP = NULL;
-uint32_t *muteButtonsBMP   = NULL, *posEdBMP           = NULL, *samplerFiltersBMP  = NULL;
-uint32_t *samplerScreenBMP = NULL, *pat2SmpDialogBMP   = NULL, *trackerFrameBMP    = NULL;
-uint32_t *yesNoDialogBMP   = NULL, *bigYesNoDialogBMP  = NULL, *sampleMonitorBMP   = NULL;
+uint32_t *aboutScreenBMP   = NULL, *diskOpScreenBMP  = NULL, *editOpModeCharsBMP = NULL;
+uint32_t *editOpScreen1BMP = NULL, *editOpScreen2BMP = NULL, *samplerVolumeBMP   = NULL;
+uint32_t *editOpScreen3BMP = NULL, *editOpScreen4BMP = NULL, *spectrumVisualsBMP = NULL;
+uint32_t *muteButtonsBMP   = NULL, *posEdBMP         = NULL, *samplerFiltersBMP  = NULL;
+uint32_t *samplerScreenBMP = NULL, *trackerFrameBMP  = NULL, *sampleMonitorBMP   = NULL;
 uint32_t *samplingBoxBMP   = NULL;
 
 // fix-bitmaps for 128K sample mode
@@ -28,11 +26,9 @@
 void createBitmaps(void)
 {
 	uint8_t r8, g8, b8, r8_2, g8_2, b8_2;
-	uint16_t pixel12;
-	uint32_t i, j, x, y, pixel24;
 
-	pixel24 = video.palette[PAL_PATCURSOR];
-	for (y = 0; y < 14; y++)
+	uint32_t pixel24 = video.palette[PAL_PATCURSOR];
+	for (int32_t y = 0; y < 14; y++)
 	{
 		// top two rows have a lighter color
 		if (y < 2)
@@ -56,7 +52,7 @@
 			else
 				b8 = 0xFF;
 
-			for (x = 0; x < 11; x++)
+			for (int32_t x = 0; x < 11; x++)
 				patternCursorBMP[(y * 11) + x] = RGB24(r8, g8, b8);
 		}
 
@@ -65,7 +61,7 @@
 		{
 			patternCursorBMP[(y * 11) + 0] = pixel24;
 
-			for (x = 1; x < 10; x++)
+			for (int32_t x = 1; x < 10; x++)
 				patternCursorBMP[(y * 11) + x] = video.palette[PAL_COLORKEY];
 
 			patternCursorBMP[(y * 11) + 10] = pixel24;
@@ -93,19 +89,19 @@
 			else
 				b8 = 0x00;
 
-			for (x = 0; x < 11; x++)
+			for (int32_t x = 0; x < 11; x++)
 				patternCursorBMP[(y * 11) + x] = RGB24(r8, g8, b8);
 		}
 	}
 
 	// create spectrum analyzer bar graphics
-	for (i = 0; i < 36; i++)
+	for (int32_t i = 0; i < 36; i++)
 		analyzerColorsRGB24[i] = RGB12_to_RGB24(analyzerColors[35-i]);
 
 	// create VU-Meter bar graphics
-	for (i = 0; i < 48; i++)
+	for (int32_t i = 0; i < 48; i++)
 	{
-		pixel12 = vuMeterColors[47-i];
+		uint16_t pixel12 = vuMeterColors[47-i];
 
 		r8_2 = r8 = R12_to_R24(pixel12);
 		g8_2 = g8 = G12_to_G24(pixel12);
@@ -134,7 +130,7 @@
 		vuMeterBMP[(i * 10) + 1] = pixel24;
 
 		// main pixels
-		for (j = 2; j < 8; j++)
+		for (int32_t j = 2; j < 8; j++)
 			vuMeterBMP[(i * 10) + j] = RGB24(r8, g8, b8);
 
 		// darker pixels on the right side
@@ -173,14 +169,9 @@
 	if (samplerScreenBMP != NULL) free(samplerScreenBMP);
 	if (samplerVolumeBMP != NULL) free(samplerVolumeBMP);
 	if (samplerFiltersBMP != NULL) free(samplerFiltersBMP);
-	if (clearDialogBMP != NULL) free(clearDialogBMP);
 	if (diskOpScreenBMP != NULL) free(diskOpScreenBMP);
-	if (mod2wavBMP != NULL) free(mod2wavBMP);
 	if (posEdBMP != NULL) free(posEdBMP);
 	if (spectrumVisualsBMP != NULL) free(spectrumVisualsBMP);
-	if (yesNoDialogBMP != NULL) free(yesNoDialogBMP);
-	if (bigYesNoDialogBMP != NULL) free(bigYesNoDialogBMP);
-	if (pat2SmpDialogBMP != NULL) free(pat2SmpDialogBMP);
 	if (editOpScreen1BMP != NULL) free(editOpScreen1BMP);
 	if (editOpScreen2BMP != NULL) free(editOpScreen2BMP);
 	if (editOpScreen3BMP != NULL) free(editOpScreen3BMP);
@@ -194,22 +185,16 @@
 
 uint32_t *unpackBMP(const uint8_t *src, uint32_t packedLen)
 {
-	const uint8_t *packSrc;
-	uint8_t *tmpBuffer, *packDst, byteIn;
-	int16_t count;
-	uint32_t *dst;
-	
-	int32_t decodedLength, i;
-
 	// RLE decode
-	decodedLength = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
 
+	int32_t decodedLength = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+
 	// 2-bit to 8-bit conversion
-	dst = (uint32_t *)malloc(((decodedLength * 4) * sizeof (int32_t)) + 8);
+	uint32_t *dst = (uint32_t *)malloc(((decodedLength * 4) * sizeof (int32_t)) + 8);
 	if (dst == NULL)
 		return NULL;
 
-	tmpBuffer = (uint8_t *)malloc(decodedLength + 128); // some margin is needed, the packer is buggy
+	uint8_t *tmpBuffer = (uint8_t *)malloc(decodedLength + 128); // some margin is needed, the packer is buggy
 	if (tmpBuffer == NULL)
 	{
 		free(dst);
@@ -216,16 +201,16 @@
 		return NULL;
 	}
 
-	packSrc = src + 4; // skip "length" field
-	packDst = tmpBuffer;
+	const uint8_t *packSrc = src + 4; // skip "length" field
+	uint8_t *packDst = tmpBuffer;
 
-	i = packedLen - 4; // subtract "length" field
+	int32_t i = packedLen - 4; // subtract "length" field
 	while (i > 0)
 	{
-		byteIn = *packSrc++;
+		uint8_t byteIn = *packSrc++;
 		if (byteIn == 0xCC) // compactor code
 		{
-			count  = *packSrc++;
+			int16_t count  = *packSrc++;
 			byteIn = *packSrc++;
 
 			while (count-- >= 0)
@@ -243,21 +228,21 @@
 
 	for (i = 0; i < decodedLength; i++)
 	{
-		byteIn = (tmpBuffer[i] & 0xC0) >> 6;
-		assert(byteIn < PALETTE_NUM);
-		dst[(i << 2) + 0] = video.palette[byteIn];
+		const uint8_t byte1 = (tmpBuffer[i] & 0xC0) >> 6;
+		assert(byte1 < PALETTE_NUM);
+		dst[(i << 2) + 0] = video.palette[byte1];
 
-		byteIn = (tmpBuffer[i] & 0x30) >> 4;
-		assert(byteIn < PALETTE_NUM);
-		dst[(i << 2) + 1] = video.palette[byteIn];
+		const uint8_t byte2 = (tmpBuffer[i] & 0x30) >> 4;
+		assert(byte2 < PALETTE_NUM);
+		dst[(i << 2) + 1] = video.palette[byte2];
 
-		byteIn = (tmpBuffer[i] & 0x0C) >> 2;
-		assert(byteIn < PALETTE_NUM);
-		dst[(i << 2) + 2] = video.palette[byteIn];
+		const uint8_t byte3 = (tmpBuffer[i] & 0x0C) >> 2;
+		assert(byte3 < PALETTE_NUM);
+		dst[(i << 2) + 2] = video.palette[byte3];
 
-		byteIn = (tmpBuffer[i] & 0x03) >> 0;
-		assert(byteIn < PALETTE_NUM);
-		dst[(i << 2) + 3] = video.palette[byteIn];
+		const uint8_t byte4 = (tmpBuffer[i] & 0x03) >> 0;
+		assert(byte4 < PALETTE_NUM);
+		dst[(i << 2) + 3] = video.palette[byte4];
 	}
 
 	free(tmpBuffer);
@@ -273,14 +258,9 @@
 	samplerScreenBMP = unpackBMP(samplerScreenPackedBMP, sizeof (samplerScreenPackedBMP));
 	samplerVolumeBMP = unpackBMP(samplerVolumePackedBMP, sizeof (samplerVolumePackedBMP));
 	samplerFiltersBMP = unpackBMP(samplerFiltersPackedBMP, sizeof (samplerFiltersPackedBMP));
-	clearDialogBMP = unpackBMP(clearDialogPackedBMP, sizeof (clearDialogPackedBMP));
 	diskOpScreenBMP = unpackBMP(diskOpScreenPackedBMP, sizeof (diskOpScreenPackedBMP));
-	mod2wavBMP = unpackBMP(mod2wavPackedBMP, sizeof (mod2wavPackedBMP));
 	posEdBMP = unpackBMP(posEdPackedBMP, sizeof (posEdPackedBMP));
 	spectrumVisualsBMP = unpackBMP(spectrumVisualsPackedBMP, sizeof (spectrumVisualsPackedBMP));
-	yesNoDialogBMP = unpackBMP(yesNoDialogPackedBMP, sizeof (yesNoDialogPackedBMP));
-	bigYesNoDialogBMP = unpackBMP(bigYesNoDialogPackedBMP, sizeof (bigYesNoDialogPackedBMP));
-	pat2SmpDialogBMP = unpackBMP(pat2SmpDialogPackedBMP, sizeof (pat2SmpDialogPackedBMP));
 	editOpScreen1BMP = unpackBMP(editOpScreen1PackedBMP, sizeof (editOpScreen1PackedBMP));
 	editOpScreen2BMP = unpackBMP(editOpScreen2PackedBMP, sizeof (editOpScreen2PackedBMP));
 	editOpScreen3BMP = unpackBMP(editOpScreen3PackedBMP, sizeof (editOpScreen3PackedBMP));
@@ -291,14 +271,13 @@
 	sampleMonitorBMP = unpackBMP(sampleMonitorPackedBMP, sizeof (sampleMonitorPackedBMP));
 	samplingBoxBMP = unpackBMP(samplingBoxPackedBMP, sizeof (samplingBoxPackedBMP));
 
-	if (fix128KTrackerBMP  == NULL || fix128KPosBMP      == NULL || fix128KChordBMP  == NULL || 
-		trackerFrameBMP    == NULL || samplerScreenBMP   == NULL || samplerVolumeBMP == NULL ||
-		clearDialogBMP     == NULL || diskOpScreenBMP    == NULL || mod2wavBMP       == NULL ||
-		posEdBMP           == NULL || spectrumVisualsBMP == NULL || yesNoDialogBMP   == NULL ||
-		editOpScreen1BMP   == NULL || editOpScreen2BMP   == NULL || editOpScreen3BMP == NULL ||
-		editOpScreen4BMP   == NULL || aboutScreenBMP     == NULL || muteButtonsBMP   == NULL ||
-		editOpModeCharsBMP == NULL || samplerFiltersBMP  == NULL || yesNoDialogBMP   == NULL ||
-		bigYesNoDialogBMP  == NULL || sampleMonitorBMP   == NULL || samplingBoxBMP   == NULL)
+	if (fix128KTrackerBMP  == NULL || fix128KPosBMP     == NULL || fix128KChordBMP    == NULL ||
+		trackerFrameBMP    == NULL || samplerScreenBMP  == NULL || samplerVolumeBMP   == NULL ||
+		diskOpScreenBMP    == NULL || posEdBMP          == NULL || spectrumVisualsBMP == NULL ||
+		editOpScreen1BMP   == NULL || editOpScreen2BMP  == NULL || editOpScreen3BMP   == NULL ||
+		editOpScreen4BMP   == NULL || aboutScreenBMP    == NULL || muteButtonsBMP     == NULL ||
+		editOpModeCharsBMP == NULL || samplerFiltersBMP == NULL || sampleMonitorBMP   == NULL ||
+		samplingBoxBMP     == NULL)
 	{
 		showErrorMsgBox("Out of memory!");
 		return false; // BMPs are free'd in cleanUp()
--- a/src/pt2_bmp.h
+++ b/src/pt2_bmp.h
@@ -28,7 +28,6 @@
 extern const uint8_t editOpScreen2PackedBMP[1502];
 extern const uint8_t editOpScreen3PackedBMP[1736];
 extern const uint8_t editOpScreen4PackedBMP[1713];
-extern const uint8_t mod2wavPackedBMP[607];
 extern const uint8_t muteButtonsPackedBMP[46];
 extern const uint8_t posEdPackedBMP[1375];
 extern const uint8_t sampleMonitorPackedBMP[441];
@@ -38,9 +37,6 @@
 extern const uint8_t spectrumVisualsPackedBMP[2217];
 extern const uint8_t tracker128KFixPackedBMP[363];
 extern const uint8_t trackerFramePackedBMP[8486];
-extern const uint8_t yesNoDialogPackedBMP[476];
-extern const uint8_t bigYesNoDialogPackedBMP[472];
-extern const uint8_t pat2SmpDialogPackedBMP[520];
 extern const uint8_t samplingBoxPackedBMP[1379];
 
 // these are filled/normalized on init, so no const
@@ -53,13 +49,9 @@
 extern uint32_t *editOpScreen2BMP;
 extern uint32_t *editOpScreen3BMP;
 extern uint32_t *editOpScreen4BMP;
-extern uint32_t *yesNoDialogBMP;
-extern uint32_t *bigYesNoDialogBMP;
 extern uint32_t *spectrumVisualsBMP;
 extern uint32_t *posEdBMP;
-extern uint32_t *mod2wavBMP;
 extern uint32_t *diskOpScreenBMP;
-extern uint32_t *clearDialogBMP;
 extern uint32_t *samplerVolumeBMP;
 extern uint32_t *samplerFiltersBMP;
 extern uint32_t *samplerScreenBMP;
@@ -67,7 +59,6 @@
 extern uint32_t *aboutScreenBMP;
 extern uint32_t *muteButtonsBMP;
 extern uint32_t *editOpModeCharsBMP;
-extern uint32_t *pat2SmpDialogBMP;
 extern uint32_t *sampleMonitorBMP;
 extern uint32_t *samplingBoxBMP;
 
--- a/src/pt2_chordmaker.c
+++ b/src/pt2_chordmaker.c
@@ -6,12 +6,9 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <stdbool.h>
-#include "pt2_header.h"
 #include "pt2_config.h"
-#include "pt2_mouse.h"
 #include "pt2_textout.h"
 #include "pt2_visuals.h"
-#include "pt2_structs.h"
 #include "pt2_helpers.h"
 #include "pt2_tables.h"
 #include "pt2_sampler.h"
@@ -18,6 +15,7 @@
 #include "pt2_audio.h"
 #include "pt2_blep.h"
 #include "pt2_downsample2x.h"
+#include "pt2_replayer.h"
 
 #define MAX_NOTES 4
 
@@ -69,14 +67,10 @@
 // this has 2x oversampling for BLEP to function properly with all pitches
 void mixChordSample(void)
 {
-	bool smpLoopFlag;
 	char smpText[22+1];
-	int8_t *smpData, sameNotes, smpVolume;
-	uint8_t smpFinetune, finetune;
-	int32_t i, smpLoopStart, smpLoopLength, smpEnd;
+	int32_t i;
 	sampleMixer_t mixCh[MAX_NOTES];
-	moduleSample_t *s;
-	blep_t blep[MAX_NOTES];
+	blep_t bleps[MAX_NOTES];
 
 	if (editor.sampleZero)
 	{
@@ -90,7 +84,7 @@
 		return;
 	}
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length == 0)
 	{
 		statusSampleIsEmpty();
@@ -98,7 +92,7 @@
 	}
 
 	// check if all notes are the same (illegal)
-	sameNotes = true;
+	bool sameNotes = true;
 	if (editor.note2 != 36 && editor.note2 != editor.note1) sameNotes = false; else editor.note2 = 36;
 	if (editor.note3 != 36 && editor.note3 != editor.note1) sameNotes = false; else editor.note3 = 36;
 	if (editor.note4 != 36 && editor.note4 != editor.note1) sameNotes = false; else editor.note4 = 36;
@@ -118,11 +112,11 @@
 	ui.updateChordNote4Text = true;
 
 	// setup some variables
-	smpLoopStart = s->loopStart;
-	smpLoopLength = s->loopLength;
-	smpLoopFlag = (smpLoopStart + smpLoopLength) > 2;
-	smpEnd = smpLoopFlag ? (smpLoopStart + smpLoopLength) : s->length;
-	smpData = &song->sampleData[s->offset];
+	int32_t smpLoopStart = s->loopStart;
+	int32_t smpLoopLength = s->loopLength;
+	bool smpLoopFlag = (smpLoopStart + smpLoopLength) > 2;
+	int32_t smpEnd = smpLoopFlag ? (smpLoopStart + smpLoopLength) : s->length;
+	int8_t *smpData = &song->sampleData[s->offset];
 
 	if (editor.newOldFlag == 0)
 	{
@@ -140,8 +134,8 @@
 			return;
 		}
 
-		smpFinetune = s->fineTune;
-		smpVolume = s->volume;
+		uint8_t smpFinetune = s->fineTune;
+		int8_t smpVolume = s->volume;
 		memcpy(smpText, s->text, sizeof (smpText));
 
 		s = &song->samples[i];
@@ -169,7 +163,7 @@
 
 	// setup mixing lengths and deltas
 
-	finetune = s->fineTune & 0xF;
+	uint8_t finetune = s->fineTune & 0xF;
 	const double dOutputHz = ((double)PAULA_PAL_CLK / periodTable[24]) * 2.0;
 
 	const double dClk = PAULA_PAL_CLK / dOutputHz;
@@ -179,11 +173,11 @@
 	if (editor.note4 < 36) setupMixVoice(&mixCh[3], smpEnd, dClk / periodTable[(finetune * 37) + editor.note4]);
 
 	// start mixing
-	memset(blep, 0, sizeof (blep));
+	memset(bleps, 0, sizeof (bleps));
 	turnOffVoices();
 
 	sampleMixer_t *v = mixCh;
-	blep_t *bSmp = blep;
+	blep_t *bSmp = bleps;
 
 	for (i = 0; i < MAX_NOTES; i++, v++, bSmp++)
 	{
@@ -212,7 +206,8 @@
 				v->dPhase -= 1.0;
 				v->dLastPhase = v->dPhase;
 
-				if (++v->pos >= smpEnd)
+				v->pos++;
+				if (v->pos >= smpEnd)
 				{
 					if (smpLoopFlag)
 					{
@@ -222,7 +217,10 @@
 						}
 						while (v->pos >= smpEnd);
 					}
-					else break; // we should insert an ending blep here, but I lost that code ages ago...
+					else
+					{
+						break;
+					}
 				}
 			}
 		}
@@ -270,11 +268,9 @@
 
 void recalcChordLength(void)
 {
-	int8_t note;
-	int32_t len;
-	moduleSample_t *s;
+	int32_t note;
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 
 	if (editor.chordLengthMin)
 	{
@@ -294,7 +290,7 @@
 	}
 	else
 	{
-		len = (s->length * periodTable[(37 * s->fineTune) + note]) / periodTable[24];
+		int32_t len = (s->length * periodTable[(37 * s->fineTune) + note]) / periodTable[24];
 		if (len > config.maxSampleLength)
 			len = config.maxSampleLength;
 
@@ -583,13 +579,4 @@
 	}
 
 	ui.updateChordNote4Text = true;
-}
-
-void makeChord(void)
-{
-	ui.askScreenShown = true;
-	ui.askScreenType = ASK_MAKE_CHORD;
-	pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-	setStatusMessage("MAKE CHORD?", NO_CARRY);
-	renderAskDialog();
 }
--- a/src/pt2_chordmaker.h
+++ b/src/pt2_chordmaker.h
@@ -1,5 +1,6 @@
 #pragma once
 
+void mixChordSample(void);
 void recalcChordLength(void);
 void resetChord(void);
 void undoChord(void);
@@ -15,4 +16,3 @@
 void selectChordNote2(void);
 void selectChordNote3(void);
 void selectChordNote4(void);
-void makeChord(void);
--- a/src/pt2_config.c
+++ b/src/pt2_config.c
@@ -13,14 +13,11 @@
 #include <unistd.h>
 #include <limits.h>
 #endif
-#include "pt2_header.h"
 #include "pt2_helpers.h"
 #include "pt2_config.h"
 #include "pt2_tables.h"
-#include "pt2_audio.h"
-#include "pt2_diskop.h"
-#include "pt2_textout.h"
 #include "pt2_sampler.h"
+#include "pt2_diskop.h" // changePathToDesktop()
 
 #ifndef _WIN32
 static char oldCwd[PATH_MAX];
@@ -35,7 +32,6 @@
 
 void loadConfig(void)
 {
-	bool proTrackerDotIniFound, ptDotConfigFound;
 #ifndef _WIN32
 	bool colorsDotIniFound;
 #endif
@@ -67,6 +63,7 @@
 	config.pixelFilter = PIXELFILTER_NEAREST;
 	config.integerScaling = true;
 	config.audioInputFrequency = 44100;
+	config.mod2WavOutputFreq = 44100;
 	config.keepEditModeAfterStepPlay = false;
 
 	config.maxSampleLength = 65534;
@@ -77,7 +74,7 @@
 #endif
 
 	// load protracker.ini
-	proTrackerDotIniFound = false;
+	bool proTrackerDotIniFound = false;
 
 #ifdef _WIN32
 	f = fopen("protracker.ini", "r");
@@ -90,7 +87,7 @@
 		proTrackerDotIniFound = true;
 
 	// check in ~/.protracker/
-	if (!proTrackerDotIniFound && changePathToHome() && chdir(".protracker") == 0)
+	if (!proTrackerDotIniFound && changePathToDesktop() && chdir(".protracker") == 0)
 	{
 		f = fopen("protracker.ini", "r");
 		if (f != NULL)
@@ -106,7 +103,7 @@
 	editor.oldTempo = editor.initialTempo;
 
 	// load PT.Config (if available)
-	ptDotConfigFound = false;
+	bool ptDotConfigFound = false;
 
 #ifdef _WIN32
 	f = openPTDotConfig();
@@ -119,7 +116,7 @@
 		ptDotConfigFound = true;
 
 	// check in ~/.protracker/
-	if (!ptDotConfigFound && changePathToHome() && chdir(".protracker") == 0)
+	if (!ptDotConfigFound && changePathToDesktop() && chdir(".protracker") == 0)
 	{
 		f = openPTDotConfig();
 		if (f != NULL)
@@ -143,7 +140,7 @@
 	colorsDotIniFound = loadColorsDotIni();
 
 	// check in ~/.protracker/
-	if (!colorsDotIniFound && changePathToHome() && chdir(".protracker") == 0)
+	if (!colorsDotIniFound && changePathToDesktop() && chdir(".protracker") == 0)
 		loadColorsDotIni();
 #endif
 
@@ -157,14 +154,11 @@
 
 static bool loadProTrackerDotIni(FILE *f)
 {
-	char *configBuffer, *configLine;
-	uint32_t configFileSize, lineLen, i;
-
 	fseek(f, 0, SEEK_END);
-	configFileSize = ftell(f);
+	uint32_t configFileSize = ftell(f);
 	rewind(f);
 
-	configBuffer = (char *)malloc(configFileSize + 1);
+	char *configBuffer = (char *)malloc(configFileSize + 1);
 	if (configBuffer == NULL)
 	{
 		fclose(f);
@@ -176,10 +170,10 @@
 	configBuffer[configFileSize] = '\0';
 	fclose(f);
 
-	configLine = strtok(configBuffer, "\n");
+	char *configLine = strtok(configBuffer, "\n");
 	while (configLine != NULL)
 	{
-		lineLen = (uint32_t)strlen(configLine);
+		uint32_t lineLen = (uint32_t)strlen(configLine);
 
 		// remove CR in CRLF linefeed (if present)
 		if (lineLen > 1)
@@ -385,7 +379,7 @@
 		{
 			if (lineLen > 11)
 			{
-				i = 11;
+				uint32_t i = 11;
 				while (configLine[i] == ' ') i++; // remove spaces before string (if present)
 				while (configLine[lineLen-1] == ' ') lineLen--; // remove spaces after string (if present)
 
@@ -400,7 +394,7 @@
 		{
 			if (lineLen > 14)
 			{
-				i = 14;
+				uint32_t i = 14;
 				while (configLine[i] == ' ') i++; // remove spaces before string (if present)
 				while (configLine[lineLen-1] == ' ') lineLen--; // remove spaces after string (if present)
 
@@ -441,6 +435,16 @@
 			}
 		}
 
+		// MOD2WAVFREQUENCY
+		else if (!_strnicmp(configLine, "MOD2WAVFREQUENCY=", 17))
+		{
+			if (configLine[17] != '\0')
+			{
+				const int32_t num = atoi(&configLine[17]);
+				config.mod2WavOutputFreq = CLAMP(num, 44100, 192000);
+			}
+		}
+
 		// FREQUENCY
 		else if (!_strnicmp(configLine, "FREQUENCY=", 10))
 		{
@@ -480,16 +484,17 @@
 
 static FILE *openPTDotConfig(void)
 {
-	char tmpFilename[16];
-	uint8_t i;
-	FILE *f;
-
-	f = fopen("PT.Config", "rb"); // PT didn't read PT.Config with no number, but let's support it
+	FILE *f = fopen("PT.Config", "rb"); // PT didn't read PT.Config with no number, but let's support it
 	if (f == NULL)
 	{
+		// try regular PT config filenames (PT.Config-xx)
+		char tmpFilename[16];
+		int32_t i;
+
 		for (i = 0; i < 100; i++)
 		{
 			sprintf(tmpFilename, "PT.Config-%02d", i);
+
 			f = fopen(tmpFilename, "rb");
 			if (f != NULL)
 				break;
@@ -507,12 +512,10 @@
 	char cfgString[24];
 	uint8_t tmp8;
 	uint16_t tmp16;
-	int32_t i;
-	uint32_t configFileSize;
 
 	// get filesize
 	fseek(f, 0, SEEK_END);
-	configFileSize = ftell(f);
+	uint32_t configFileSize = ftell(f);
 	if (configFileSize != 1024)
 	{
 		// not a valid PT.Config file
@@ -538,7 +541,7 @@
 
 	// Palette
 	fseek(f, 154, SEEK_SET);
-	for (i = 0; i < 8; i++)
+	for (int32_t i = 0; i < 8; i++)
 	{
 		fread(&tmp16, 2, 1, f); // stored as Big-Endian
 		tmp16 = SWAP16(tmp16);
@@ -566,7 +569,7 @@
 
 	// Effect Macros
 	fseek(f, 466, SEEK_SET);
-	for (i = 0; i < 10; i++)
+	for (int32_t i = 0; i < 10; i++)
 	{
 		fread(&tmp16, 2, 1, f); // stored as Big-Endian
 		tmp16 = SWAP16(tmp16);
@@ -600,6 +603,9 @@
 	if (tmp8 > 35) tmp8 = 35;
 	editor.tuningNote = tmp8;
 
+	if (editor.tuningNote > 35)
+		editor.tuningNote = 35;
+
 	// Tuning Tone Volume
 	fseek(f, 503, SEEK_SET);
 	fread(&tmp8, 1, 1, f);
@@ -621,7 +627,7 @@
 
 	// VU-Meter Colors
 	fseek(f, 546, SEEK_SET);
-	for (i = 0; i < 48; i++)
+	for (int32_t i = 0; i < 48; i++)
 	{
 		fread(&vuMeterColors[i], 2, 1, f); // stored as Big-Endian
 		vuMeterColors[i] = SWAP16(vuMeterColors[i]);
@@ -629,7 +635,7 @@
 
 	// Spectrum Analyzer Colors
 	fseek(f, 642, SEEK_SET);
-	for (i = 0; i < 36; i++)
+	for (int32_t i = 0; i < 36; i++)
 	{
 		fread(&analyzerColors[i], 2, 1, f); // stored as Big-Endian
 		analyzerColors[i] = SWAP16(analyzerColors[i]);
@@ -643,8 +649,10 @@
 {
 	ch = (char)toupper(ch);
 
-	     if (ch >= 'A' && ch <= 'F') return 10 + (ch - 'A');
-	else if (ch >= '0' && ch <= '9') return ch - '0';
+	if (ch >= 'A' && ch <= 'F')
+		return 10 + (ch - 'A');
+	else if (ch >= '0' && ch <= '9')
+		return ch - '0';
 
 	return 0; // not a hex
 }
@@ -651,21 +659,16 @@
 
 static bool loadColorsDotIni(void)
 {
-	char *configBuffer, *configLine;
-	uint16_t color;
-	uint32_t line, fileSize, lineLen;
-	FILE *f;
-
-	f = fopen("colors.ini", "r");
+	FILE *f = fopen("colors.ini", "r");
 	if (f == NULL)
 		return false;
 
 	// get filesize
 	fseek(f, 0, SEEK_END);
-	fileSize = ftell(f);
+	uint32_t fileSize = ftell(f);
 	rewind(f);
 
-	configBuffer = (char *)malloc(fileSize + 1);
+	char *configBuffer = (char *)malloc(fileSize + 1);
 	if (configBuffer == NULL)
 	{
 		fclose(f);
@@ -678,10 +681,10 @@
 	fclose(f);
 
 	// do parsing
-	configLine = strtok(configBuffer, "\n");
+	char *configLine = strtok(configBuffer, "\n");
 	while (configLine != NULL)
 	{
-		lineLen = (uint32_t)strlen(configLine);
+		uint32_t lineLen = (uint32_t)strlen(configLine);
 
 		// read palette
 		if (lineLen >= (sizeof ("[Palette]")-1))
@@ -690,10 +693,10 @@
 			{
 				configLine = strtok(NULL, "\n");
 
-				line = 0;
+				uint32_t line = 0;
 				while (configLine != NULL && line < 8)
 				{
-					color = (hex2int(configLine[0]) << 8) | (hex2int(configLine[1]) << 4) | hex2int(configLine[2]);
+					uint16_t color = (hex2int(configLine[0]) << 8) | (hex2int(configLine[1]) << 4) | hex2int(configLine[2]);
 					color &= 0xFFF;
 					video.palette[line] = RGB12_to_RGB24(color);
 
@@ -715,10 +718,10 @@
 			{
 				configLine = strtok(NULL, "\n");
 
-				line = 0;
+				uint32_t line = 0;
 				while (configLine != NULL && line < 48)
 				{
-					color = (hex2int(configLine[0]) << 8) | (hex2int(configLine[1]) << 4) | hex2int(configLine[2]);
+					uint16_t color = (hex2int(configLine[0]) << 8) | (hex2int(configLine[1]) << 4) | hex2int(configLine[2]);
 					vuMeterColors[line] = color & 0xFFF;
 
 					configLine = strtok(NULL, "\n");
@@ -739,10 +742,10 @@
 			{
 				configLine = strtok(NULL, "\n");
 
-				line = 0;
+				uint32_t line = 0;
 				while (configLine != NULL && line < 36)
 				{
-					color = (hex2int(configLine[0]) << 8) | (hex2int(configLine[1]) << 4) | hex2int(configLine[2]);
+					uint16_t color = (hex2int(configLine[0]) << 8) | (hex2int(configLine[1]) << 4) | hex2int(configLine[2]);
 					analyzerColors[line] = color & 0xFFF;
 
 					configLine = strtok(NULL, "\n");
--- a/src/pt2_config.h
+++ b/src/pt2_config.h
@@ -20,7 +20,7 @@
 	uint8_t pixelFilter, filterModel;
 	uint16_t quantizeValue;
 	int32_t maxSampleLength;
-	uint32_t soundFrequency, soundBufferSize, audioInputFrequency, reservedSampleOffset;
+	uint32_t soundFrequency, soundBufferSize, audioInputFrequency, mod2WavOutputFreq, reservedSampleOffset;
 } config_t;
 
 extern config_t config; // pt2_config.c
--- a/src/pt2_diskop.c
+++ b/src/pt2_diskop.c
@@ -23,19 +23,16 @@
 #include <sys/stat.h>
 #include <time.h>
 #include <limits.h>
-#include "pt2_header.h"
 #include "pt2_textout.h"
 #include "pt2_diskop.h"
 #include "pt2_tables.h"
 #include "pt2_module_loader.h"
-#include "pt2_audio.h"
-#include "pt2_sampler.h"
 #include "pt2_config.h"
-#include "pt2_helpers.h"
-#include "pt2_keyboard.h"
 #include "pt2_visuals.h"
 #include "pt2_sample_loader.h"
 #include "pt2_bmp.h"
+#include "pt2_askbox.h"
+#include "pt2_replayer.h"
 
 typedef struct fileEntry_t
 {
@@ -63,7 +60,6 @@
 #endif
 
 static char fileNameBuffer[PATH_MAX + 1];
-static uint32_t oldFileEntryRow;
 static UNICHAR pathTmp[PATH_MAX + 2];
 static fileEntry_t *diskOpEntry;
 
@@ -79,9 +75,7 @@
 
 static fileEntry_t *bufferCreateEmptyDir(void) // special case: creates a dir entry with a ".." directory
 {
-	fileEntry_t *dirEntry;
-
-	dirEntry = (fileEntry_t *)malloc(sizeof (fileEntry_t));
+	fileEntry_t *dirEntry = (fileEntry_t *)malloc(sizeof (fileEntry_t));
 	if (dirEntry == NULL)
 		return NULL;
 
@@ -283,7 +277,7 @@
 
 void diskOpShowSelectText(void)
 {
-	if (!ui.diskOpScreenShown || ui.pointerMode == POINTER_MODE_MSG1 || editor.errorMsgActive)
+	if (ui.pointerMode == POINTER_MODE_MSG1 || editor.errorMsgActive)
 		return;
 
 	if (diskop.mode == DISKOP_MODE_MOD)
@@ -340,11 +334,9 @@
 
 char *diskOpGetAnsiEntry(int32_t fileIndex)
 {
-	UNICHAR *filenameU;
-
 	if (diskOpEntry != NULL && !diskOpEntryIsEmpty(fileIndex))
 	{
-		filenameU = diskOpEntry[diskop.scrollOffset+fileIndex].nameU;
+		UNICHAR *filenameU = diskOpEntry[diskop.scrollOffset+fileIndex].nameU;
 		if (filenameU != NULL)
 		{
 			unicharToAnsi(fileNameBuffer, filenameU, PATH_MAX);
@@ -378,12 +370,11 @@
 	ui.updateDiskOpPathText = true;
 }
 
-bool changePathToHome(void)
+bool changePathToDesktop(void)
 {
 #ifdef _WIN32
 	UNICHAR pathU[PATH_MAX + 2];
-
-	if (SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, pathU) >= 0)
+	if (SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, pathU) >= 0)
 	{
 		if (UNICHAR_CHDIR(pathU) == 0)
 			return true;
@@ -391,11 +382,12 @@
 
 	return false;
 #else
-	char *homePath;
-
-	homePath = getenv("HOME");
+	char *homePath = getenv("HOME");
 	if (homePath != NULL && chdir(homePath) == 0)
+	{
+		chdir("Desktop"); // keep home dir in case we couldn't change the dir to desktop
 		return true;
+	}
 
 	return false;
 #endif
@@ -556,8 +548,7 @@
 
 static bool diskOpFillBuffer(void)
 {
-	uint8_t lastFindFileFlag;
-	fileEntry_t tmpBuffer, *newPtr;
+	fileEntry_t tmpBuffer;
 
 	diskop.scrollOffset = 0;
 
@@ -570,7 +561,7 @@
 	// fill disk op. buffer (type, size, path, file name, date changed)
 
 	// read first file
-	lastFindFileFlag = findFirst(&tmpBuffer);
+	uint8_t lastFindFileFlag = findFirst(&tmpBuffer);
 	if (lastFindFileFlag != LFF_DONE && lastFindFileFlag != LFF_SKIP)
 	{
 		diskOpEntry = (fileEntry_t *)malloc(sizeof (fileEntry_t) * (diskop.numEntries + 1));
@@ -592,7 +583,7 @@
 		lastFindFileFlag = findNext(&tmpBuffer);
 		if (lastFindFileFlag != LFF_DONE && lastFindFileFlag != LFF_SKIP)
 		{
-			newPtr = (fileEntry_t *)realloc(diskOpEntry, sizeof (fileEntry_t) * (diskop.numEntries + 1));
+			fileEntry_t *newPtr = (fileEntry_t *)realloc(diskOpEntry, sizeof (fileEntry_t) * (diskop.numEntries + 1));
 			if (newPtr == NULL)
 			{
 				findClose();
@@ -641,7 +632,6 @@
 static void printFileSize(fileEntry_t *entry, uint16_t x, uint16_t y)
 {
 	char tmpStr[7];
-	uint32_t fileSize, j;
 
 	if (entry->filesize == -1) // -1 means that the original filesize is above 2GB in our directory reader
 	{
@@ -649,7 +639,7 @@
 		return;
 	}
 
-	fileSize = (uint32_t)entry->filesize;
+	uint32_t fileSize = (uint32_t)entry->filesize;
 	if (fileSize <= 999999)
 	{
 		// bytes
@@ -669,12 +659,12 @@
 	}
 
 	// turn zeroes on the left side into spaces
-	for (j = 0; j < 7; j++)
+	for (int32_t i = 0; i < 7; i++)
 	{
-		if (tmpStr[j] != '0')
+		if (tmpStr[i] != '0')
 			break;
 
-		tmpStr[j] = ' ';
+		tmpStr[i] = ' ';
 	}
 
 	textOut(x, y, tmpStr, video.palette[PAL_QADSCP]);
@@ -685,8 +675,8 @@
 	if (entryLength > maxLength)
 	{
 		// shorten name and add ".." to end
-		for (int32_t j = 0; j < maxLength-2; j++)
-			charOut(x + (j * FONT_CHAR_W), y, entryName[j], video.palette[PAL_QADSCP]);
+		for (int32_t i = 0; i < maxLength-2; i++)
+			charOut(x + (i * FONT_CHAR_W), y, entryName[i], video.palette[PAL_QADSCP]);
 
 		textOut(x + ((maxLength - 2) * FONT_CHAR_W), y, "..", video.palette[PAL_QADSCP]);
 	}
@@ -699,11 +689,8 @@
 
 void diskOpRenderFileList(void)
 {
-	char *entryName;
 	uint8_t maxFilenameChars, maxDirNameChars;
-	uint16_t x, y, textXStart;
-	int32_t entryLength;
-	fileEntry_t *entry;
+	uint16_t textXStart;
 
 	if (config.hideDiskOpDates)
 	{
@@ -727,8 +714,8 @@
 	if (!diskop.cached)
 	{
 		diskop.fillThread = SDL_CreateThread(diskOpFillThreadFunc, NULL, NULL);
-		if (diskop.fillThread != NULL)
-			SDL_DetachThread(diskop.fillThread);
+		if (diskop.fillThread == NULL)
+			return;
 
 		diskop.cached = true;
 		return;
@@ -746,12 +733,12 @@
 		if (diskop.scrollOffset+i >= diskop.numEntries)
 			break;
 
-		entry = &diskOpEntry[diskop.scrollOffset+i];
-		entryName = diskOpGetAnsiEntry(i);
-		entryLength = (int32_t)strlen(entryName);
+		fileEntry_t *entry = &diskOpEntry[diskop.scrollOffset+i];
+		char *entryName = diskOpGetAnsiEntry(i);
+		int32_t entryLength = (int32_t)strlen(entryName);
 
-		x = textXStart;
-		y = (uint8_t)(35 + (i * (FONT_CHAR_H + 1)));
+		uint16_t x = textXStart;
+		uint16_t y = (uint8_t)(35 + (i * (FONT_CHAR_H + 1)));
 
 		if (!entry->isDir)
 		{
@@ -774,9 +761,6 @@
 
 void diskOpLoadFile(uint32_t fileEntryRow, bool songModifiedCheck)
 {
-	uint8_t oldMode, oldPlayMode;
-	UNICHAR *filePath;
-
 	// if we clicked on an empty space, return...
 	if (diskOpEntryIsEmpty(fileEntryRow))
 		return;
@@ -787,7 +771,7 @@
 	}
 	else
 	{
-		filePath = diskOpGetUnicodeEntry(fileEntryRow);
+		UNICHAR *filePath = diskOpGetUnicodeEntry(fileEntryRow);
 		if (filePath != NULL)
 		{
 			if (diskop.mode == DISKOP_MODE_MOD)
@@ -794,16 +778,15 @@
 			{
 				if (songModifiedCheck && song->modified)
 				{
-					oldFileEntryRow = fileEntryRow;
-					showSongUnsavedAskBox(ASK_DISCARD_SONG);
-					return;
+					if (!askBox(ASKBOX_YES_NO, "SONG IS UNSAVED !"))
+						return;
 				}
 
 				module_t *newSong = modLoad(filePath);
 				if (newSong != NULL)
 				{
-					oldMode = editor.currMode;
-					oldPlayMode = editor.playMode;
+					uint8_t oldMode = editor.currMode;
+					uint8_t oldPlayMode = editor.playMode;
 
 					modStop();
 					modFree();
@@ -865,11 +848,6 @@
 	}
 }
 
-void diskOpLoadFile2(void)
-{
-	diskOpLoadFile(oldFileEntryRow, false);
-}
-
 void renderDiskOpScreen(void)
 {
 	blit32(0, 0, 320, 99, diskOpScreenBMP);
@@ -883,9 +861,7 @@
 
 void updateDiskOp(void)
 {
-	char tmpChar;
-
-	if (!ui.diskOpScreenShown || ui.posEdScreenShown)
+	if (!ui.diskOpScreenShown || ui.posEdScreenShown || ui.askBoxShown)
 		return;
 
 	if (ui.updateDiskOpFileList)
@@ -930,7 +906,7 @@
 		// print disk op. path
 		for (int32_t i = 0; i < 26; i++)
 		{
-			tmpChar = editor.currPath[ui.diskOpPathTextOffset+i];
+			char tmpChar = editor.currPath[ui.diskOpPathTextOffset+i];
 			if (tmpChar == '\0')
 				tmpChar = '_';
 
--- a/src/pt2_diskop.h
+++ b/src/pt2_diskop.h
@@ -15,7 +15,6 @@
 void addSampleFileExt(char *fileName);
 void diskOpShowSelectText(void);
 void diskOpLoadFile(uint32_t fileEntryRow, bool songModifiedCheck);
-void diskOpLoadFile2(void);
 void handleEntryJumping(SDL_Keycode jumpToChar);
 bool diskOpEntryIsEmpty(int32_t fileIndex);
 bool diskOpEntryIsDir(int32_t fileIndex);
@@ -28,6 +27,6 @@
 void freeDiskOpMem(void);
 void freeDiskOpEntryMem(void);
 void setPathFromDiskOpMode(void);
-bool changePathToHome(void);
+bool changePathToDesktop(void);
 void renderDiskOpScreen(void);
 void updateDiskOp(void);
\ No newline at end of file
--- a/src/pt2_downsample2x.c
+++ b/src/pt2_downsample2x.c
@@ -9,7 +9,7 @@
 
 #include <stdint.h>
 #include <stdbool.h>
-#include <math.h> // round()
+#include <stdlib.h>
 #include "pt2_helpers.h" // ABS()
 
 // ----------------------------------------------------------
@@ -131,6 +131,7 @@
 
 	const double *input = buffer;
 	const uint32_t length = originalLength / 2;
+
 	for (uint32_t i = 0; i < length; i++, input += 2)
 		buffer[i] = decimate2x(input[0], input[1]);
 }
@@ -141,6 +142,7 @@
 
 	const float *input = buffer;
 	const uint32_t length = originalLength / 2;
+
 	for (uint32_t i = 0; i < length; i++, input += 2)
 		buffer[i] = (float)decimate2x(input[0], input[1]);
 }
@@ -189,7 +191,6 @@
 	}
 
 	free(dBuffer);
-
 	return true;
 }
 
@@ -235,7 +236,6 @@
 	}
 
 	free(dBuffer);
-
 	return true;
 }
 
@@ -281,7 +281,6 @@
 	}
 
 	free(dBuffer);
-
 	return true;
 }
 
@@ -327,6 +326,5 @@
 	}
 
 	free(dBuffer);
-
 	return true;
 }
--- a/src/pt2_edit.c
+++ b/src/pt2_edit.c
@@ -13,24 +13,20 @@
 #else
 #include <unistd.h>
 #endif
-#include "pt2_header.h"
 #include "pt2_helpers.h"
 #include "pt2_textout.h"
 #include "pt2_tables.h"
-#include "pt2_audio.h"
 #include "pt2_diskop.h"
-#include "pt2_mouse.h"
 #include "pt2_sampler.h"
 #include "pt2_visuals.h"
 #include "pt2_keyboard.h"
-#include "pt2_scopes.h"
-#include "pt2_structs.h"
 #include "pt2_config.h"
 #include "pt2_audio.h"
-#include "pt2_sync.h"
 #include "pt2_chordmaker.h"
+#include "pt2_edit.h"
+#include "pt2_replayer.h"
 
-const int8_t scancode2NoteLo[52] = // "USB usage page standard" order
+static const int8_t scancode2NoteLo[52] = // "USB usage page standard" order
 {
 	 7,  4,  3, 16, -1,  6,  8, 24,
 	10, -1, 13, 11,  9, 26, 28, 12,
@@ -41,7 +37,7 @@
 	-1, 12, 14, 16
 };
 
-const int8_t scancode2NoteHi[52] = // "USB usage page standard" order
+static const int8_t scancode2NoteHi[52] = // "USB usage page standard" order
 {
 	19, 16, 15, 28, -1, 18, 20, -2,
 	22, -1, 25, 23, 21, -2, -2, 24,
@@ -52,13 +48,6 @@
 	-1, 24, 26, 28
 };
 
-void setPattern(int16_t pattern); // pt2_replayer.c
-
-void jamAndPlaceSample(SDL_Scancode scancode,  bool normalMode);
-uint8_t quantizeCheck(uint8_t row);
-bool handleSpecialKeys(SDL_Scancode scancode);
-int8_t keyToNote(SDL_Scancode scancode);
-
 // used for re-rendering text object while editing it
 void updateTextObject(int16_t editObject)
 {
@@ -97,10 +86,8 @@
 void exitGetTextLine(bool updateValue)
 {
 	int8_t tmp8;
-	int16_t posEdPos, tmp16;
-	int32_t tmp32;
-	UNICHAR *pathU;
-	moduleSample_t *s;
+	int16_t tmp16;
+	int32_t tmp32;
 
 	SDL_StopTextInput();
 
@@ -107,7 +94,7 @@
 	// if user updated the disk op path text
 	if (ui.diskOpScreenShown && ui.editObject == PTB_DO_DATAPATH)
 	{
-		pathU = (UNICHAR *)calloc(PATH_MAX + 2, sizeof (UNICHAR));
+		UNICHAR *pathU = (UNICHAR *)calloc(PATH_MAX + 2, sizeof (UNICHAR));
 		if (pathU != NULL)
 		{
 #ifdef _WIN32
@@ -157,7 +144,7 @@
 	{
 		// set back GUI text pointers and update values (if requested)
 
-		s = &song->samples[editor.currSample];
+		moduleSample_t *s = &song->samples[editor.currSample];
 		switch (ui.editObject)
 		{
 			case PTB_SA_FIL_LP_CUTOFF:
@@ -333,7 +320,7 @@
 
 			case PTB_PE_PATT:
 			{
-				posEdPos = song->currOrder;
+				int16_t posEdPos = song->currOrder;
 				if (posEdPos > song->header.numOrders-1)
 					posEdPos = song->header.numOrders-1;
 
@@ -420,7 +407,7 @@
 					{
 						song->header.numOrders = tmp16;
 
-						posEdPos = song->currOrder;
+						int16_t posEdPos = song->currOrder;
 						if (posEdPos > song->header.numOrders-1)
 							posEdPos = song->header.numOrders-1;
 
@@ -559,7 +546,7 @@
 					{
 						turnOffVoices();
 						s->loopStart = tmp32;
-						mixerUpdateLoops();
+						updatePaulaLoops();
 
 						ui.updateCurrSampleRepeat = true;
 
@@ -604,7 +591,7 @@
 					{
 						turnOffVoices();
 						s->loopLength = tmp32;
-						mixerUpdateLoops();
+						updatePaulaLoops();
 
 						ui.updateCurrSampleReplen = true;
 						if (ui.editOpScreenShown && ui.editOpScreen == 3)
@@ -672,11 +659,147 @@
 	SDL_StartTextInput();
 }
 
-void handleEditKeys(SDL_Scancode scancode, bool normalMode)
+static uint8_t quantizeCheck(uint8_t row)
 {
-	int8_t key, hexKey, numberKey;
-	note_t *note;
+	assert(song != NULL);
+	if (song == NULL)
+		return row;
 
+	const uint8_t quantize = (uint8_t)config.quantizeValue;
+
+	editor.didQuantize = false;
+	if (editor.currMode == MODE_RECORD)
+	{
+		if (quantize == 0)
+		{
+			return row;
+		}
+		else if (quantize == 1)
+		{
+			if (song->tick > song->speed>>1)
+			{
+				row = (row + 1) & 0x3F;
+				editor.didQuantize = true;
+			}
+		}
+		else
+		{
+			uint8_t tempRow = ((((quantize >> 1) + row) & 63) / quantize) * quantize;
+			if (tempRow > row)
+				editor.didQuantize = true;
+
+			return tempRow;
+		}
+	}
+
+	return row;
+}
+
+static void jamAndPlaceSample(SDL_Scancode scancode, bool normalMode)
+{
+	uint8_t chNum = cursor.channel;
+	assert(chNum < PAULA_VOICES);
+
+	moduleChannel_t *ch = &song->channels[chNum];
+	note_t *note = &song->patterns[song->currPattern][(quantizeCheck(song->currRow) * PAULA_VOICES) + chNum];
+
+	int8_t noteVal = normalMode ? keyToNote(scancode) : pNoteTable[editor.currSample];
+	if (noteVal >= 0)
+	{
+		moduleSample_t *s = &song->samples[editor.currSample];
+
+		int16_t tempPeriod  = periodTable[((s->fineTune & 0xF) * 37) + noteVal];
+		uint16_t cleanPeriod = periodTable[noteVal];
+
+		editor.currPlayNote = noteVal;
+
+		// play current sample
+
+		// don't play sample if we quantized to another row (will be played in modplayer instead)
+		if (editor.currMode != MODE_RECORD || !editor.didQuantize)
+		{
+			lockAudio();
+
+			ch->n_samplenum = editor.currSample;
+			ch->n_volume = s->volume;
+			ch->n_period = tempPeriod;
+			ch->n_start = &song->sampleData[s->offset];
+			ch->n_length = (uint16_t)((s->loopStart > 0) ? (s->loopStart + s->loopLength) >> 1 : s->length >> 1);
+			ch->n_loopstart = &song->sampleData[s->offset + s->loopStart];
+			ch->n_replen = (uint16_t)(s->loopLength >> 1);
+
+			if (ch->n_length == 0)
+				ch->n_length = 1;
+
+			paulaSetVolume(chNum, ch->n_volume);
+			paulaSetPeriod(chNum, ch->n_period);
+			paulaSetData(chNum, ch->n_start);
+			paulaSetLength(chNum, ch->n_length);
+
+			if (!editor.muted[chNum])
+				paulaSetDMACON(0x8000 | ch->n_dmabit); // voice DMA on
+			else
+				paulaSetDMACON(ch->n_dmabit); // voice DMA off
+
+			// these take effect after the current DMA cycle is done
+			paulaSetData(chNum, ch->n_loopstart);
+			paulaSetLength(chNum, ch->n_replen);
+
+			unlockAudio();
+		}
+
+		// normalMode = normal keys, or else keypad keys (in jam mode)
+		if (normalMode || editor.pNoteFlag != 0)
+		{
+			if (normalMode || editor.pNoteFlag == 2)
+			{
+				// insert note and sample number
+				if (!ui.samplerScreenShown && (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD))
+				{
+					note->sample = editor.sampleZero ? 0 : (editor.currSample + 1);
+					note->period = cleanPeriod;
+
+					if (editor.autoInsFlag)
+					{
+						note->command = editor.effectMacros[editor.autoInsSlot] >> 8;
+						note->param = editor.effectMacros[editor.autoInsSlot] & 0xFF;
+					}
+
+					if (editor.currMode != MODE_RECORD)
+						modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 63);
+
+					updateWindowTitle(MOD_IS_MODIFIED);
+				}
+			}
+
+			if (editor.multiFlag)
+				gotoNextMulti();
+		}
+
+		updateSpectrumAnalyzer(s->volume, tempPeriod);
+	}
+	else if (noteVal == -2)
+	{
+		// delete note and sample if illegal note (= -2, -1 = ignore) key was entered
+
+		if (normalMode || editor.pNoteFlag == 2)
+		{
+			if (!ui.samplerScreenShown && (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD))
+			{
+				note->period = 0;
+				note->sample = 0;
+
+				if (editor.currMode != MODE_RECORD)
+					modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 63);
+
+				updateWindowTitle(MOD_IS_MODIFIED);
+			}
+		}
+	}
+}
+
+void handleEditKeys(SDL_Scancode scancode, bool normalMode)
+{
 	if (ui.editTextFlag)
 		return;
 
@@ -695,7 +818,7 @@
 		if (handleSpecialKeys(scancode))
 		{
 			if (editor.currMode != MODE_RECORD)
-				modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
+				modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 63);
 
 			return;
 		}
@@ -710,6 +833,8 @@
 
 		if (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD)
 		{
+			int8_t hexKey, numberKey;
+
 			if (scancode == SDL_SCANCODE_0)
 				numberKey = 0;
 			else if (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_9)
@@ -722,7 +847,7 @@
 			else
 				hexKey = -1;
 
-			key = -1;
+			int8_t key = -1;
 			if (numberKey != -1)
 			{
 				if (key == -1)
@@ -739,8 +864,7 @@
 				key += hexKey;
 			}
 
-			note = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
-
+			note_t *note = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 			switch (cursor.mode)
 			{
 				case CURSOR_SAMPLE1:
@@ -747,10 +871,10 @@
 				{
 					if (key != -1 && key < 2)
 					{
-						note->sample = (uint8_t)((note->sample % 0x10) | (key << 4));
+						note->sample = (uint8_t)((note->sample & 0x0F) | (key << 4));
 
 						if (editor.currMode != MODE_RECORD)
-							modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
+							modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 63);
 
 						updateWindowTitle(MOD_IS_MODIFIED);
 					}
@@ -761,10 +885,10 @@
 				{
 					if (key != -1 && key < 16)
 					{
-						note->sample = (uint8_t)((note->sample & 16) | key);
+						note->sample = (uint8_t)((note->sample & 0xF0) | key);
 
 						if (editor.currMode != MODE_RECORD)
-							modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
+							modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 63);
 
 						updateWindowTitle(MOD_IS_MODIFIED);
 					}
@@ -778,7 +902,7 @@
 						note->command = (uint8_t)key;
 
 						if (editor.currMode != MODE_RECORD)
-							modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
+							modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 63);
 
 						updateWindowTitle(MOD_IS_MODIFIED);
 					}
@@ -789,10 +913,10 @@
 				{
 					if (key != -1 && key < 16)
 					{
-						note->param = (uint8_t)((note->param % 0x10) | (key << 4));
+						note->param = (uint8_t)((note->param & 0x0F) | (key << 4));
 
 						if (editor.currMode != MODE_RECORD)
-							modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
+							modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 63);
 
 						updateWindowTitle(MOD_IS_MODIFIED);
 					}
@@ -806,7 +930,7 @@
 						note->param = (uint8_t)((note->param & 0xF0) | key);
 
 						if (editor.currMode != MODE_RECORD)
-							modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
+							modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 63);
 
 						updateWindowTitle(MOD_IS_MODIFIED);
 					}
@@ -823,7 +947,7 @@
 		{
 			if (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD)
 			{
-				note = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
+				note_t *note = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 
 				if (!keyb.leftAltPressed)
 				{
@@ -838,7 +962,7 @@
 				}
 
 				if (editor.currMode != MODE_RECORD)
-					modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
+					modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 63);
 
 				updateWindowTitle(MOD_IS_MODIFIED);
 			}
@@ -856,14 +980,12 @@
 
 bool handleSpecialKeys(SDL_Scancode scancode)
 {
-	note_t *patt, *note, *prevNote;
-
 	if (!keyb.leftAltPressed)
 		return false;
 
-	patt = song->patterns[song->currPattern];
-	note = &patt[(song->currRow * AMIGA_VOICES) + cursor.channel];
-	prevNote = &patt[(((song->currRow - 1) & 0x3F) * AMIGA_VOICES) + cursor.channel];
+	note_t *patt = song->patterns[song->currPattern];
+	note_t *note = &patt[(song->currRow * PAULA_VOICES) + cursor.channel];
+	note_t *prevNote = &patt[(((song->currRow - 1) & 63) * PAULA_VOICES) + cursor.channel];
 
 	if (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0)
 	{
@@ -910,7 +1032,7 @@
 
 void handleSampleJamming(SDL_Scancode scancode) // used for the sampling feature (in SAMPLER)
 {
-	const int32_t ch = cursor.channel;
+	const int32_t chNum = cursor.channel;
 
 	if (scancode == SDL_SCANCODE_NONUSBACKSLASH)
 	{
@@ -918,7 +1040,7 @@
 		return;
 	}
 
-	const int8_t noteVal = keyToNote(scancode);
+	int8_t noteVal = keyToNote(scancode);
 	if (noteVal < 0 || noteVal > 35)
 		return;
 
@@ -926,191 +1048,44 @@
 	if (s->length <= 1)
 		return;
 
-	lockAudio();
+	moduleChannel_t *ch = &song->channels[chNum];
 
-	song->channels[ch].n_samplenum = editor.currSample; // needed for sample playback/sampling line
+	int8_t *n_start = &song->sampleData[s->offset];
+	int8_t vol = 64;
+	uint16_t n_length = (uint16_t)(s->length >> 1);
+	uint16_t period = periodTable[((s->fineTune & 0xF) * 37) + noteVal];
 
-	const int8_t *n_start = &song->sampleData[s->offset];
-	const int8_t vol = 64;
-	const uint16_t n_length = (uint16_t)(s->length >> 1);
-	const uint16_t period = periodTable[((s->fineTune & 0xF) * 37) + noteVal];
+	lockAudio();
 
-	paulaSetVolume(ch, vol);
-	paulaSetPeriod(ch, period);
-	paulaSetData(ch, n_start);
-	paulaSetLength(ch, n_length);
+	ch->n_samplenum = editor.currSample; // needed for sample playback/sampling line
 
-	if (!editor.muted[ch])
-		paulaStartDMA(ch);
+	paulaSetVolume(chNum, vol);
+	paulaSetPeriod(chNum, period);
+	paulaSetData(chNum, n_start);
+	paulaSetLength(chNum, n_length);
+
+	if (!editor.muted[chNum])
+		paulaSetDMACON(0x8000 | ch->n_dmabit); // voice DMA on
 	else
-		paulaStopDMA(ch);
+		paulaSetDMACON(ch->n_dmabit); // voice DMA off
 
 	// these take effect after the current DMA cycle is done
-	paulaSetData(ch, NULL);
-	paulaSetLength(ch, 1);
+	paulaSetData(chNum, NULL); // NULL = reserved buffer (empty)
+	paulaSetLength(chNum, 1);
 
 	unlockAudio();
 }
 
-void jamAndPlaceSample(SDL_Scancode scancode, bool normalMode)
-{
-	int8_t noteVal;
-	uint8_t ch;
-	int16_t tempPeriod;
-	uint16_t cleanPeriod;
-	moduleChannel_t *chn;
-	moduleSample_t *s;
-	note_t *note;
-
-	ch = cursor.channel;
-	assert(ch < AMIGA_VOICES);
-
-	chn = &song->channels[ch];
-	note = &song->patterns[song->currPattern][(quantizeCheck(song->currRow) * AMIGA_VOICES) + ch];
-
-	noteVal = normalMode ? keyToNote(scancode) : pNoteTable[editor.currSample];
-	if (noteVal >= 0)
-	{
-		s = &song->samples[editor.currSample];
-
-		tempPeriod  = periodTable[((s->fineTune & 0xF) * 37) + noteVal];
-		cleanPeriod = periodTable[noteVal];
-
-		editor.currPlayNote = noteVal;
-
-		// play current sample
-
-		// don't play sample if we quantized to another row (will be played in modplayer instead)
-		if (editor.currMode != MODE_RECORD || !editor.didQuantize)
-		{
-			lockAudio();
-
-			chn->n_samplenum = editor.currSample;
-			chn->n_volume = s->volume;
-			chn->n_period = tempPeriod;
-			chn->n_start = &song->sampleData[s->offset];
-			chn->n_length = (uint16_t)((s->loopStart > 0) ? (s->loopStart + s->loopLength) >> 1 : s->length >> 1);
-			chn->n_loopstart = &song->sampleData[s->offset + s->loopStart];
-			chn->n_replen = (uint16_t)(s->loopLength >> 1);
-
-			if (chn->n_length == 0)
-				chn->n_length = 1;
-
-			paulaSetVolume(ch, chn->n_volume);
-			paulaSetPeriod(ch, chn->n_period);
-			paulaSetData(ch, chn->n_start);
-			paulaSetLength(ch, chn->n_length);
-
-			if (!editor.muted[ch])
-				paulaStartDMA(ch);
-			else
-				paulaStopDMA(ch);
-
-			// these take effect after the current DMA cycle is done
-			paulaSetData(ch, chn->n_loopstart);
-			paulaSetLength(ch, chn->n_replen);
-
-			unlockAudio();
-		}
-
-		// normalMode = normal keys, or else keypad keys (in jam mode)
-		if (normalMode || editor.pNoteFlag != 0)
-		{
-			if (normalMode || editor.pNoteFlag == 2)
-			{
-				// insert note and sample number
-				if (!ui.samplerScreenShown && (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD))
-				{
-					note->sample = editor.sampleZero ? 0 : (editor.currSample + 1);
-					note->period = cleanPeriod;
-
-					if (editor.autoInsFlag)
-					{
-						note->command = editor.effectMacros[editor.autoInsSlot] >> 8;
-						note->param = editor.effectMacros[editor.autoInsSlot] & 0xFF;
-					}
-
-					if (editor.currMode != MODE_RECORD)
-						modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
-
-					updateWindowTitle(MOD_IS_MODIFIED);
-				}
-			}
-
-			if (editor.multiFlag)
-				gotoNextMulti();
-		}
-
-		updateSpectrumAnalyzer(s->volume, tempPeriod);
-	}
-	else if (noteVal == -2)
-	{
-		// delete note and sample if illegal note (= -2, -1 = ignore) key was entered
-
-		if (normalMode || editor.pNoteFlag == 2)
-		{
-			if (!ui.samplerScreenShown && (editor.currMode == MODE_EDIT || editor.currMode == MODE_RECORD))
-			{
-				note->period = 0;
-				note->sample = 0;
-
-				if (editor.currMode != MODE_RECORD)
-					modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
-
-				updateWindowTitle(MOD_IS_MODIFIED);
-			}
-		}
-	}
-}
-
-uint8_t quantizeCheck(uint8_t row)
-{
-	assert(song != NULL);
-	if (song == NULL)
-		return row;
-
-	const uint8_t quantize = (uint8_t)config.quantizeValue;
-
-	editor.didQuantize = false;
-	if (editor.currMode == MODE_RECORD)
-	{
-		if (quantize == 0)
-		{
-			return row;
-		}
-		else if (quantize == 1)
-		{
-			if (song->tick > song->speed>>1)
-			{
-				row = (row + 1) & 0x3F;
-				editor.didQuantize = true;
-			}
-		}
-		else
-		{
-			uint8_t tempRow = ((((quantize >> 1) + row) & 0x3F) / quantize) * quantize;
-			if (tempRow > row)
-				editor.didQuantize = true;
-
-			return tempRow;
-		}
-	}
-
-	return row;
-}
-
 void saveUndo(void)
 {
-	memcpy(editor.undoBuffer, song->patterns[song->currPattern], sizeof (note_t) * (AMIGA_VOICES * MOD_ROWS));
+	memcpy(editor.undoBuffer, song->patterns[song->currPattern], sizeof (note_t) * (PAULA_VOICES * MOD_ROWS));
 }
 
 void undoLastChange(void)
 {
-	note_t data;
-
-	for (uint16_t i = 0; i < MOD_ROWS*AMIGA_VOICES; i++)
+	for (uint16_t i = 0; i < MOD_ROWS * PAULA_VOICES; i++)
 	{
-		data = editor.undoBuffer[i];
+		note_t data = editor.undoBuffer[i];
 		editor.undoBuffer[i] = song->patterns[song->currPattern][i];
 		song->patterns[song->currPattern][i] = data;
 	}
@@ -1121,11 +1096,6 @@
 
 void copySampleTrack(void)
 {
-	uint8_t i;
-	uint32_t tmpOffset;
-	note_t *noteSrc;
-	moduleSample_t *smpFrom, *smpTo;
-
 	if (editor.trackPattFlag == 2)
 	{
 		// copy from one sample slot to another
@@ -1137,13 +1107,13 @@
 			return;
 		}
 
-		smpTo = &song->samples[editor.sampleTo - 1];
-		smpFrom = &song->samples[editor.sampleFrom - 1];
+		moduleSample_t *smpTo = &song->samples[editor.sampleTo - 1];
+		moduleSample_t *smpFrom = &song->samples[editor.sampleFrom - 1];
 
 		turnOffVoices();
 
 		// copy
-		tmpOffset = smpTo->offset;
+		uint32_t tmpOffset = smpTo->offset;
 		*smpTo = *smpFrom;
 		smpTo->offset = tmpOffset;
 
@@ -1164,9 +1134,9 @@
 		// copy sample number in track/pattern
 		if (editor.trackPattFlag == 0)
 		{
-			for (i = 0; i < MOD_ROWS; i++)
+			for (int32_t i = 0; i < MOD_ROWS; i++)
 			{
-				noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 				if (noteSrc->sample == editor.sampleFrom)
 					noteSrc->sample = editor.sampleTo;
 			}
@@ -1173,11 +1143,11 @@
 		}
 		else
 		{
-			for (i = 0; i < AMIGA_VOICES; i++)
+			for (int32_t i = 0; i < PAULA_VOICES; i++)
 			{
-				for (uint8_t j = 0; j < MOD_ROWS; j++)
+				for (int32_t j = 0; j < MOD_ROWS; j++)
 				{
-					noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
+					note_t *noteSrc = &song->patterns[song->currPattern][(j * PAULA_VOICES) + i];
 					if (noteSrc->sample == editor.sampleFrom)
 						noteSrc->sample = editor.sampleTo;
 				}
@@ -1195,12 +1165,6 @@
 
 void exchSampleTrack(void)
 {
-	int8_t smp;
-	int32_t i;
-	uint32_t tmpOffset;
-	moduleSample_t *smpFrom, *smpTo, smpTmp;
-	note_t *noteSrc;
-
 	if (editor.trackPattFlag == 2)
 	{
 		// exchange sample slots
@@ -1212,18 +1176,18 @@
 			return;
 		}
 
-		smpTo = &song->samples[editor.sampleTo-1];
-		smpFrom = &song->samples[editor.sampleFrom-1];
+		moduleSample_t *smpTo = &song->samples[editor.sampleTo-1];
+		moduleSample_t *smpFrom = &song->samples[editor.sampleFrom-1];
 
 		turnOffVoices();
 
 		// swap offsets first so that the next swap will leave offsets intact
-		tmpOffset = smpFrom->offset;
+		uint32_t tmpOffset = smpFrom->offset;
 		smpFrom->offset = smpTo->offset;
 		smpTo->offset = tmpOffset;
 
 		// swap sample (now offsets are left as before)
-		smpTmp = *smpFrom;
+		moduleSample_t smpTmp = *smpFrom;
 		*smpFrom = *smpTo;
 		*smpTo = smpTmp;
 
@@ -1238,9 +1202,9 @@
 		smpTo->loopLengthDisp = &smpTo->loopLength;
 
 		// swap sample data
-		for (i = 0; i < config.maxSampleLength; i++)
+		for (int32_t i = 0; i < config.maxSampleLength; i++)
 		{
-			smp = song->sampleData[smpFrom->offset+i];
+			int8_t smp = song->sampleData[smpFrom->offset+i];
 			song->sampleData[smpFrom->offset+i] = song->sampleData[smpTo->offset+i];
 			song->sampleData[smpTo->offset+i] = smp;
 		}
@@ -1254,9 +1218,9 @@
 		// exchange sample number in track/pattern
 		if (editor.trackPattFlag == 0)
 		{
-			for (i = 0; i < MOD_ROWS; i++)
+			for (int32_t i = 0; i < MOD_ROWS; i++)
 			{
-				noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 
 				     if (noteSrc->sample == editor.sampleFrom) noteSrc->sample = editor.sampleTo;
 				else if (noteSrc->sample == editor.sampleTo) noteSrc->sample = editor.sampleFrom;
@@ -1264,11 +1228,11 @@
 		}
 		else
 		{
-			for (i = 0; i < AMIGA_VOICES; i++)
+			for (int32_t i = 0; i < PAULA_VOICES; i++)
 			{
-				for (uint8_t j = 0; j < MOD_ROWS; j++)
+				for (int32_t j = 0; j < MOD_ROWS; j++)
 				{
-					noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
+					note_t *noteSrc = &song->patterns[song->currPattern][(j * PAULA_VOICES) + i];
 
 					     if (noteSrc->sample == editor.sampleFrom) noteSrc->sample = editor.sampleTo;
 					else if (noteSrc->sample == editor.sampleTo) noteSrc->sample = editor.sampleFrom;
@@ -1287,15 +1251,13 @@
 
 void delSampleTrack(void)
 {
-	uint8_t i;
-	note_t *noteSrc;
-
 	saveUndo();
+
 	if (editor.trackPattFlag == 0)
 	{
-		for (i = 0; i < MOD_ROWS; i++)
+		for (int32_t i = 0; i < MOD_ROWS; i++)
 		{
-			noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+			note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 			if (noteSrc->sample == editor.currSample+1)
 			{
 				noteSrc->period = 0;
@@ -1307,11 +1269,11 @@
 	}
 	else
 	{
-		for (i = 0; i < AMIGA_VOICES; i++)
+		for (int32_t i = 0; i < PAULA_VOICES; i++)
 		{
-			for (uint8_t j = 0; j < MOD_ROWS; j++)
+			for (int32_t j = 0; j < MOD_ROWS; j++)
 			{
-				noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
+				note_t *noteSrc = &song->patterns[song->currPattern][(j * PAULA_VOICES) + i];
 				if (noteSrc->sample == editor.currSample+1)
 				{
 					noteSrc->period = 0;
@@ -1329,21 +1291,17 @@
 
 void trackNoteUp(bool sampleAllFlag, uint8_t from, uint8_t to)
 {
-	bool noteDeleted;
-	uint8_t j;
-	note_t *noteSrc;
-
 	if (from > to)
 	{
-		j = from;
+		uint8_t old = from;
 		from = to;
-		to = j;
+		to = old;
 	}
 
 	saveUndo();
-	for (uint8_t i = from; i <= to; i++)
+	for (int32_t i = from; i <= to; i++)
 	{
-		noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+		note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 
 		if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
 			continue;
@@ -1351,6 +1309,7 @@
 		if (noteSrc->period)
 		{
 			// period -> note
+			int32_t j;
 			for (j = 0; j < 36; j++)
 			{
 				if (noteSrc->period >= periodTable[j])
@@ -1357,7 +1316,7 @@
 					break;
 			}
 
-			noteDeleted = false;
+			bool noteDeleted = false;
 			if (++j > 35)
 			{
 				j = 35;
@@ -1382,21 +1341,17 @@
 
 void trackNoteDown(bool sampleAllFlag, uint8_t from, uint8_t to)
 {
-	bool noteDeleted;
-	int8_t j;
-	note_t *noteSrc;
-
 	if (from > to)
 	{
-		j = from;
+		uint8_t old = from;
 		from = to;
-		to = j;
+		to = old;
 	}
 
 	saveUndo();
-	for (uint8_t i = from; i <= to; i++)
+	for (int32_t i = from; i <= to; i++)
 	{
-		noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+		note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 
 		if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
 			continue;
@@ -1404,6 +1359,7 @@
 		if (noteSrc->period)
 		{
 			// period -> note
+			int32_t j;
 			for (j = 0; j < 36; j++)
 			{
 				if (noteSrc->period >= periodTable[j])
@@ -1410,7 +1366,7 @@
 					break;
 			}
 
-			noteDeleted = false;
+			bool noteDeleted = false;
 			if (--j < 0)
 			{
 				j = 0;
@@ -1435,23 +1391,19 @@
 
 void trackOctaUp(bool sampleAllFlag, uint8_t from, uint8_t to)
 {
-	bool noteDeleted, noteChanged;
-	uint8_t j;
-	note_t *noteSrc;
-
 	if (from > to)
 	{
-		j = from;
+		uint8_t old = from;
 		from = to;
-		to = j;
+		to = old;
 	}
 
-	noteChanged = false;
+	bool noteChanged = false;
 
 	saveUndo();
-	for (uint8_t i = from; i <= to; i++)
+	for (int32_t i = from; i <= to; i++)
 	{
-		noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+		note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 
 		if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
 			continue;
@@ -1461,6 +1413,7 @@
 			uint16_t oldPeriod = noteSrc->period;
 
 			// period -> note
+			int32_t j;
 			for (j = 0; j < 36; j++)
 			{
 				if (noteSrc->period >= periodTable[j])
@@ -1467,7 +1420,7 @@
 					break;
 			}
 
-			noteDeleted = false;
+			bool noteDeleted = false;
 			if (j+12 > 35 && config.transDel)
 			{
 				noteSrc->period = 0;
@@ -1496,21 +1449,17 @@
 
 void trackOctaDown(bool sampleAllFlag, uint8_t from, uint8_t to)
 {
-	bool noteDeleted;
-	int8_t j;
-	note_t *noteSrc;
-
 	if (from > to)
 	{
-		j = from;
+		uint8_t old = from;
 		from = to;
-		to = j;
+		to = old;
 	}
 
 	saveUndo();
-	for (uint8_t i = from; i <= to; i++)
+	for (int32_t i = from; i <= to; i++)
 	{
-		noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+		note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 
 		if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
 			continue;
@@ -1518,6 +1467,7 @@
 		if (noteSrc->period)
 		{
 			// period -> note
+			int32_t j;
 			for (j = 0; j < 36; j++)
 			{
 				if (noteSrc->period >= periodTable[j])
@@ -1524,7 +1474,7 @@
 					break;
 			}
 
-			noteDeleted = false;
+			bool noteDeleted = false;
 			if (j-12 < 0 && config.transDel)
 			{
 				noteSrc->period = 0;
@@ -1547,16 +1497,12 @@
 
 void pattNoteUp(bool sampleAllFlag)
 {
-	bool noteDeleted;
-	uint8_t k;
-	note_t *noteSrc;
-
 	saveUndo();
-	for (uint8_t i = 0; i < AMIGA_VOICES; i++)
+	for (int32_t i = 0; i < PAULA_VOICES; i++)
 	{
-		for (uint8_t j = 0; j < MOD_ROWS; j++)
+		for (int32_t j = 0; j < MOD_ROWS; j++)
 		{
-			noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
+			note_t *noteSrc = &song->patterns[song->currPattern][(j * PAULA_VOICES) + i];
 
 			if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
 				continue;
@@ -1564,6 +1510,7 @@
 			if (noteSrc->period)
 			{
 				// period -> note
+				int32_t k;
 				for (k = 0; k < 36; k++)
 				{
 					if (noteSrc->period >= periodTable[k])
@@ -1570,7 +1517,7 @@
 						break;
 				}
 
-				noteDeleted = false;
+				bool noteDeleted = false;
 				if (++k > 35)
 				{
 					k = 35;
@@ -1596,16 +1543,12 @@
 
 void pattNoteDown(bool sampleAllFlag)
 {
-	bool noteDeleted;
-	int8_t k;
-	note_t *noteSrc;
-
 	saveUndo();
-	for (uint8_t i = 0; i < AMIGA_VOICES; i++)
+	for (int32_t i = 0; i < PAULA_VOICES; i++)
 	{
-		for (uint8_t j = 0; j < MOD_ROWS; j++)
+		for (int32_t j = 0; j < MOD_ROWS; j++)
 		{
-			noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
+			note_t *noteSrc = &song->patterns[song->currPattern][(j * PAULA_VOICES) + i];
 
 			if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
 				continue;
@@ -1613,6 +1556,7 @@
 			if (noteSrc->period)
 			{
 				// period -> note
+				int32_t k;
 				for (k = 0; k < 36; k++)
 				{
 					if (noteSrc->period >= periodTable[k])
@@ -1619,7 +1563,7 @@
 						break;
 				}
 
-				noteDeleted = false;
+				bool noteDeleted = false;
 				if (--k < 0)
 				{
 					k = 0;
@@ -1645,16 +1589,12 @@
 
 void pattOctaUp(bool sampleAllFlag)
 {
-	bool noteDeleted;
-	uint8_t k;
-	note_t *noteSrc;
-
 	saveUndo();
-	for (uint8_t i = 0; i < AMIGA_VOICES; i++)
+	for (int32_t i = 0; i < PAULA_VOICES; i++)
 	{
-		for (uint8_t j = 0; j < MOD_ROWS; j++)
+		for (int32_t j = 0; j < MOD_ROWS; j++)
 		{
-			noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
+			note_t *noteSrc = &song->patterns[song->currPattern][(j * PAULA_VOICES) + i];
 
 			if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
 				continue;
@@ -1662,6 +1602,7 @@
 			if (noteSrc->period)
 			{
 				// period -> note
+				int32_t k;
 				for (k = 0; k < 36; k++)
 				{
 					if (noteSrc->period >= periodTable[k])
@@ -1668,7 +1609,7 @@
 						break;
 				}
 
-				noteDeleted = false;
+				bool noteDeleted = false;
 				if (k+12 > 35 && config.transDel)
 				{
 					noteSrc->period = 0;
@@ -1692,16 +1633,12 @@
 
 void pattOctaDown(bool sampleAllFlag)
 {
-	bool noteDeleted;
-	int8_t k;
-	note_t *noteSrc;
-
 	saveUndo();
-	for (uint8_t i = 0; i < AMIGA_VOICES; i++)
+	for (int32_t i = 0; i < PAULA_VOICES; i++)
 	{
-		for (uint8_t j = 0; j < MOD_ROWS; j++)
+		for (int32_t j = 0; j < MOD_ROWS; j++)
 		{
-			noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
+			note_t *noteSrc = &song->patterns[song->currPattern][(j * PAULA_VOICES) + i];
 
 			if (!sampleAllFlag && noteSrc->sample != editor.currSample+1)
 				continue;
@@ -1709,6 +1646,7 @@
 			if (noteSrc->period)
 			{
 				// period -> note
+				int32_t k;
 				for (k = 0; k < 36; k++)
 				{
 					if (noteSrc->period >= periodTable[k])
@@ -1715,7 +1653,7 @@
 						break;
 				}
 
-				noteDeleted = false;
+				bool noteDeleted = false;
 				if (k-12 < 0 && config.transDel)
 				{
 					noteSrc->period = 0;
@@ -1740,12 +1678,11 @@
 int8_t keyToNote(SDL_Scancode scancode)
 {
 	int8_t note;
-	int32_t lookUpKey;
 
 	if (scancode < SDL_SCANCODE_B || scancode > SDL_SCANCODE_SLASH)
 		return -1; // not a note key
 
-	lookUpKey = (int32_t)scancode - SDL_SCANCODE_B;
+	int32_t lookUpKey = (int32_t)scancode - SDL_SCANCODE_B;
 	if (lookUpKey < 0 || lookUpKey >= 52)
 		return -1; // just in case
 
--- a/src/pt2_edit.h
+++ b/src/pt2_edit.h
@@ -21,8 +21,7 @@
 void getTextLine(int16_t editObject);
 void getNumLine(uint8_t type, int16_t editObject);
 void handleEditKeys(SDL_Scancode scancode, bool normalMode);
-uint8_t handleSpecialKeys(SDL_Scancode scancode);
+bool handleSpecialKeys(SDL_Scancode scancode);
 int8_t keyToNote(SDL_Scancode scancode);
 void updateTextObject(int16_t editObject);
-
 void handleSampleJamming(SDL_Scancode scancode);
--- a/src/pt2_header.h
+++ b/src/pt2_header.h
@@ -14,7 +14,7 @@
 #include "pt2_unicode.h"
 #include "pt2_palette.h"
 
-#define PROG_VER_STR "1.51"
+#define PROG_VER_STR "1.52"
 
 #ifdef _WIN32
 #define DIR_DELIMITER '\\'
@@ -31,6 +31,14 @@
 #define SCREEN_W 320
 #define SCREEN_H 255
 
+// main crystal oscillator for PAL Amiga systems
+#define AMIGA_PAL_XTAL_HZ 28375160
+#define AMIGA_PAL_CCK_HZ (AMIGA_PAL_XTAL_HZ/8.0)
+#define CIA_PAL_CLK (AMIGA_PAL_CCK_HZ / 5.0)
+
+// nominal framerate in normal PAL videomodes (~49.92Hz)
+#define AMIGA_PAL_VBLANK_HZ (AMIGA_PAL_CCK_HZ / (double)(313*227))
+
 /* "60Hz" ranges everywhere from 59..61Hz depending on the monitor, so with
 ** no vsync we will get stuttering because the rate is not perfect...
 */
@@ -50,7 +58,6 @@
 #define MOD_ORDERS 128
 #define MAX_PATTERNS 100
 
-#define AMIGA_VOICES 4
 #define SCOPE_WIDTH 40
 #define SCOPE_HEIGHT 33
 #define SPECTRUM_BAR_NUM 23
@@ -59,22 +66,6 @@
 
 #define POSED_LIST_SIZE 12
 
-// main crystal oscillator for PAL Amiga systems
-#define AMIGA_PAL_XTAL_HZ 28375160
-
-#define AMIGA_PAL_CCK_HZ (AMIGA_PAL_XTAL_HZ/8.0)
-
-// nominal framerate in normal PAL videomodes (~49.92Hz)
-#define AMIGA_PAL_VBLANK_HZ (AMIGA_PAL_CCK_HZ / (double)(313*227))
-
-#define PAULA_PAL_CLK AMIGA_PAL_CCK_HZ
-#define CIA_PAL_CLK (AMIGA_PAL_CCK_HZ / 5.0)
-
-#define PAL_PAULA_MIN_SAFE_PERIOD 124
-#define PAL_PAULA_MAX_SAFE_HZ (PAULA_PAL_CLK / (double)PAL_PAULA_MIN_SAFE_PERIOD)
-
-#define FILTERS_BASE_FREQ (PAULA_PAL_CLK / 214.0)
-
 // Amount of video frames. 14 (PT on Amiga) -> 17 (converted from 49.92Hz to 60Hz)
 #define KEYB_REPEAT_DELAY 17
 
@@ -181,28 +172,6 @@
 	DISKOP_SMP_IFF = 1,
 	DISKOP_SMP_RAW = 2,
 
-	ASK_QUIT = 0,
-	ASK_SAVE_MODULE = 1,
-	ASK_SAVE_SONG = 2,
-	ASK_SAVE_SAMPLE = 3,
-	ASK_MOD2WAV = 4,
-	ASK_MOD2WAV_OVERWRITE = 5,
-	ASK_SAVEMOD_OVERWRITE = 6,
-	ASK_SAVESMP_OVERWRITE = 7,
-	ASK_LOAD_DOWNSAMPLE = 8,
-	ASK_RESAMPLE = 9,
-	ASK_KILL_SAMPLE = 10,
-	ASK_UPSAMPLE = 11,
-	ASK_DOWNSAMPLE = 12,
-	ASK_FILTER_ALL_SAMPLES = 13,
-	ASK_BOOST_ALL_SAMPLES = 14,
-	ASK_MAKE_CHORD = 15,
-	ASK_SAVE_ALL_SAMPLES = 16,
-	ASK_PAT2SMP = 17,
-	ASK_RESTORE_SAMPLE = 18,
-	ASK_DISCARD_SONG = 19,
-	ASK_DISCARD_SONG_DRAGNDROP = 20,
-
 	TEMPO_MODE_CIA = 0,
 	TEMPO_MODE_VBLANK = 1,
 
@@ -210,27 +179,3 @@
 	TEXT_EDIT_DECIMAL = 1,
 	TEXT_EDIT_HEX = 2
 };
-
-// pt2_replayer.c
-int8_t *allocMemForAllSamples(void);
-void setReplayerPosToTrackerPos(void);
-// -------------------------
-
-void restartSong(void);
-void resetSong(void);
-void incPatt(void);
-void decPatt(void);
-void modSetPos(int16_t order, int16_t row);
-void modStop(void);
-void doStopIt(bool resetPlayMode);
-void playPattern(int8_t startRow);
-void modPlay(int16_t patt, int16_t order, int8_t row);
-void modSetSpeed(int32_t speed);
-void modSetTempo(int32_t bpm, bool doLockAudio);
-void modFree(void);
-bool setupAudio(void);
-void audioClose(void);
-void clearSong(void);
-void clearSamples(void);
-void clearAll(void);
-void modSetPattern(uint8_t pattern);
--- a/src/pt2_helpers.c
+++ b/src/pt2_helpers.c
@@ -9,15 +9,6 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <ctype.h> // toupper()
-#ifndef _WIN32
-#include <unistd.h>
-#else
-#define WIN32_MEAN_AND_LEAN
-#include <windows.h>
-#endif
-#include "pt2_helpers.h"
-#include "pt2_header.h"
-#include "pt2_tables.h"
 #include "pt2_structs.h"
 #include "pt2_config.h"
 
@@ -54,7 +45,7 @@
 	if (name == NULL)
 		return true;
 
-	for (uint8_t i = 0; i < 22; i++)
+	for (int32_t i = 0; i < 22; i++)
 	{
 		if (name[i] != '\0')
 			return false;
@@ -68,7 +59,7 @@
 	if (name == NULL)
 		return true;
 
-	for (uint8_t i = 0; i < 20; i++)
+	for (int32_t i = 0; i < 20; i++)
 	{
 		if (name[i] != '\0')
 			return false;
@@ -79,8 +70,12 @@
 
 void updateWindowTitle(bool modified)
 {
-	char titleTemp[128];
+	char editStr[32], titleTemp[256];
 
+	editStr[0] = '\0';
+	if (editor.currMode == MODE_EDIT)
+		strcpy(editStr, "[EDITING] ");
+
 	if (modified)
 		song->modified = true;
 	else
@@ -91,16 +86,20 @@
 		if (modified)
 		{
 			if (config.modDot)
-				sprintf(titleTemp, "ProTracker 2 clone v%s - \"mod.%s\" (unsaved)", PROG_VER_STR, song->header.name);
+				sprintf(titleTemp, "ProTracker 2 clone v%s %s- \"mod.%s\" (unsaved)",
+					PROG_VER_STR, editStr, song->header.name);
 			else
-				sprintf(titleTemp, "ProTracker 2 clone v%s - \"%s.mod\" (unsaved)", PROG_VER_STR, song->header.name);
+				sprintf(titleTemp, "ProTracker 2 clone v%s %s- \"%s.mod\" (unsaved)",
+					PROG_VER_STR, editStr, song->header.name);
 		}
 		else
 		{
 			if (config.modDot)
-				sprintf(titleTemp, "ProTracker 2 clone v%s - \"mod.%s\"", PROG_VER_STR, song->header.name);
+				sprintf(titleTemp, "ProTracker 2 clone v%s %s- \"mod.%s\"",
+					PROG_VER_STR, editStr, song->header.name);
 			else
-				sprintf(titleTemp, "ProTracker 2 clone v%s - \"%s.mod\"", PROG_VER_STR, song->header.name);
+				sprintf(titleTemp, "ProTracker 2 clone v%s %s- \"%s.mod\"",
+					PROG_VER_STR, editStr, song->header.name);
 		}
 	}
 	else
@@ -108,16 +107,20 @@
 		if (modified)
 		{
 			if (config.modDot)
-				sprintf(titleTemp, "ProTracker 2 clone v%s - \"mod.untitled\" (unsaved)", PROG_VER_STR);
+				sprintf(titleTemp, "ProTracker 2 clone v%s %s- \"mod.untitled\" (unsaved)",
+					PROG_VER_STR, editStr);
 			else
-				sprintf(titleTemp, "ProTracker 2 clone v%s - \"untitled.mod\" (unsaved)", PROG_VER_STR);
+				sprintf(titleTemp, "ProTracker 2 clone v%s %s- \"untitled.mod\" (unsaved)",
+					PROG_VER_STR, editStr);
 		}
 		else
 		{
 			if (config.modDot)
-				sprintf(titleTemp, "ProTracker 2 clone v%s - \"mod.untitled\"", PROG_VER_STR);
+				sprintf(titleTemp, "ProTracker 2 clone v%s %s- \"mod.untitled\"",
+					PROG_VER_STR, editStr);
 			else
-				sprintf(titleTemp, "ProTracker 2 clone v%s - \"untitled.mod\"", PROG_VER_STR);
+				sprintf(titleTemp, "ProTracker 2 clone v%s %s- \"untitled.mod\"",
+					PROG_VER_STR, editStr);
 		}
 	}
 
--- a/src/pt2_helpers.h
+++ b/src/pt2_helpers.h
@@ -2,8 +2,6 @@
 
 #include <stdint.h>
 #include <stdbool.h>
-#include <math.h>
-#include "pt2_header.h"
 
 // fast 32-bit -> 16-bit clamp
 #define CLAMP16(i) if ((int16_t)(i) != i) i = 0x7FFF ^ (i >> 31)
@@ -10,9 +8,6 @@
 
 // fast 16-bit -> 8-bit clamp
 #define CLAMP8(i) if ((int8_t)(i) != i) i = 0x7F ^ (i >> 15)
-
-#define ALIGN_PTR(p, x) (((uintptr_t)(p) + ((x)-1)) & ~((x)-1))
-#define MALLOC_PAD(size, pad) (malloc((size) + (pad)))
 
 #define SWAP16(value) \
 ( \
--- a/src/pt2_hpc.c
+++ b/src/pt2_hpc.c
@@ -1,6 +1,4 @@
-/*
-** Hardware Performance Counter delay routines
-*/
+// Hardware Performance Counter delay routines, by 8bitbubsy
 
 #ifdef _WIN32
 #define WIN32_MEAN_AND_LEAN
@@ -13,6 +11,7 @@
 #include <stdbool.h>
 #include "pt2_hpc.h"
 
+// more bits than this makes little sense (double -> uint64_t precision)
 #define FRAC_BITS 53
 #define FRAC_SCALE (1ULL << FRAC_BITS)
 #define FRAC_MASK (FRAC_SCALE-1)
@@ -103,7 +102,7 @@
 	{
 		uint64_t timeLeft64 = hpc->endTime64Int - currTime64;
 
-		// convert to int32_t for fast SSE2 SIMD usage lateron
+		// limit (and cast to) int32_t for fast SSE2 SIMD usage
 		if (timeLeft64 > INT32_MAX)
 			timeLeft64 = INT32_MAX;
 
--- a/src/pt2_hpc.h
+++ b/src/pt2_hpc.h
@@ -15,9 +15,9 @@
 	uint64_t endTime64Int, endTime64Frac;
 } hpc_t;
 
-extern hpcFreq_t hpcFreq;
-
 void hpc_Init(void);
 void hpc_SetDurationInHz(hpc_t *hpc, double dHz);
 void hpc_ResetEndTime(hpc_t *hpc);
 void hpc_Wait(hpc_t *hpc);
+
+extern hpcFreq_t hpcFreq;
--- a/src/pt2_keyboard.c
+++ b/src/pt2_keyboard.c
@@ -13,7 +13,6 @@
 #include <unistd.h>
 #endif
 #include "pt2_textout.h"
-#include "pt2_header.h"
 #include "pt2_helpers.h"
 #include "pt2_visuals.h"
 #include "pt2_diskop.h"
@@ -20,15 +19,15 @@
 #include "pt2_edit.h"
 #include "pt2_sampler.h"
 #include "pt2_audio.h"
-#include "pt2_keyboard.h"
+#include "pt2_amigafilters.h"
 #include "pt2_tables.h"
-#include "pt2_module_loader.h"
 #include "pt2_module_saver.h"
-#include "pt2_mouse.h"
-#include "pt2_unicode.h"
+#include "pt2_sample_saver.h"
 #include "pt2_config.h"
 #include "pt2_sampling.h"
 #include "pt2_chordmaker.h"
+#include "pt2_askbox.h"
+#include "pt2_replayer.h"
 
 #if defined _WIN32 && !defined _DEBUG
 extern bool windowsKeyIsDown;
@@ -35,17 +34,14 @@
 extern HHOOK g_hKeyboardHook;
 #endif
 
-void movePatCurPrevCh(void);
-void movePatCurNextCh(void);
-void movePatCurRight(void);
-void movePatCurLeft(void);
+static bool handleGeneralModes(SDL_Scancode scancode);
+static void movePatCurPrevCh(void);
+static void movePatCurNextCh(void);
+static void movePatCurRight(void);
+static void movePatCurLeft(void);
 
-static bool handleGeneralModes(SDL_Keycode keycode, SDL_Scancode scancode);
 bool handleTextEditMode(SDL_Scancode scancode);
 
-void sampleUpButton(void); // pt2_mouse.c
-void sampleDownButton(void); // pt2_mouse.c
-
 void gotoNextMulti(void)
 {
 	cursor.channel = (editor.multiModeNext[cursor.channel] - 1) & 3;
@@ -275,7 +271,7 @@
 }
 // --------------------------------
 
-void keyUpHandler(SDL_Scancode scancode, SDL_Keycode keycode)
+void keyUpHandler(SDL_Scancode scancode)
 {
 	if (scancode == SDL_SCANCODE_KP_PLUS)
 		keyb.keypadEnterPressed = false;
@@ -308,8 +304,6 @@
 		}
 		break;
 	}
-
-	(void)keycode;
 }
 
 static void incMulti(uint8_t slot)
@@ -329,12 +323,6 @@
 
 void keyDownHandler(SDL_Scancode scancode, SDL_Keycode keycode)
 {
-	uint8_t blockFrom, blockTo;
-	int16_t i, j;
-	note_t *patt, *noteSrc, *noteDst, noteTmp;
-	moduleSample_t *s;
-	moduleChannel_t *ch;
-
 	if (scancode == SDL_SCANCODE_CAPSLOCK)
 	{
 		editor.repeatKeyFlag ^= 1;
@@ -415,7 +403,7 @@
 
 	// XXX: This really needs some refactoring, it's messy and not logical
 
-	if (!handleGeneralModes(keycode, scancode)) return;
+	if (!handleGeneralModes(scancode)) return;
 	if (!handleTextEditMode(scancode)) return;
 	if (ui.samplerVolBoxShown || ui.samplingBoxShown) return;
 
@@ -452,7 +440,7 @@
 			if (keyb.leftAltPressed)
 			{
 				if (handleSpecialKeys(scancode) && editor.currMode != MODE_RECORD)
-					modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 0x3F);
+					modSetPos(DONT_SET_ORDER, (song->currRow + editor.editMoveAdd) & 63);
 			}
 			else
 			{
@@ -483,7 +471,7 @@
 #endif
 		{
 			// right Amiga key on Amiga keyb
-			if (!ui.askScreenShown)
+			if (!ui.askBoxShown)
 			{
 				editor.playMode = PLAY_MODE_NORMAL;
 				modPlay(DONT_SET_PATTERN, song->currOrder, DONT_SET_ROW);
@@ -501,7 +489,7 @@
 #endif
 		{
 			// right alt on Amiga keyb
-			if (!ui.askScreenShown)
+			if (!ui.askBoxShown)
 			{
 				editor.playMode = PLAY_MODE_PATTERN;
 				modPlay(song->currPattern, DONT_SET_ORDER, DONT_SET_ROW);
@@ -515,7 +503,7 @@
 		case SDL_SCANCODE_RSHIFT:
 		{
 			// right shift on Amiga keyb
-			if (!ui.samplerScreenShown && !ui.askScreenShown)
+			if (!ui.samplerScreenShown && !ui.askBoxShown)
 			{
 				editor.playMode = PLAY_MODE_PATTERN;
 				modPlay(song->currPattern, DONT_SET_ORDER, DONT_SET_ROW);
@@ -549,13 +537,11 @@
 			}
 			else
 			{
-				ui.askScreenShown = true;
-				ui.askScreenType = ASK_QUIT;
-
-				pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-				setStatusMessage("REALLY QUIT ?", NO_CARRY);
-				renderAskDialog();
-				return;
+				if (askBox(ASKBOX_YES_NO, "REALLY QUIT ?"))
+				{
+					ui.throwExit = true;
+					return;
+				}
 			}
 
 			pointerSetPreviousMode();
@@ -737,7 +723,7 @@
 			}
 			else
 			{
-				toggleFilterModel();
+				toggleAmigaFilterModel();
 			}
 		}
 		break;
@@ -744,103 +730,94 @@
 
 		case SDL_SCANCODE_RETURN:
 		{
-			if (ui.askScreenShown)
+			if (keyb.shiftPressed || keyb.leftAltPressed || keyb.leftCtrlPressed)
 			{
-				ui.answerNo = false;
-				ui.answerYes = true;
-				ui.askScreenShown = false;
-
-				handleAskYes();
-			}
-			else
-			{
-				if (keyb.shiftPressed || keyb.leftAltPressed || keyb.leftCtrlPressed)
+				saveUndo();
+				if (keyb.leftAltPressed && !keyb.leftCtrlPressed)
 				{
-					saveUndo();
-					if (keyb.leftAltPressed && !keyb.leftCtrlPressed)
+					if (song->currRow < 63)
 					{
-						if (song->currRow < 63)
+						for (int32_t i = 0; i < PAULA_VOICES; i++)
 						{
-							for (i = 0; i < AMIGA_VOICES; i++)
+							int32_t j;
+							for (j = 62; j >= song->currRow; j--)
 							{
-								for (j = 62; j >= song->currRow; j--)
-								{
-									noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + i];
-									song->patterns[song->currPattern][((j + 1) * AMIGA_VOICES) + i] = *noteSrc;
-								}
-
-								noteDst = &song->patterns[song->currPattern][((j + 1) * AMIGA_VOICES) + i];
-
-								noteDst->period = 0;
-								noteDst->sample = 0;
-								noteDst->command = 0;
-								noteDst->param = 0;
+								note_t *noteSrc = &song->patterns[song->currPattern][(j * PAULA_VOICES) + i];
+								song->patterns[song->currPattern][((j + 1) * PAULA_VOICES) + i] = *noteSrc;
 							}
 
-							song->currRow++;
+							note_t *noteDst = &song->patterns[song->currPattern][((j + 1) * PAULA_VOICES) + i];
 
-							updateWindowTitle(MOD_IS_MODIFIED);
-							ui.updatePatternData = true;
+							noteDst->period = 0;
+							noteDst->sample = 0;
+							noteDst->command = 0;
+							noteDst->param = 0;
 						}
+
+						song->currRow++;
+
+						updateWindowTitle(MOD_IS_MODIFIED);
+						ui.updatePatternData = true;
 					}
-					else
+				}
+				else
+				{
+					if (song->currRow < 63)
 					{
-						if (song->currRow < 63)
+						int32_t i;
+						for (i = 62; i >= song->currRow; i--)
 						{
-							for (i = 62; i >= song->currRow; i--)
-							{
-								noteSrc = &song->patterns[song->currPattern][((i + 0) * AMIGA_VOICES) + cursor.channel];
-								noteDst = &song->patterns[song->currPattern][((i + 1) * AMIGA_VOICES) + cursor.channel];
+							note_t *noteSrc = &song->patterns[song->currPattern][((i + 0) * PAULA_VOICES) + cursor.channel];
+							note_t *noteDst = &song->patterns[song->currPattern][((i + 1) * PAULA_VOICES) + cursor.channel];
 
-								if (keyb.leftCtrlPressed)
-								{
-									noteDst->command = noteSrc->command;
-									noteDst->param = noteSrc->param;
-								}
-								else
-								{
-									*noteDst = *noteSrc;
-								}
+							if (keyb.leftCtrlPressed)
+							{
+								noteDst->command = noteSrc->command;
+								noteDst->param = noteSrc->param;
 							}
-
-							noteDst = &song->patterns[song->currPattern][((i + 1) * AMIGA_VOICES) + cursor.channel];
-
-							if (!keyb.leftCtrlPressed)
+							else
 							{
-								noteDst->period = 0;
-								noteDst->sample = 0;
+								*noteDst = *noteSrc;
 							}
+						}
 
-							noteDst->command = 0;
-							noteDst->param = 0;
+						note_t *noteDst = &song->patterns[song->currPattern][((i + 1) * PAULA_VOICES) + cursor.channel];
 
-							song->currRow++;
-
-							updateWindowTitle(MOD_IS_MODIFIED);
-							ui.updatePatternData = true;
+						if (!keyb.leftCtrlPressed)
+						{
+							noteDst->period = 0;
+							noteDst->sample = 0;
 						}
+
+						noteDst->command = 0;
+						noteDst->param = 0;
+
+						song->currRow++;
+
+						updateWindowTitle(MOD_IS_MODIFIED);
+						ui.updatePatternData = true;
 					}
 				}
-				else
-				{
-					editor.stepPlayEnabled = true;
-					editor.stepPlayBackwards = false;
+			}
+			else
+			{
+				editor.stepPlayEnabled = true;
+				editor.stepPlayBackwards = false;
 
-					editor.stepPlayLastMode = editor.currMode;
+				editor.stepPlayLastMode = editor.currMode;
 
-					if (config.keepEditModeAfterStepPlay && editor.stepPlayLastMode == MODE_EDIT)
-						doStopIt(false);
-					else
-						doStopIt(true);
+				if (config.keepEditModeAfterStepPlay && editor.stepPlayLastMode == MODE_EDIT)
+					doStopIt(false);
+				else
+					doStopIt(true);
 
-					playPattern(song->currRow);
+				playPattern(song->currRow);
 
-					if (config.keepEditModeAfterStepPlay && editor.stepPlayLastMode == MODE_EDIT)
-					{
-						pointerSetMode(POINTER_MODE_EDIT, DO_CARRY);
-						editor.playMode = PLAY_MODE_NORMAL;
-						editor.currMode = MODE_EDIT;
-					}
+				if (config.keepEditModeAfterStepPlay && editor.stepPlayLastMode == MODE_EDIT)
+				{
+					pointerSetMode(POINTER_MODE_EDIT, DO_CARRY);
+					editor.playMode = PLAY_MODE_NORMAL;
+					editor.currMode = MODE_EDIT;
 				}
 			}
 		}
@@ -895,10 +872,10 @@
 					// cut channel and put in buffer
 					saveUndo();
 
-					noteDst = editor.trackBuffer;
-					for (i = 0; i < MOD_ROWS; i++)
+					note_t *noteDst = editor.trackBuffer;
+					for (int32_t i = 0; i < MOD_ROWS; i++)
 					{
-						noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+						note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 						*noteDst++ = *noteSrc;
 
 						noteSrc->period = 0;
@@ -916,10 +893,10 @@
 					saveUndo();
 
 					memcpy(editor.patternBuffer, song->patterns[song->currPattern],
-						sizeof (note_t) * (AMIGA_VOICES * MOD_ROWS));
+						sizeof (note_t) * (PAULA_VOICES * MOD_ROWS));
 
 					memset(song->patterns[song->currPattern], 0,
-						sizeof (note_t) * (AMIGA_VOICES * MOD_ROWS));
+						sizeof (note_t) * (PAULA_VOICES * MOD_ROWS));
 
 					updateWindowTitle(MOD_IS_MODIFIED);
 					ui.updatePatternData = true;
@@ -929,10 +906,10 @@
 					// cut channel commands and put in buffer
 					saveUndo();
 
-					noteDst = editor.cmdsBuffer;
-					for (i = 0; i < MOD_ROWS; i++)
+					note_t *noteDst = editor.cmdsBuffer;
+					for (int32_t i = 0; i < MOD_ROWS; i++)
 					{
-						noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+						note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 						*noteDst++ = *noteSrc;
 
 						noteSrc->command = 0;
@@ -958,9 +935,9 @@
 				{
 					// copy channel to buffer
 
-					noteDst = editor.trackBuffer;
-					for (i = 0; i < MOD_ROWS; i++)
-						*noteDst++ = song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+					note_t *noteDst = editor.trackBuffer;
+					for (int32_t i = 0; i < MOD_ROWS; i++)
+						*noteDst++ = song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 				}
 				else if (keyb.leftAltPressed)
 				{
@@ -967,16 +944,16 @@
 					// copy pattern to buffer
 
 					memcpy(editor.patternBuffer, song->patterns[song->currPattern],
-						sizeof (note_t) * (AMIGA_VOICES * MOD_ROWS));
+						sizeof (note_t) * (PAULA_VOICES * MOD_ROWS));
 				}
 				else if (keyb.leftCtrlPressed)
 				{
 					// copy channel commands to buffer
 
-					noteDst = editor.cmdsBuffer;
-					for (i = 0; i < MOD_ROWS; i++)
+					note_t *noteDst = editor.cmdsBuffer;
+					for (int32_t i = 0; i < MOD_ROWS; i++)
 					{
-						noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+						note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 						noteDst->command = noteSrc->command;
 						noteDst->param = noteSrc->param;
 
@@ -1000,9 +977,9 @@
 					// paste channel buffer to channel
 					saveUndo();
 
-					noteSrc = editor.trackBuffer;
-					for (i = 0; i < MOD_ROWS; i++)
-						song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel] = *noteSrc++;
+					note_t *noteSrc = editor.trackBuffer;
+					for (int32_t i = 0; i < MOD_ROWS; i++)
+						song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel] = *noteSrc++;
 
 					updateWindowTitle(MOD_IS_MODIFIED);
 					ui.updatePatternData = true;
@@ -1013,7 +990,7 @@
 					saveUndo();
 
 					memcpy(song->patterns[song->currPattern],
-						editor.patternBuffer, sizeof (note_t) * (AMIGA_VOICES * MOD_ROWS));
+						editor.patternBuffer, sizeof (note_t) * (PAULA_VOICES * MOD_ROWS));
 
 					updateWindowTitle(MOD_IS_MODIFIED);
 					ui.updatePatternData = true;
@@ -1023,10 +1000,10 @@
 					// paste channel commands buffer to channel
 					saveUndo();
 
-					noteSrc = editor.cmdsBuffer;
-					for (i = 0; i < MOD_ROWS; i++)
+					note_t *noteSrc = editor.cmdsBuffer;
+					for (int32_t i = 0; i < MOD_ROWS; i++)
 					{
-						noteDst = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+						note_t *noteDst = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 						noteDst->command = noteSrc->command;
 						noteDst->param = noteSrc->param;
 
@@ -1304,7 +1281,7 @@
 			}
 			else if (keyb.shiftPressed)
 			{
-				noteSrc = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 				editor.effectMacros[9] = (noteSrc->command << 8) | noteSrc->param;
 				displayMsg("COMMAND STORED!");
 			}
@@ -1329,7 +1306,7 @@
 			}
 			else if (keyb.shiftPressed)
 			{
-				noteSrc = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 				editor.effectMacros[0] = (noteSrc->command << 8) | noteSrc->param;
 				displayMsg("COMMAND STORED!");
 			}
@@ -1358,7 +1335,7 @@
 			}
 			else if (keyb.shiftPressed)
 			{
-				noteSrc = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 				editor.effectMacros[1] = (noteSrc->command << 8) | noteSrc->param;
 				displayMsg("COMMAND STORED!");
 			}
@@ -1387,7 +1364,7 @@
 			}
 			else if (keyb.shiftPressed)
 			{
-				noteSrc = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 				editor.effectMacros[2] = (noteSrc->command << 8) | noteSrc->param;
 				displayMsg("COMMAND STORED!");
 			}
@@ -1416,7 +1393,7 @@
 			}
 			else if (keyb.shiftPressed)
 			{
-				noteSrc = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 				editor.effectMacros[3] = (noteSrc->command << 8) | noteSrc->param;
 				displayMsg("COMMAND STORED!");
 			}
@@ -1441,7 +1418,7 @@
 			}
 			else if (keyb.shiftPressed)
 			{
-				noteSrc = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 				editor.effectMacros[4] = (noteSrc->command << 8) | noteSrc->param;
 				displayMsg("COMMAND STORED!");
 			}
@@ -1462,7 +1439,7 @@
 			}
 			else if (keyb.shiftPressed)
 			{
-				noteSrc = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 				editor.effectMacros[5] = (noteSrc->command << 8) | noteSrc->param;
 				displayMsg("COMMAND STORED!");
 			}
@@ -1483,7 +1460,7 @@
 			}
 			else if (keyb.shiftPressed)
 			{
-				noteSrc = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 				editor.effectMacros[6] = (noteSrc->command << 8) | noteSrc->param;
 				displayMsg("COMMAND STORED!");
 			}
@@ -1504,7 +1481,7 @@
 			}
 			else if (keyb.shiftPressed)
 			{
-				noteSrc = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 				editor.effectMacros[7] = (noteSrc->command << 8) | noteSrc->param;
 				displayMsg("COMMAND STORED!");
 			}
@@ -1525,7 +1502,7 @@
 			}
 			else if (keyb.shiftPressed)
 			{
-				noteSrc = &song->patterns[song->currPattern][(song->currRow * AMIGA_VOICES) + cursor.channel];
+				note_t *noteSrc = &song->patterns[song->currPattern][(song->currRow * PAULA_VOICES) + cursor.channel];
 				editor.effectMacros[8] = (noteSrc->command << 8) | noteSrc->param;
 				displayMsg("COMMAND STORED!");
 			}
@@ -1726,45 +1703,35 @@
 
 		case SDL_SCANCODE_KP_ENTER:
 		{
-			if (ui.askScreenShown)
+			editor.hiLowInstr ^= 0x10;
+
+			if (editor.sampleZero)
 			{
-				ui.answerNo = false;
-				ui.answerYes = true;
-				ui.askScreenShown = false;
-				handleAskYes();
+				editor.currSample = 15;
+				editor.sampleZero = false;
 			}
 			else
 			{
-				editor.hiLowInstr ^= 0x10;
+				editor.currSample ^= 0x10;
+			}
 
-				if (editor.sampleZero)
-				{
-					editor.currSample = 15;
-					editor.sampleZero = false;
-				}
-				else
-				{
-					editor.currSample ^= 0x10;
-				}
+			if (editor.currSample == 31) // kludge if sample was 15 (0010 in UI) before key press
+			{
+				editor.currSample = 15;
+				editor.sampleZero ^= 1;
+			}
 
-				if (editor.currSample == 31) // kludge if sample was 15 (0010 in UI) before key press
-				{
-					editor.currSample = 15;
-					editor.sampleZero ^= 1;
-				}
-
-				updateCurrSample();
-				if (keyb.leftAltPressed && editor.pNoteFlag > 0)
-				{
-					ui.changingDrumPadNote = true;
-					setStatusMessage("SELECT NOTE", NO_CARRY);
-					pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-					break;
-				}
-
-				if (editor.pNoteFlag > 0)
-					handleEditKeys(scancode, EDIT_SPECIAL);
+			updateCurrSample();
+			if (keyb.leftAltPressed && editor.pNoteFlag > 0)
+			{
+				ui.changingDrumPadNote = true;
+				setStatusMessage("SELECT NOTE", NO_CARRY);
+				pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
+				break;
 			}
+
+			if (editor.pNoteFlag > 0)
+				handleEditKeys(scancode, EDIT_SPECIAL);
 		}
 		break;
 
@@ -1866,11 +1833,8 @@
 
 		case SDL_SCANCODE_KP_PERIOD:
 		{
-			ui.askScreenShown = true;
-			ui.askScreenType = ASK_KILL_SAMPLE;
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-			setStatusMessage("KILL SAMPLE ?", NO_CARRY);
-			renderAskDialog();
+			if (askBox(ASKBOX_YES_NO, "KILL SAMPLE ?"))
+				killSample();
 		}
 		break;
 
@@ -1919,7 +1883,7 @@
 			else if (!ui.samplerScreenShown)
 			{
 				if (editor.currMode != MODE_PLAY && editor.currMode != MODE_RECORD)
-					modSetPos(DONT_SET_ORDER, (song->currRow + 1) & 0x3F);
+					modSetPos(DONT_SET_ORDER, (song->currRow + 1) & 63);
 
 				keyb.repeatKey = true;
 			}
@@ -1965,7 +1929,7 @@
 			else if (!ui.samplerScreenShown)
 			{
 				if ((editor.currMode != MODE_PLAY) && (editor.currMode != MODE_RECORD))
-					modSetPos(DONT_SET_ORDER, (song->currRow - 1) & 0x3F);
+					modSetPos(DONT_SET_ORDER, (song->currRow - 1) & 63);
 
 				keyb.repeatKey = true;
 			}
@@ -2100,9 +2064,9 @@
 			if (keyb.leftCtrlPressed)
 			{
 				// CTRL+B doesn't change the status message back, so do this:
-				if (ui.introScreenShown)
+				if (ui.introTextShown)
 				{
-					ui.introScreenShown = false;
+					ui.introTextShown = false;
 					statusAllRight();
 				}
 
@@ -2121,7 +2085,7 @@
 			}
 			else if (keyb.leftAltPressed)
 			{
-				s = &song->samples[editor.currSample];
+				moduleSample_t *s = &song->samples[editor.currSample];
 				if (s->length == 0)
 				{
 					statusSampleIsEmpty();
@@ -2163,8 +2127,8 @@
 				editor.blockMarkFlag = false;
 				editor.blockBufferFlag = true;
 
-				for (i = 0; i < MOD_ROWS; i++)
-					editor.blockBuffer[i] = song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+				for (int32_t i = 0; i < MOD_ROWS; i++)
+					editor.blockBuffer[i] = song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 
 				if (editor.blockFromPos > editor.blockToPos)
 				{
@@ -2256,16 +2220,17 @@
 			{
 				saveUndo();
 
-				j = song->currRow + 1;
+				int32_t j = song->currRow + 1;
 				while (j < MOD_ROWS)
 				{
+					int32_t i;
 					for (i = 62; i >= j; i--)
 					{
-						noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
-						song->patterns[song->currPattern][((i + 1) * AMIGA_VOICES) + cursor.channel] = *noteSrc;
+						note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
+						song->patterns[song->currPattern][((i + 1) * PAULA_VOICES) + cursor.channel] = *noteSrc;
 					}
 
-					noteDst = &song->patterns[song->currPattern][((i + 1) * AMIGA_VOICES) + cursor.channel];
+					note_t *noteDst = &song->patterns[song->currPattern][((i + 1) * PAULA_VOICES) + cursor.channel];
 					noteDst->period = 0;
 					noteDst->sample = 0;
 					noteDst->command = 0;
@@ -2299,16 +2264,21 @@
 			}
 			else if (keyb.leftCtrlPressed)
 			{
-				toggleLEDFilter();
-
+				editor.useLEDFilter ^= 1;
 				if (editor.useLEDFilter)
+				{
+					setLEDFilter(true);
 					displayMsg("LED FILTER ON");
+				}
 				else
+				{
+					setLEDFilter(false);
 					displayMsg("LED FILTER OFF");
+				}
 			}
 			else if (keyb.leftAltPressed)
 			{
-				s = &song->samples[editor.currSample];
+				moduleSample_t *s = &song->samples[editor.currSample];
 				if (s->length == 0)
 				{
 					statusSampleIsEmpty();
@@ -2330,11 +2300,16 @@
 		{
 			if (keyb.leftCtrlPressed)
 			{
-				ui.askScreenShown = true;
-				ui.askScreenType = ASK_BOOST_ALL_SAMPLES;
-				pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-				setStatusMessage("BOOST ALL SAMPLES", NO_CARRY);
-				renderAskDialog();
+				if (askBox(ASKBOX_YES_NO, "BOOST ALL SAMPLES"))
+				{
+					for (int32_t i = 0; i < MOD_SAMPLES; i++)
+						boostSample(i, true);
+
+					if (ui.samplerScreenShown)
+						redrawSample();
+
+					updateWindowTitle(MOD_IS_MODIFIED);
+				}
 			}
 			else if (keyb.leftAltPressed) // toggle record mode (PT clone and PT2.3E only)
 			{
@@ -2385,23 +2360,25 @@
 
 				if (song->currRow < 63)
 				{
-					for (i = 0; i <= editor.buffToPos-editor.buffFromPos; i++)
+					for (int32_t i = 0; i <= editor.buffToPos-editor.buffFromPos; i++)
 					{
-						for (j = 62; j >= song->currRow; j--)
+						for (int32_t j = 62; j >= song->currRow; j--)
 						{
-							noteSrc = &song->patterns[song->currPattern][(j * AMIGA_VOICES) + cursor.channel];
-							song->patterns[song->currPattern][((j + 1) * AMIGA_VOICES) + cursor.channel] = *noteSrc;
+							note_t *noteSrc = &song->patterns[song->currPattern][(j * PAULA_VOICES) + cursor.channel];
+							song->patterns[song->currPattern][((j + 1) * PAULA_VOICES) + cursor.channel] = *noteSrc;
 						}
 					}
 				}
 
 				saveUndo();
+
+				int32_t i;
 				for (i = 0; i <= editor.buffToPos-editor.buffFromPos; i++)
 				{
 					if (song->currRow+i > 63)
 						break;
 
-					song->patterns[song->currPattern][((song->currRow + i) * AMIGA_VOICES) + cursor.channel]
+					song->patterns[song->currPattern][((song->currRow + i) * PAULA_VOICES) + cursor.channel]
 						= editor.blockBuffer[editor.buffFromPos + i];
 				}
 
@@ -2439,12 +2416,13 @@
 
 				saveUndo();
 
-				i = editor.buffFromPos;
-				j = song->currRow;
-				patt = song->patterns[song->currPattern];
+				int32_t i = editor.buffFromPos;
+				int32_t j = song->currRow;
+				note_t *patt = song->patterns[song->currPattern];
+
 				while (true)
 				{
-					noteDst = &patt[(j * AMIGA_VOICES) + cursor.channel];
+					note_t *noteDst = &patt[(j * PAULA_VOICES) + cursor.channel];
 
 					if (editor.blockBuffer[i].period == 0 && editor.blockBuffer[i].sample == 0)
 					{
@@ -2484,9 +2462,9 @@
 		{
 			if (keyb.leftAltPressed)
 			{
-				for (i = 0; i < MOD_ROWS; i++)
+				for (int32_t i = 0; i < MOD_ROWS; i++)
 				{
-					noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+					note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 					if (noteSrc->sample == editor.currSample+1)
 					{
 						noteSrc->period = 0;
@@ -2503,13 +2481,13 @@
 			{
 				saveUndo();
 
-				i = song->currRow;
+				int32_t i = song->currRow;
 				if (keyb.shiftPressed)
 				{
 					// kill to start
 					while (i >= 0)
 					{
-						noteDst = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+						note_t *noteDst = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 						noteDst->period = 0;
 						noteDst->sample = 0;
 						noteDst->command = 0;
@@ -2523,7 +2501,7 @@
 					// kill to end
 					while (i < MOD_ROWS)
 					{
-						noteDst = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+						note_t *noteDst = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 						noteDst->period = 0;
 						noteDst->sample = 0;
 						noteDst->command = 0;
@@ -2608,17 +2586,17 @@
 
 				saveUndo();
 
-				j = song->currRow + 1;
+				int32_t j = song->currRow + 1;
 				while (j < MOD_ROWS)
 				{
-					for (i = j; i < MOD_ROWS-1; i++)
+					for (int32_t i = j; i < MOD_ROWS-1; i++)
 					{
-						noteSrc = &song->patterns[song->currPattern][((i + 1) * AMIGA_VOICES) + cursor.channel];
-						song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel] = *noteSrc;
+						note_t *noteSrc = &song->patterns[song->currPattern][((i + 1) * PAULA_VOICES) + cursor.channel];
+						song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel] = *noteSrc;
 					}
 
 					// clear newly made row on very bottom
-					noteDst = &song->patterns[song->currPattern][(63 * AMIGA_VOICES) + cursor.channel];
+					note_t *noteDst = &song->patterns[song->currPattern][(63 * PAULA_VOICES) + cursor.channel];
 					noteDst->period = 0;
 					noteDst->sample = 0;
 					noteDst->command = 0;
@@ -2649,12 +2627,13 @@
 
 				saveUndo();
 
-				i = editor.buffFromPos;
-				j = song->currRow;
-				patt = song->patterns[song->currPattern];
+				int32_t i = editor.buffFromPos;
+				int32_t j = song->currRow;
+				note_t *patt = song->patterns[song->currPattern];
+
 				while (true)
 				{
-					noteDst = &patt[(j * AMIGA_VOICES) + cursor.channel];
+					note_t *noteDst = &patt[(j * PAULA_VOICES) + cursor.channel];
 					*noteDst = editor.blockBuffer[i];
 
 					if (i == editor.buffToPos || i == 63 || j == 63)
@@ -2713,12 +2692,8 @@
 			}
 			else if (keyb.leftAltPressed)
 			{
-				ui.askScreenShown = true;
-				ui.askScreenType = ASK_QUIT;
-
-				pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-				setStatusMessage("REALLY QUIT ?", NO_CARRY);
-				renderAskDialog();
+				if (askBox(ASKBOX_YES_NO, "REALLY QUIT ?"))
+					ui.throwExit = true;
 			}
 			else
 			{
@@ -2745,11 +2720,8 @@
 			}
 			else if (keyb.leftAltPressed)
 			{
-				ui.askScreenShown = true;
-				ui.askScreenType = ASK_RESAMPLE;
-				pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-				setStatusMessage("RESAMPLE?", NO_CARRY);
-				renderAskDialog();
+				if (askBox(ASKBOX_YES_NO, "RESAMPLE?"))
+					samplerResample();
 			}
 			else
 			{
@@ -2829,12 +2801,16 @@
 				}
 				else
 				{
-					ui.askScreenShown = true;
-					ui.askScreenType = ASK_FILTER_ALL_SAMPLES;
+					if (askBox(ASKBOX_YES_NO, "FILTER ALL SAMPLS"))
+					{
+						for (int32_t i = 0; i < MOD_SAMPLES; i++)
+							filterSample(i, true);
 
-					pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-					setStatusMessage("FILTER ALL SAMPLS", NO_CARRY);
-					renderAskDialog();
+						if (ui.samplerScreenShown)
+							redrawSample();
+
+						updateWindowTitle(MOD_IS_MODIFIED);
+					}
 				}
 			}
 			else if (keyb.leftAltPressed)
@@ -2866,12 +2842,13 @@
 
 				saveUndo();
 
-				i = editor.buffFromPos;
-				j = song->currRow;
-				patt = song->patterns[song->currPattern];
+				int32_t i = editor.buffFromPos;
+				int32_t j = song->currRow;
+				note_t *patt = song->patterns[song->currPattern];
+
 				while (true)
 				{
-					noteDst = &patt[(j * AMIGA_VOICES) + cursor.channel];
+					note_t *noteDst = &patt[(j * PAULA_VOICES) + cursor.channel];
 					if (editor.blockBuffer[i].period == 0 && editor.blockBuffer[i].sample == 0)
 					{
 						noteDst->command = editor.blockBuffer[i].command;
@@ -2931,8 +2908,8 @@
 				saveUndo();
 				editor.blockBufferFlag = true;
 
-				for (i = 0; i < MOD_ROWS; i++)
-					editor.blockBuffer[i] = song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+				for (int32_t i = 0; i < MOD_ROWS; i++)
+					editor.blockBuffer[i] = song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 
 				if (editor.blockFromPos > editor.blockToPos)
 				{
@@ -2945,9 +2922,9 @@
 					editor.buffToPos = editor.blockToPos;
 				}
 
-				for (i = editor.buffFromPos; i <= editor.buffToPos; i++)
+				for (int32_t i = editor.buffFromPos; i <= editor.buffToPos; i++)
 				{
-					noteDst = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+					note_t *noteDst = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 					noteDst->period = 0;
 					noteDst->sample = 0;
 					noteDst->command = 0;
@@ -2975,6 +2952,8 @@
 
 		case SDL_SCANCODE_Y:
 		{
+			uint8_t blockFrom, blockTo;
+
 			if (keyb.leftCtrlPressed)
 			{
 				if (!editor.blockMarkFlag)
@@ -3000,10 +2979,10 @@
 
 				while (blockFrom < blockTo)
 				{
-					noteDst = &song->patterns[song->currPattern][(blockFrom * AMIGA_VOICES) + cursor.channel];
-					noteSrc = &song->patterns[song->currPattern][(blockTo * AMIGA_VOICES) + cursor.channel];
+					note_t *noteDst = &song->patterns[song->currPattern][(blockFrom * PAULA_VOICES) + cursor.channel];
+					note_t *noteSrc = &song->patterns[song->currPattern][(blockTo * PAULA_VOICES) + cursor.channel];
 
-					noteTmp = *noteDst;
+					note_t noteTmp = *noteDst;
 					*noteDst = *noteSrc;
 					*noteSrc = noteTmp;
 
@@ -3017,11 +2996,20 @@
 			}
 			else if (keyb.leftAltPressed)
 			{
-				ui.askScreenShown = true;
-				ui.askScreenType = ASK_SAVE_ALL_SAMPLES;
-				pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-				setStatusMessage("SAVE ALL SAMPLES?", NO_CARRY);
-				renderAskDialog();
+				if (askBox(ASKBOX_YES_NO, "SAVE ALL SAMPLES?"))
+				{
+					int8_t oldSample = editor.currSample;
+					for (int32_t i = 0; i < MOD_SAMPLES; i++)
+					{
+						editor.currSample = (int8_t)i;
+						if (song->samples[i].length > 2)
+							saveSample(DONT_CHECK_IF_FILE_EXIST, GIVE_NEW_FILENAME);
+					}
+					editor.currSample = oldSample;
+
+					displayMsg("SAMPLES SAVED !");
+					setMsgPointer();
+				}
 			}
 			else
 			{
@@ -3040,12 +3028,8 @@
 			{
 				if (ui.samplerScreenShown)
 				{
-					ui.askScreenShown = true;
-					ui.askScreenType = ASK_RESTORE_SAMPLE;
-
-					pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-					setStatusMessage("RESTORE SAMPLE ?", NO_CARRY);
-					renderAskDialog();
+					if (askBox(ASKBOX_YES_NO, "RESTORE SAMPLE?"))
+						redoSampleData(editor.currSample);
 				}
 				else
 				{
@@ -3052,9 +3036,9 @@
 					modSetTempo(125, true);
 					modSetSpeed(6);
 
-					for (i = 0; i < AMIGA_VOICES; i++)
+					moduleChannel_t *ch = song->channels;
+					for (int32_t i = 0; i < PAULA_VOICES; i++, ch++)
 					{
-						ch = &song->channels[i];
 						ch->n_wavecontrol = 0;
 						ch->n_glissfunk = 0;
 						ch->n_finetune = 0;
@@ -3082,7 +3066,7 @@
 	}
 }
 
-void movePatCurPrevCh(void)
+static void movePatCurPrevCh(void)
 {
 	int8_t pos = ((cursor.pos + 5) / 6) - 1;
 
@@ -3097,7 +3081,7 @@
 	updateCursorPos();
 }
 
-void movePatCurNextCh(void)
+static void movePatCurNextCh(void)
 {
 	int8_t pos = (cursor.pos / 6) + 1;
 
@@ -3112,7 +3096,7 @@
 	updateCursorPos();
 }
 
-void movePatCurRight(void)
+static void movePatCurRight(void)
 {
 	cursor.pos = (cursor.pos == 23) ? 0 : (cursor.pos + 1);
 
@@ -3125,7 +3109,7 @@
 	updateCursorPos();
 }
 
-void movePatCurLeft(void)
+static void movePatCurLeft(void)
 {
 	cursor.pos = (cursor.pos == 0) ? 23 : (cursor.pos - 1);
 
@@ -3140,9 +3124,7 @@
 
 void handleKeyRepeat(SDL_Scancode scancode)
 {
-	uint8_t repeatNum;
-
-	if (!keyb.repeatKey || (ui.clearScreenShown || ui.askScreenShown))
+	if (!keyb.repeatKey || ui.askBoxShown)
 	{
 		keyb.repeatFrac = 0;
 		keyb.repeatCounter = 0;
@@ -3374,7 +3356,7 @@
 			{
 				if (editor.currMode != MODE_PLAY && editor.currMode != MODE_RECORD)
 				{
-					repeatNum = 6;
+					uint8_t repeatNum = 6;
 					if (keyb.leftAltPressed)
 						repeatNum = 1;
 					else if (keyb.shiftPressed)
@@ -3383,7 +3365,7 @@
 					if (keyb.repeatCounter >= repeatNum)
 					{
 						keyb.repeatCounter = 0;
-						modSetPos(DONT_SET_ORDER, (song->currRow - 1) & 0x3F);
+						modSetPos(DONT_SET_ORDER, (song->currRow - 1) & 63);
 					}
 				}
 			}
@@ -3431,7 +3413,7 @@
 			{
 				if (editor.currMode != MODE_PLAY && editor.currMode != MODE_RECORD)
 				{
-					repeatNum = 6;
+					uint8_t repeatNum = 6;
 					if (keyb.leftAltPressed)
 						repeatNum = 1;
 					else if (keyb.shiftPressed)
@@ -3440,7 +3422,7 @@
 					if (keyb.repeatCounter >= repeatNum)
 					{
 						keyb.repeatCounter = 0;
-						modSetPos(DONT_SET_ORDER, (song->currRow + 1) & 0x3F);
+						modSetPos(DONT_SET_ORDER, (song->currRow + 1) & 63);
 					}
 				}
 			}
@@ -3485,9 +3467,9 @@
 	}
 
 	keyb.repeatFrac += keyb.repeatDelta; // 32.32 fixed-point counter
-	if (keyb.repeatFrac > 0xFFFFFFFF)
+	if (keyb.repeatFrac > UINT32_MAX)
 	{
-		keyb.repeatFrac &= 0xFFFFFFFF;
+		keyb.repeatFrac &= UINT32_MAX;
 		keyb.repeatCounter++;
 	}
 }
@@ -3499,10 +3481,10 @@
 
 	for (int32_t i = 0; i < MOD_ROWS; i++)
 	{
-		note_t *noteSrc = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + dstCh];
-		note_t noteTmp = song->patterns[song->currPattern][(i * AMIGA_VOICES) + srcCh];
+		note_t *noteSrc = &song->patterns[song->currPattern][(i * PAULA_VOICES) + dstCh];
+		note_t noteTmp = song->patterns[song->currPattern][(i * PAULA_VOICES) + srcCh];
 
-		song->patterns[song->currPattern][(i * AMIGA_VOICES) + srcCh] = *noteSrc;
+		song->patterns[song->currPattern][(i * PAULA_VOICES) + srcCh] = *noteSrc;
 		*noteSrc = noteTmp;
 	}
 
@@ -3510,10 +3492,17 @@
 	ui.updatePatternData = true;
 }
 
-bool handleGeneralModes(SDL_Keycode keycode, SDL_Scancode scancode)
+static bool handleGeneralModes(SDL_Scancode scancode)
 {
-	int8_t rawKey;
+	// if MOD2WAV is ongoing, only check for ESC key
+	if (editor.mod2WavOngoing)
+	{
+		if (scancode == SDL_SCANCODE_ESCAPE)
+			editor.abortMod2Wav = true;
 
+		return false; // don't handle other keys
+	}
+
 	// SAMPLER SCREEN (volume box)
 	if (ui.samplerVolBoxShown && !ui.editTextFlag && scancode == SDL_SCANCODE_ESCAPE)
 	{
@@ -3539,7 +3528,6 @@
 			return false;
 		}
 
-
 		if (scancode == SDL_SCANCODE_F1)
 			editor.keyOctave = OCTAVE_LOW;
 		else if (scancode == SDL_SCANCODE_F2)
@@ -3554,7 +3542,7 @@
 				pointerSetPreviousMode();
 			}
 
-			rawKey = keyToNote(scancode);
+			int8_t rawKey = keyToNote(scancode);
 			if (rawKey >= 0)
 			{
 				ui.changingSamplingNote = false;
@@ -3619,7 +3607,7 @@
 		else if (scancode == SDL_SCANCODE_F2)
 			editor.keyOctave = OCTAVE_HIGH;
 
-		rawKey = keyToNote(scancode);
+		int8_t rawKey = keyToNote(scancode);
 		if (rawKey >= 0)
 		{
 			if (ui.changingChordNote == 1)
@@ -3669,7 +3657,7 @@
 		else if (scancode == SDL_SCANCODE_F2)
 			editor.keyOctave = OCTAVE_HIGH;
 
-		rawKey = keyToNote(scancode);
+		int8_t rawKey = keyToNote(scancode);
 		if (rawKey >= 0)
 		{
 			pNoteTable[editor.currSample] = rawKey;
@@ -3698,7 +3686,7 @@
 		else if (scancode == SDL_SCANCODE_F2)
 			editor.keyOctave = OCTAVE_HIGH;
 
-		rawKey = keyToNote(scancode);
+		int8_t rawKey = keyToNote(scancode);
 		if (rawKey >= 0)
 		{
 			editor.resampleNote = rawKey;
@@ -3711,66 +3699,6 @@
 		return false;
 	}
 
-	// DISK OP. SCREEN
-	if (diskop.isFilling)
-	{
-		if (ui.askScreenShown && ui.askScreenType == ASK_QUIT)
-		{
-			if (keycode == SDLK_y || keycode == SDLK_RETURN)
-			{
-				ui.askScreenShown = false;
-				ui.answerNo = false;
-				ui.answerYes = true;
-				handleAskYes();
-			}
-			else if (keycode == SDLK_n || keycode == SDLK_ESCAPE)
-			{
-				ui.askScreenShown = false;
-				ui.answerNo = true;
-				ui.answerYes = false;
-				handleAskNo();
-			}
-		}
-
-		return false;
-	}
-
-	// if MOD2WAV is ongoing, only react to ESC and Y/N on exit ask dialog
-	if (editor.isWAVRendering)
-	{
-		if (ui.askScreenShown && ui.askScreenType == ASK_QUIT)
-		{
-			if (keycode == SDLK_y)
-			{
-				editor.isWAVRendering = false;
-				SDL_WaitThread(editor.mod2WavThread, NULL);
-
-				ui.askScreenShown = false;
-				ui.answerNo = false;
-				ui.answerYes = true;
-
-				handleAskYes();
-			}
-			else if (keycode == SDLK_n)
-			{
-				ui.askScreenShown = false;
-				ui.answerNo = true;
-				ui.answerYes = false;
-
-				handleAskNo();
-
-				pointerSetMode(POINTER_MODE_MSG2, NO_CARRY);
-				setStatusMessage("RENDERING MOD...", NO_CARRY);
-			}
-		}
-		else if (scancode == SDL_SCANCODE_ESCAPE)
-		{
-			editor.abortMod2Wav = true;
-		}
-
-		return false;
-	}
-
 	// SWAP CHANNEL (CTRL+T)
 	if (editor.swapChannelFlag)
 	{
@@ -3830,167 +3758,11 @@
 		return false;
 	}
 
-	// YES/NO ASK DIALOG
-	if (ui.askScreenShown)
-	{
-		if (ui.pat2SmpDialogShown)
-		{
-			// PAT2SMP specific ask dialog
-			switch (keycode)
-			{
-				case SDLK_KP_ENTER:
-				case SDLK_RETURN:
-				case SDLK_h:
-				{
-					ui.askScreenShown = false;
-					ui.answerNo = true;
-					ui.answerYes = false;
-					editor.pat2SmpHQ = true;
-					handleAskYes();
-				}
-				break;
-
-				case SDLK_l:
-				{
-					ui.askScreenShown = false;
-					ui.answerNo = false;
-					ui.answerYes = true;
-					editor.pat2SmpHQ = false;
-					handleAskYes();
-					// pointer/status is updated by the 'yes handler'
-				}
-				break;
-
-				case SDLK_ESCAPE:
-				case SDLK_a:
-				case SDLK_n:
-				{
-					ui.askScreenShown = false;
-					ui.answerNo = true;
-					ui.answerYes = false;
-					handleAskNo();
-				}
-				break;
-
-				default: break;
-			}
-		}
-		else
-		{
-			// normal yes/no dialog
-			switch (keycode)
-			{
-				case SDLK_ESCAPE:
-				case SDLK_n:
-				{
-					ui.askScreenShown = false;
-					ui.answerNo = true;
-					ui.answerYes = false;
-					handleAskNo();
-				}
-				break;
-
-				case SDLK_KP_ENTER:
-				case SDLK_RETURN:
-				case SDLK_y:
-				{
-					ui.askScreenShown = false;
-					ui.answerNo = false;
-					ui.answerYes = true;
-					handleAskYes();
-					// pointer/status is updated by the 'yes handler'
-				}
-				break;
-
-				default: break;
-			}
-		}
-
-		return false;
-	}
-
-	// CLEAR SCREEN DIALOG
-	if (ui.clearScreenShown)
-	{
-		switch (keycode)
-		{
-			case SDLK_s:
-			{
-				ui.clearScreenShown = false;
-				removeClearScreen();
-
-				modStop();
-				clearSamples();
-
-				editor.playMode = PLAY_MODE_NORMAL;
-				editor.currMode = MODE_IDLE;
-
-				pointerSetPreviousMode();
-				setPrevStatusMessage();
-			}
-			break;
-
-			case SDLK_o:
-			{
-				ui.clearScreenShown = false;
-				removeClearScreen();
-
-				modStop();
-				clearSong();
-
-				editor.playMode = PLAY_MODE_NORMAL;
-				editor.currMode = MODE_IDLE;
-
-				pointerSetPreviousMode();
-				setPrevStatusMessage();
-			}
-			break;
-
-			case SDLK_a:
-			{
-				ui.clearScreenShown = false;
-				removeClearScreen();
-
-				modStop();
-				clearAll();
-
-				editor.playMode = PLAY_MODE_NORMAL;
-				editor.currMode = MODE_IDLE;
-
-				pointerSetPreviousMode();
-				setPrevStatusMessage();
-			}
-			break;
-
-			case SDLK_c:
-			case SDLK_ESCAPE:
-			{
-				ui.clearScreenShown = false;
-				removeClearScreen();
-
-				editor.currMode = MODE_IDLE;
-
-				pointerSetPreviousMode();
-				setPrevStatusMessage();
-			}
-			break;
-
-			default: break;
-		}
-
-		return false;
-	}
-
 	return true;
 }
 
 void handleTextEditInputChar(char textChar)
 {
-	char *readTmp;
-	int8_t readTmpPrev;
-	uint8_t digit1, digit2, digit3, digit4;
-	uint32_t i, number;
-
 	// we only want certain keys
 	if (textChar < ' ' || textChar > '~')
 		return;
@@ -4005,10 +3777,10 @@
 		{
 			if (!editor.mixFlag)
 			{
-				readTmp = ui.textEndPtr;
+				char *readTmp = ui.textEndPtr;
 				while (readTmp > ui.editPos)
 				{
-					readTmpPrev = *--readTmp;
+					int8_t readTmpPrev = *--readTmp;
 					*(readTmp + 1) = readTmpPrev;
 				}
 
@@ -4030,7 +3802,7 @@
 
 					if (ui.dstPos == 9) // hack for sample mix text
 					{
-						for (i = 0; i < 4; i++)
+						for (int32_t i = 0; i < 4; i++)
 						{
 							ui.editPos++;
 							textMarkerMoveRight();
@@ -4051,6 +3823,9 @@
 		{
 			if (textChar >= '0' && textChar <= '9')
 			{
+				uint8_t digit1, digit2, digit3, digit4;
+				uint32_t number;
+
 				textChar -= '0';
 
 				if (ui.numLen == 4)
@@ -4143,11 +3918,6 @@
 
 bool handleTextEditMode(SDL_Scancode scancode)
 {
-	char *readTmp;
-	int8_t readTmpNext;
-	int16_t i, j;
-	note_t *noteSrc, *noteDst;
-
 	switch (scancode)
 	{
 		case SDL_SCANCODE_ESCAPE:
@@ -4229,10 +3999,10 @@
 				if (editor.mixFlag || ui.editTextType != TEXT_EDIT_STRING)
 					break;
 
-				readTmp = ui.editPos;
+				char *readTmp = ui.editPos;
 				while (readTmp < ui.textEndPtr)
 				{
-					readTmpNext = *(readTmp + 1);
+					int8_t readTmpNext = *(readTmp + 1);
 					*readTmp++ = readTmpNext;
 				}
 
@@ -4262,10 +4032,10 @@
 				{
 					ui.editPos--;
 
-					readTmp = ui.editPos;
+					char *readTmp = ui.editPos;
 					while (readTmp < ui.textEndPtr)
 					{
-						readTmpNext = *(readTmp + 1);
+						int8_t readTmpNext = *(readTmp + 1);
 						*readTmp++ = readTmpNext;
 					}
 
@@ -4300,16 +4070,16 @@
 					{
 						if (song->currRow > 0)
 						{
-							for (i = 0; i < AMIGA_VOICES; i++)
+							for (int32_t i = 0; i < PAULA_VOICES; i++)
 							{
-								for (j = (song->currRow - 1); j < MOD_ROWS; j++)
+								for (int32_t j = (song->currRow - 1); j < MOD_ROWS; j++)
 								{
-									noteSrc = &song->patterns[song->currPattern][((j + 1) * AMIGA_VOICES) + i];
-									song->patterns[song->currPattern][(j * AMIGA_VOICES) + i] = *noteSrc;
+									note_t *noteSrc = &song->patterns[song->currPattern][((j + 1) * PAULA_VOICES) + i];
+									song->patterns[song->currPattern][(j * PAULA_VOICES) + i] = *noteSrc;
 								}
 
 								// clear newly made row on very bottom
-								noteDst = &song->patterns[song->currPattern][(63 * AMIGA_VOICES) + i];
+								note_t *noteDst = &song->patterns[song->currPattern][(63 * PAULA_VOICES) + i];
 								noteDst->period = 0;
 								noteDst->sample = 0;
 								noteDst->command = 0;
@@ -4324,10 +4094,10 @@
 					{
 						if (song->currRow > 0)
 						{
-							for (i = song->currRow-1; i < MOD_ROWS-1; i++)
+							for (int32_t i = song->currRow-1; i < MOD_ROWS-1; i++)
 							{
-								noteSrc = &song->patterns[song->currPattern][((i + 1) * AMIGA_VOICES) + cursor.channel];
-								noteDst = &song->patterns[song->currPattern][(i * AMIGA_VOICES) + cursor.channel];
+								note_t *noteSrc = &song->patterns[song->currPattern][((i + 1) * PAULA_VOICES) + cursor.channel];
+								note_t *noteDst = &song->patterns[song->currPattern][(i * PAULA_VOICES) + cursor.channel];
 
 								if (keyb.leftCtrlPressed)
 								{
@@ -4341,7 +4111,7 @@
 							}
 
 							// clear newly made row on very bottom
-							noteDst = &song->patterns[song->currPattern][(63 * AMIGA_VOICES) + cursor.channel];
+							note_t *noteDst = &song->patterns[song->currPattern][(63 * PAULA_VOICES) + cursor.channel];
 							noteDst->period = 0;
 							noteDst->sample = 0;
 							noteDst->command = 0;
@@ -4364,7 +4134,7 @@
 					else
 						doStopIt(true);
 
-					playPattern((song->currRow - 1) & 0x3F);
+					playPattern((song->currRow - 1) & 63);
 
 					if (config.keepEditModeAfterStepPlay && editor.stepPlayLastMode == MODE_EDIT)
 					{
--- a/src/pt2_keyboard.h
+++ b/src/pt2_keyboard.h
@@ -13,7 +13,7 @@
 void textCharNext(void);
 void readKeyModifiers(void);
 void handleKeyRepeat(SDL_Scancode scancode);
-void keyUpHandler(SDL_Scancode scancode, SDL_Keycode keycode);
+void keyUpHandler(SDL_Scancode scancode);
 void keyDownHandler(SDL_Scancode scancode, SDL_Keycode keycode);
 void handleTextEditInputChar(char textChar);
 
--- a/src/pt2_ledfilter.c
+++ /dev/null
@@ -1,46 +1,0 @@
-/* Fast and approximated implementation of the Amiga "LED" filter.
-** Based on https://www.musicdsp.org/en/latest/Filters/38-lp-and-hp-filter.html
-*/
-
-#include "pt2_math.h"
-#include "pt2_ledfilter.h"
-
-void clearLEDFilterState(ledFilter_t *f)
-{
-	f->LIn1 = f->LIn2 = f->LOut1 = f->LOut2 = 0.0;
-	f->RIn1 = f->RIn2 = f->ROut1 = f->ROut2 = 0.0;
-}
-
-void calcLEDFilterCoeffs(double sr, double hz, double qfactor, ledFilter_t *filter)
-{
-	const double c = 1.0 / pt2_tan((PT2_PI * hz) / sr);
-	const double r = 1.0 / qfactor;
-
-	filter->a1 = 1.0 / (1.0 + r * c + c * c);
-	filter->a2 = 2.0 * filter->a1;
-	filter->a3 = filter->a1;
-	filter->b1 = 2.0 * (1.0 - c*c) * filter->a1;
-	filter->b2 = (1.0 - r * c + c * c) * filter->a1;
-}
-
-void LEDFilter(ledFilter_t *f, const double *in, double *out)
-{
-	const double LOut = (f->a1 * in[0]) + (f->a2 * f->LIn1) + (f->a3 * f->LIn2) - (f->b1 * f->LOut1) - (f->b2 * f->LOut2);
-	const double ROut = (f->a1 * in[1]) + (f->a2 * f->RIn1) + (f->a3 * f->RIn2) - (f->b1 * f->ROut1) - (f->b2 * f->ROut2);
-
-	// shift states
-
-	f->LIn2 = f->LIn1;
-	f->LIn1 = in[0];
-	f->LOut2 = f->LOut1;
-	f->LOut1 = LOut;
-
-	f->RIn2 = f->RIn1;
-	f->RIn1 = in[1];
-	f->ROut2 = f->ROut1;
-	f->ROut1 = ROut;
-
-	// set output
-	out[0] = LOut;
-	out[1] = ROut;
-}
--- a/src/pt2_ledfilter.h
+++ /dev/null
@@ -1,12 +1,0 @@
-#pragma once
-
-typedef struct ledFilter_t
-{
-	double LIn1, LIn2, LOut1, LOut2;
-	double RIn1, RIn2, ROut1, ROut2;
-	double a1, a2, a3, b1, b2;
-} ledFilter_t;
-
-void clearLEDFilterState(ledFilter_t *f);
-void calcLEDFilterCoeffs(double sr, double hz, double qfactor, ledFilter_t *filter);
-void LEDFilter(ledFilter_t *f, const double *in, double *out);
--- a/src/pt2_main.c
+++ b/src/pt2_main.c
@@ -17,7 +17,6 @@
 #include <unistd.h> // chdir()
 #endif
 #include <sys/stat.h>
-#include "pt2_header.h"
 #include "pt2_helpers.h"
 #include "pt2_keyboard.h"
 #include "pt2_textout.h"
@@ -29,14 +28,13 @@
 #include "pt2_edit.h"
 #include "pt2_module_loader.h"
 #include "pt2_module_saver.h"
-#include "pt2_sample_loader.h"
-#include "pt2_unicode.h"
 #include "pt2_scopes.h"
 #include "pt2_audio.h"
 #include "pt2_bmp.h"
 #include "pt2_sync.h"
 #include "pt2_sampling.h"
-#include "pt2_hpc.h"
+#include "pt2_askbox.h"
+#include "pt2_replayer.h"
 
 #define CRASH_TEXT "Oh no!\nThe ProTracker 2 clone has crashed...\n\nA backup .mod was hopefully " \
                    "saved to the current module directory.\n\nPlease report this bug if you can.\n" \
@@ -170,7 +168,7 @@
 #ifdef _WIN32
 
 	// ALT+F4 is used in ProTracker, but is "close program" in Windows...
-#if SDL_MAJOR_VERSION == 2 && SDL_MINOR_VERSION >= 0 && SDL_PATCHLEVEL >= 4
+#if SDL_MINOR_VERSION >= 24 || (SDL_MINOR_VERSION == 0 && SDL_PATCHLEVEL >= 4)
 	SDL_SetHint(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, "1");
 #endif
 
@@ -332,14 +330,18 @@
 	if (config.startInFullscreen)
 		toggleFullscreen();
 
-	changePathToHome(); // set path to home/user-dir now
+	changePathToDesktop(); // change path to desktop now
 	diskOpSetInitPath(); // set path to custom path in config (if present)
 
 	SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
 
-	hpc_ResetEndTime(&video.vblankHpc);
+	editor.mainLoopOngoing = true;
+	hpc_ResetEndTime(&video.vblankHpc); // this must be the very last thing done before entering the main loop
+
+	// XXX: if you change anything in the main loop, make sure it goes in the askBox()(pt2_askbox.c) loop too, if needed
 	while (editor.programRunning)
 	{
+		handleThreadedAskBox();
 		sinkVisualizerBars();
 		updateChannelSyncBuffer();
 		readMouseXY();
@@ -348,11 +350,8 @@
 		updateMouseCounters();
 		handleKeyRepeat(keyb.lastRepKey);
 
-		if (!mouse.buttonWaiting && ui.sampleMarkingPos == -1 &&
-			!ui.forceSampleDrag && !ui.forceVolDrag && !ui.forceSampleEdit)
-		{
+		if (!mouse.buttonWaiting && ui.sampleMarkingPos == -1 && !ui.forceSampleDrag && !ui.forceVolDrag && !ui.forceSampleEdit)
 			handleGUIButtonRepeat();
-		}
 
 		renderFrame();
 		flipFrame();
@@ -366,9 +365,7 @@
 
 static void handleInput(void)
 {
-	char inputChar;
 	SDL_Event event;
-
 	while (SDL_PollEvent(&event))
 	{
 		if (event.type == SDL_WINDOWEVENT)
@@ -390,7 +387,7 @@
 		{
 			// text input when editing texts/numbers
 
-			inputChar = event.text.text[0];
+			char inputChar = event.text.text[0];
 			if (inputChar == '\0')
 				continue;
 
@@ -404,12 +401,12 @@
 		}
 		else if (event.type == SDL_DROPFILE)
 		{
-			loadDroppedFile(event.drop.file, (uint32_t)strlen(event.drop.file), false, true);
-			SDL_free(event.drop.file);
-
 			// kludge: allow focus-clickthrough after drag-n-drop
 			SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
 			didDropFile = true;
+
+			loadDroppedFile(event.drop.file, (uint32_t)strlen(event.drop.file), false, true);
+			SDL_free(event.drop.file);
 		}
 		if (event.type == SDL_QUIT)
 		{
@@ -417,7 +414,7 @@
 		}
 		else if (event.type == SDL_KEYUP)
 		{
-			keyUpHandler(event.key.keysym.scancode, event.key.keysym.sym);
+			keyUpHandler(event.key.keysym.scancode);
 		}
 		else if (event.type == SDL_KEYDOWN)
 		{
@@ -428,12 +425,12 @@
 		{
 			mouseButtonUpHandler(event.button.button);
 
-			if (!ui.askScreenShown && ui.introScreenShown)
+			if (ui.introTextShown)
 			{
-				if (!ui.clearScreenShown && !ui.diskOpScreenShown && !editor.errorMsgActive)
+				if (!ui.diskOpScreenShown && !editor.errorMsgActive && !ui.askBoxShown)
 					statusAllRight();
 
-				ui.introScreenShown = false;
+				ui.introTextShown = false;
 			}
 
 			// kludge: we drag-n-dropped a file before this mouse click release, restore focus-clickthrough mode
@@ -461,9 +458,10 @@
 				SDL_WaitThread(diskop.fillThread, NULL);
 			}
 
-			if (editor.isWAVRendering)
+			if (editor.mod2WavOngoing)
 			{
-				editor.isWAVRendering = false;
+				editor.mod2WavOngoing = false;
+
 				editor.abortMod2Wav = true;
 				SDL_WaitThread(editor.mod2WavThread, NULL);
 			}
@@ -536,7 +534,7 @@
 	editor.multiModeNext[1] = 3;
 	editor.multiModeNext[2] = 4;
 	editor.multiModeNext[3] = 1;
-	ui.introScreenShown = true;
+	ui.introTextShown = true;
 	editor.normalizeFiltersFlag = true;
 	editor.markStartOfs = -1;
 	ui.sampleMarkingPos = -1;
@@ -557,6 +555,8 @@
 	editor.metroChannelDisp = &editor.metroChannel;
 	editor.quantizeValueDisp = &config.quantizeValue;
 
+	editor.mod2WavFadeOutSeconds = 6;
+
 	editor.programRunning = true;
 	return true;
 
@@ -567,6 +567,15 @@
 
 static void handleSigTerm(void)
 {
+	if (editor.mod2WavOngoing)
+	{
+		editor.mod2WavOngoing = false;
+
+		editor.abortMod2Wav = true;
+		SDL_WaitThread(editor.mod2WavThread, NULL);
+		removeAskBox();
+	}
+
 	if (song->modified)
 	{
 		resetAllScreens();
@@ -578,12 +587,8 @@
 			SDL_RaiseWindow(video.window);
 		}
 
-		ui.askScreenShown = true;
-		ui.askScreenType = ASK_QUIT;
-
-		pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-		setStatusMessage("REALLY QUIT ?", NO_CARRY);
-		renderAskDialog();
+		if (askBox(ASKBOX_YES_NO, "REALLY QUIT ?"))
+			ui.throwExit = true;
 	}
 	else
 	{
@@ -595,21 +600,19 @@
 #ifdef __APPLE__
 static void osxSetDirToProgramDirFromArgs(char **argv)
 {
-	char *tmpPath;
-	int32_t i, tmpPathLen;
-
 	/* OS X/macOS: hackish way of setting the current working directory to the place where we double clicked
-	** on the icon (for protracker.ini loading) */
+	** on the icon (for protracker.ini loading)
+	*/
 
 	// if we launched from the terminal, argv[0][0] would be '.'
 	if (argv[0] != NULL && argv[0][0] == DIR_DELIMITER) // don't do the hack if we launched from the terminal
 	{
-		tmpPath = strdup(argv[0]);
+		char *tmpPath = strdup(argv[0]);
 		if (tmpPath != NULL)
 		{
 			// cut off program filename
-			tmpPathLen = strlen(tmpPath);
-			for (i = tmpPathLen-1; i >= 0; i--)
+			int32_t tmpPathLen = strlen(tmpPath);
+			for (int32_t i = tmpPathLen-1; i >= 0; i--)
 			{
 				if (tmpPath[i] == DIR_DELIMITER)
 				{
@@ -690,20 +693,20 @@
 static void makeSureDirIsProgramDir(void)
 {
 #ifndef _DEBUG
-	UNICHAR *allocPtr, *path;
-	int32_t i, pathLen;
+	int32_t i;
 
 	// this can return two paths in Windows, but first one is .exe path
-	path = GetCommandLineW();
+	UNICHAR *path = GetCommandLineW();
 	if (path == NULL)
 		return;
 
-	allocPtr = UNICHAR_STRDUP(path);
+	UNICHAR *allocPtr = UNICHAR_STRDUP(path);
 	if (allocPtr == NULL)
 		return; // out of memory (but it doesn't matter)
 
 	path = allocPtr;
-	pathLen = (int32_t)UNICHAR_STRLEN(path);
+
+	int32_t pathLen = (int32_t)UNICHAR_STRLEN(path);
 
 	// remove first "
 	if (path[0] == L'\"')
--- a/src/pt2_math.c
+++ b/src/pt2_math.c
@@ -1,27 +1,45 @@
 /* Approximation routines for sin/cos/sqrt/tan.
-** These should not be used in realtime, as they are too slow.
+** These are not really fast, and shouldn't be used when speed is important.
 */
 
 #include <stdint.h>
-#include <stdbool.h>
 #include <math.h>
 #include "pt2_math.h"
 
 static const double pi = PT2_PI;
 static const double twopi = PT2_TWO_PI;
-
 static const double four_over_pi = 4.0 / PT2_PI;
 static const double threehalfpi = (3.0 * PT2_PI) / 2.0;
 static const double halfpi = PT2_PI / 2.0;
 
+static double cosTaylorSeries(double x)
+{
+#define ITERATIONS 32 /* good enough... */
+
+	x = fmod(x, twopi);
+	if (x < 0.0)
+		x = -x;
+
+	double tmp = 1.0;
+	double sum = 1.0;
+
+	for (double i = 2.0; i <= ITERATIONS*2.0; i += 2.0)
+	{
+		tmp *= -(x*x) / (i * (i-1.0));
+		sum += tmp;
+	}
+
+	return sum;
+}
+
 static double tan_14s(double x)
 {
 	const double c1 = -34287.4662577359568109624;
 	const double c2 =   2566.7175462315050423295;
-	const double c3 = -   26.5366371951731325438;
+	const double c3 =    -26.5366371951731325438;
 	const double c4 = -43656.1579281292375769579;
 	const double c5 =  12244.4839556747426927793;
-	const double c6 = -  336.611376245464339493;
+	const double c6 =   -336.611376245464339493;
 
 	double x2 = x * x;
 	return x*(c1 + x2*(c2 + x2*c3))/(c4 + x2*(c5 + x2*(c6 + x2)));
@@ -59,26 +77,6 @@
 	}
  
 	return s;
-}
-
-static double cosTaylorSeries(double x)
-{
-#define ITERATIONS 32 /* good enough... */
-
-	x = fmod(x, twopi);
-	if (x < 0.0)
-		x = -x;
-
-	double tmp = 1.0;
-	double sum = 1.0;
-
-	for (double i = 2.0; i <= ITERATIONS*2.0; i += 2.0)
-	{
-		tmp *= -(x*x) / (i * (i-1.0));
-		sum += tmp;
-	}
-
-	return sum;
 }
 
 double pt2_cos(double x)
--- a/src/pt2_mod2wav.c
+++ b/src/pt2_mod2wav.c
@@ -7,26 +7,183 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <sys/stat.h> // stat()
-#include "pt2_header.h"
 #include "pt2_audio.h"
+#include "pt2_amigafilters.h"
 #include "pt2_mouse.h"
 #include "pt2_textout.h"
 #include "pt2_visuals.h"
 #include "pt2_mod2wav.h"
-#include "pt2_structs.h"
 #include "pt2_downsample2x.h"
+#include "pt2_config.h"
+#include "pt2_askbox.h"
+#include "pt2_replayer.h"
 
+#define FADEOUT_CHUNK_SAMPLES 16384
 #define TICKS_PER_RENDER_CHUNK 64
 
-// pt2_replayer.c
-void storeTempVariables(void);
-bool intMusic(void);
-// ---------------------
+static int16_t *mod2WavBuffer, fadeOutBuffer[FADEOUT_CHUNK_SAMPLES * 2];
+static char lastFilename[PATH_MAX + 1];
 
-static int16_t *mod2WavBuffer;
-
 static void calcMod2WavTotalRows(void);
 
+void mod2WavDrawFadeoutToggle(void)
+{
+	fillRect(143, 50, FONT_CHAR_W, FONT_CHAR_H, video.palette[PAL_GENBKG]);
+	if (editor.mod2WavFadeOut)
+		charOut(143, 50, 'X', video.palette[PAL_GENTXT]);
+}
+
+void mod2WavDrawFadeoutSeconds(void)
+{
+	fillRect(259, 61, FONT_CHAR_W*2, FONT_CHAR_H+1, video.palette[PAL_GENBKG]);
+	charOut(259, 62, '0' + ((editor.mod2WavFadeOutSeconds / 10) % 10), video.palette[PAL_GENTXT]);
+	charOut(267, 62, '0' + ( editor.mod2WavFadeOutSeconds       % 10), video.palette[PAL_GENTXT]);
+}
+
+void mod2WavDrawLoopCount(void)
+{
+	fillRect(259, 72, FONT_CHAR_W*2, FONT_CHAR_H+1, video.palette[PAL_GENBKG]);
+	charOut(259, 73, '0' + ((editor.mod2WavNumLoops / 10)  % 10), video.palette[PAL_GENTXT]);
+	charOut(267, 73, '0' + ( editor.mod2WavNumLoops        % 10), video.palette[PAL_GENTXT]);
+}
+
+void toggleMod2WavFadeout(void)
+{
+	editor.mod2WavFadeOut ^= 1;
+	mod2WavDrawFadeoutToggle();
+}
+
+void mod2WavFadeoutUp(void)
+{
+	if (editor.mod2WavFadeOutSeconds < 60)
+	{
+		editor.mod2WavFadeOutSeconds++;
+		mod2WavDrawFadeoutSeconds();
+	}
+}
+
+void mod2WavFadeoutDown(void)
+{
+	if (editor.mod2WavFadeOutSeconds > 1)
+	{
+		editor.mod2WavFadeOutSeconds--;
+		mod2WavDrawFadeoutSeconds();
+	}
+}
+
+void mod2WavLoopCountUp(void)
+{
+	if (editor.mod2WavNumLoops < 50)
+	{
+		editor.mod2WavNumLoops++;
+		mod2WavDrawLoopCount();
+	}
+}
+
+void mod2WavLoopCountDown(void)
+{
+	if (editor.mod2WavNumLoops > 0)
+	{
+		editor.mod2WavNumLoops--;
+		mod2WavDrawLoopCount();
+	}
+}
+
+void drawMod2WavProgressDialog(void)
+{
+	drawFramework3(120, 44, 200, 55);
+	textOut2(150, 53, "- RENDERING MODULE -");
+
+	const int32_t buttonW = (MOD2WAV_CANCEL_BTN_X2 - MOD2WAV_CANCEL_BTN_X1)+1;
+	const int32_t buttonH = (MOD2WAV_CANCEL_BTN_Y2 - MOD2WAV_CANCEL_BTN_Y1)+1;
+	drawButton1(MOD2WAV_CANCEL_BTN_X1, MOD2WAV_CANCEL_BTN_Y1, buttonW, buttonH, "CANCEL");
+}
+
+static void showMod2WavProgress(void)
+{
+	char percText[8];
+
+	if (song->rowsInTotal == 0)
+		return;
+
+	// render progress bar
+
+	int32_t percent = (song->rowsCounter * 100) / song->rowsInTotal;
+	if (percent > 100)
+		percent = 100;
+
+	const int32_t x = 130;
+	const int32_t y = 66;
+	const int32_t w = 180;
+	const int32_t h = 11;
+
+	// foreground (progress)
+	const int32_t progressBarWidth = (percent * w) / 100;
+	if (progressBarWidth > 0)
+		fillRect(x, y, progressBarWidth, h, video.palette[PAL_GENBKG2]); // foreground (progress)
+
+	// background
+	int32_t bgWidth = w - progressBarWidth;
+	if (bgWidth > 0)
+		fillRect(x+progressBarWidth, y, bgWidth, h, video.palette[PAL_BORDER]);
+
+	// draw percentage text
+	sprintf(percText, "%d%%", percent);
+	const int32_t percTextW = (int32_t)strlen(percText) * (FONT_CHAR_W-1);
+	textOutTight(x + ((w - percTextW) / 2), y + ((h - FONT_CHAR_H) / 2), percText, video.palette[PAL_GENTXT]);
+}
+
+static void resetAudio(void)
+{
+	setupAmigaFilters(audio.outputRate);
+	paulaSetOutputFrequency(audio.outputRate, audio.oversamplingFlag);
+	generateBpmTable(audio.outputRate, editor.timingMode == TEMPO_MODE_VBLANK);
+	clearMixerDownsamplerStates();
+	modSetTempo(song->currBPM, true); // update BPM (samples per tick) with the tracker's audio frequency
+}
+
+static void handleMod2WavEnd(void)
+{
+	pointerSetMode(POINTER_MODE_IDLE, DO_CARRY);
+
+	if (editor.abortMod2Wav)
+	{
+		displayErrorMsg("MOD2WAV ABORTED!");
+	}
+	else
+	{
+		displayMsg("MOD RENDERED!");
+		setMsgPointer();
+	}
+
+	removeAskBox();
+	resetAudio();
+
+	editor.mod2WavOngoing = false; // must be set before calling resetSong() !
+	resetSong();
+}
+
+void updateMod2WavDialog(void)
+{
+	if (ui.updateMod2WavDialog)
+	{
+		ui.updateMod2WavDialog = false;
+
+		if (editor.mod2WavOngoing)
+		{
+			if (ui.mod2WavFinished)
+			{
+				ui.mod2WavFinished = false;
+				handleMod2WavEnd();
+			}
+			else
+			{
+				showMod2WavProgress();
+			}
+		}
+	}
+}
+
 static int32_t SDLCALL mod2WavThreadFunc(void *ptr)
 {
 	wavHeader_t wavHeader;
@@ -41,7 +198,7 @@
 	uint8_t tickCounter = 8;
 	int64_t tickSampleCounter64 = 0;
 
-	clearMixerDownsamplerStates();
+	int8_t numLoops = editor.mod2WavNumLoops;
 
 	bool renderDone = false;
 	while (!renderDone)
@@ -52,7 +209,7 @@
 		int16_t *ptr16 = mod2WavBuffer;
 		for (uint32_t i = 0; i < TICKS_PER_RENDER_CHUNK; i++)
 		{
-			if (!editor.isWAVRendering || renderDone || editor.abortMod2Wav || !editor.songPlaying)
+			if (!editor.mod2WavOngoing || renderDone || editor.abortMod2Wav)
 			{
 				renderDone = true;
 				break;
@@ -61,7 +218,17 @@
 			if (tickSampleCounter64 <= 0) // new replayer tick
 			{
 				if (!intMusic())
-					renderDone = true; // this tick is the last tick
+				{
+					if (--numLoops < 0)
+					{
+						renderDone = true; // this tick is the last tick
+					}
+					else
+					{
+						// clear the "last visisted rows" table and let the song continue playing (loop)
+						memset(editor.rowVisitTable, 0, MOD_ORDERS * MOD_ROWS);
+					}
+				}
 
 				tickSampleCounter64 += audio.samplesPerTick64;
 			}
@@ -71,11 +238,10 @@
 			outputAudio(ptr16, remainingTick);
 			tickSampleCounter64 -= (int64_t)remainingTick << 32;
 
-			remainingTick *= 2; // stereo
 			samplesInChunk += remainingTick;
 			sampleCounter += remainingTick;
 
-			ptr16 += remainingTick;
+			ptr16 += remainingTick * 2;
 
 			if (++tickCounter >= 4)
 			{
@@ -86,9 +252,11 @@
 
 		// write buffer to disk
 		if (samplesInChunk > 0)
-			fwrite(mod2WavBuffer, sizeof (int16_t), samplesInChunk, f);
+			fwrite(mod2WavBuffer, sizeof (int16_t), samplesInChunk * 2, f);
 	}
 
+	uint32_t endOfDataOffset = ftell(f);
+
 	free(mod2WavBuffer);
 
 	if (sampleCounter & 1)
@@ -106,19 +274,57 @@
 	wavHeader.subchunk1Size = 16;
 	wavHeader.audioFormat = 1;
 	wavHeader.numChannels = 2;
-	wavHeader.sampleRate = audio.outputRate;
+	wavHeader.sampleRate = config.mod2WavOutputFreq;
 	wavHeader.bitsPerSample = 16;
 	wavHeader.byteRate = (wavHeader.sampleRate * wavHeader.numChannels * wavHeader.bitsPerSample) / 8;
 	wavHeader.blockAlign = (wavHeader.numChannels * wavHeader.bitsPerSample) / 8;
 	wavHeader.subchunk2ID = 0x61746164; // "data"
-	wavHeader.subchunk2Size = sampleCounter * sizeof (int16_t);
+	wavHeader.subchunk2Size = sampleCounter * sizeof (int16_t) * 2;
 
 	// write main header
 	fwrite(&wavHeader, sizeof (wavHeader_t), 1, f);
 	fclose(f);
 
-	clearMixerDownsamplerStates();
+	// apply fadeout (if enabled)
+	if (editor.mod2WavFadeOut)
+	{
+		uint32_t numFadeOutSamples = config.mod2WavOutputFreq * editor.mod2WavFadeOutSeconds;
+		if (numFadeOutSamples > sampleCounter)
+			numFadeOutSamples = sampleCounter;
 
+		f = fopen(lastFilename, "r+b");
+
+		const double dFadeOutDelta = 1.0 / numFadeOutSamples;
+		double dFadeOutVal = 1.0;
+
+		fseek(f, endOfDataOffset - (numFadeOutSamples * sizeof (int16_t) * 2), SEEK_SET);
+
+		uint32_t samplesLeft = numFadeOutSamples;
+		while (samplesLeft > 0)
+		{
+			uint32_t samplesTodo = FADEOUT_CHUNK_SAMPLES;
+			if (samplesTodo > samplesLeft)
+				samplesTodo = samplesLeft;
+
+			fread(fadeOutBuffer, sizeof (int16_t), samplesTodo * 2, f);
+			fseek(f, 0 - (samplesTodo * sizeof (int16_t) * 2), SEEK_CUR);
+
+			// apply fadeout
+			for (uint32_t i = 0; i < samplesTodo; i++)
+			{
+				fadeOutBuffer[(i*2)+0] = (int16_t)(fadeOutBuffer[(i*2)+0] * dFadeOutVal); // L
+				fadeOutBuffer[(i*2)+1] = (int16_t)(fadeOutBuffer[(i*2)+1] * dFadeOutVal); // R
+				dFadeOutVal -= dFadeOutDelta;
+			}
+
+			fwrite(fadeOutBuffer, sizeof (int16_t), samplesTodo * 2, f);
+
+			samplesLeft -= samplesTodo;
+		}
+
+		fclose(f);
+	}
+
 	ui.mod2WavFinished = true;
 	ui.updateMod2WavDialog = true;
 
@@ -125,35 +331,19 @@
 	return true;
 }
 
-bool renderToWav(char *fileName, bool checkIfFileExist)
+bool mod2WavRender(char *filename)
 {
-	FILE *fOut;
 	struct stat statBuffer;
 
-	if (checkIfFileExist)
-	{
-		if (stat(fileName, &statBuffer) == 0)
-		{
-			ui.askScreenShown = true;
-			ui.askScreenType = ASK_MOD2WAV_OVERWRITE;
+	lastFilename[0] = '\0';
 
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-			setStatusMessage("OVERWRITE FILE?", NO_CARRY);
-
-			renderAskDialog();
-
+	if (stat(filename, &statBuffer) == 0)
+	{
+		if (!askBox(ASKBOX_YES_NO, "OVERWRITE FILE?"))
 			return false;
-		}
 	}
 
-	if (ui.askScreenShown)
-	{
-		ui.askScreenShown = false;
-		ui.answerNo = false;
-		ui.answerYes = false;
-	}
-
-	fOut = fopen(fileName, "wb");
+	FILE *fOut = fopen(filename, "wb");
 	if (fOut == NULL)
 	{
 		displayErrorMsg("FILE I/O ERROR");
@@ -160,51 +350,51 @@
 		return false;
 	}
 
-	const int32_t lowestBPM = 32;
-	const int64_t maxSamplesToMix64 = audio.bpmTable[lowestBPM-32];
-	const int32_t maxSamplesToMix = ((TICKS_PER_RENDER_CHUNK * maxSamplesToMix64) + (1LL << 31)) >> 32; // ceil (rounded upwards)
+	strncpy(lastFilename, filename, PATH_MAX-1);
 
-	mod2WavBuffer = (int16_t *)malloc(maxSamplesToMix * (2 * sizeof (int16_t)));
+	const int32_t audioFrequency = config.mod2WavOutputFreq * 2; // *2 for oversampling
+	const uint32_t maxSamplesToMix = (int32_t)ceil(audioFrequency / (REPLAYER_MIN_BPM / 2.5));
+
+	mod2WavBuffer = (int16_t *)malloc(((TICKS_PER_RENDER_CHUNK * maxSamplesToMix) + 1) * sizeof (int16_t) * 2);
 	if (mod2WavBuffer == NULL)
 	{
+		fclose(fOut);
 		statusOutOfMemory();
 		return false;
 	}
 
+	editor.mod2WavOngoing = true; // set this first
+
+	// do some prep work
+	generateBpmTable(config.mod2WavOutputFreq, editor.timingMode == TEMPO_MODE_VBLANK);
+	setupAmigaFilters(config.mod2WavOutputFreq);
+	paulaSetOutputFrequency(config.mod2WavOutputFreq, AUDIO_2X_OVERSAMPLING);
 	storeTempVariables();
 	calcMod2WavTotalRows();
-	restartSong();
+	restartSong(); // this also updates BPM (samples per tick) with the MOD2WAV audio output rate
+	clearMixerDownsamplerStates();
 
-	editor.blockMarkFlag = false;
+	drawMod2WavProgressDialog();
+	editor.abortMod2Wav = false;
 
 	pointerSetMode(POINTER_MODE_MSG2, NO_CARRY);
 	setStatusMessage("RENDERING MOD...", NO_CARRY);
 
-	ui.disableVisualizer = true;
-	editor.isWAVRendering = true;
-	renderMOD2WAVDialog();
-
-	editor.abortMod2Wav = false;
-
-	modSetTempo(song->currBPM, true); // update BPM with MOD2WAV audio output rate
-
 	editor.mod2WavThread = SDL_CreateThread(mod2WavThreadFunc, NULL, fOut);
-	if (editor.mod2WavThread != NULL)
+	if (editor.mod2WavThread == NULL)
 	{
-		SDL_DetachThread(editor.mod2WavThread);
-	}
-	else
-	{
+		fclose(fOut);
 		free(mod2WavBuffer);
 
-		ui.disableVisualizer = false;
-		editor.isWAVRendering = false;
+		doStopIt(true);
 
-		displayErrorMsg("THREAD ERROR");
+		editor.mod2WavOngoing = false; // must be set before calling resetAudio()
+		resetAudio();
 
+		removeAskBox();
 		pointerSetMode(POINTER_MODE_IDLE, DO_CARRY);
-		statusAllRight();
 
+		displayErrorMsg("THREAD ERROR !");
 		return false;
 	}
 
@@ -211,39 +401,47 @@
 	return true;
 }
 
+#define CALC__END_OF_SONG \
+if (--numLoops < 0) \
+{ \
+	calcingRows = false; \
+	break; \
+} \
+else \
+{ \
+	memset(editor.rowVisitTable, 0, MOD_ORDERS * MOD_ROWS); \
+}
+
 // ONLY used for a visual percentage counter, so accuracy is not very important
 static void calcMod2WavTotalRows(void)
 {
-	bool pBreakFlag, posJumpAssert, calcingRows;
-	int8_t n_pattpos[AMIGA_VOICES], n_loopcount[AMIGA_VOICES];
-	uint8_t modRow, pBreakPosition, ch, pos;
-	int16_t modOrder;
-	uint16_t modPattern;
-	note_t *note;
+	int8_t n_pattpos[PAULA_VOICES], n_loopcount[PAULA_VOICES];
 
 	// for pattern loop
-	memset(n_pattpos, 0, sizeof (n_pattpos));
+	memset(n_pattpos,   0, sizeof (n_pattpos));
 	memset(n_loopcount, 0, sizeof (n_loopcount));
 
-	song->rowsCounter = 0;
-	song->rowsInTotal = 0;
+	song->rowsCounter = song->rowsInTotal  = 0;
 
-	modRow = 0;
-	modOrder = 0;
-	modPattern = song->header.order[0];
-	pBreakPosition = 0;
-	posJumpAssert = false;
-	pBreakFlag = false;
-	calcingRows = true;
+	uint8_t modRow = 0;
+	int16_t modOrder = 0;
+	uint16_t modPattern = song->header.order[0];
+	uint8_t pBreakPosition = 0;
+	bool posJumpAssert = false;
+	bool pBreakFlag = false;
 
 	memset(editor.rowVisitTable, 0, MOD_ORDERS * MOD_ROWS);
+
+	int8_t numLoops = editor.mod2WavNumLoops; // make a copy
+
+	bool calcingRows = true;
 	while (calcingRows)
 	{
 		editor.rowVisitTable[(modOrder * MOD_ROWS) + modRow] = true;
 
-		for (ch = 0; ch < AMIGA_VOICES; ch++)
+		for (int32_t ch = 0; ch < PAULA_VOICES; ch++)
 		{
-			note = &song->patterns[modPattern][(modRow * AMIGA_VOICES) + ch];
+			note_t *note = &song->patterns[modPattern][(modRow * PAULA_VOICES) + ch];
 			if (note->command == 0x0B) // Bxx - Position Jump
 			{
 				modOrder = note->param - 1;
@@ -260,12 +458,11 @@
 			}
 			else if (note->command == 0x0F && note->param == 0) // F00 - Set Speed 0 (stop)
 			{
-				calcingRows = false;
-				break;
+				CALC__END_OF_SONG
 			}
 			else if (note->command == 0x0E && (note->param >> 4) == 0x06) // E6x - Pattern Loop
 			{
-				pos = note->param & 0x0F;
+				uint8_t pos = note->param & 0x0F;
 				if (pos == 0)
 				{
 					n_pattpos[ch] = modRow;
@@ -307,12 +504,11 @@
 			pBreakPosition = 0;
 			posJumpAssert = false;
 
-			modOrder = (modOrder + 1) & 0x7F;
+			modOrder = (modOrder + 1) & 127;
 			if (modOrder >= song->header.numOrders)
 			{
 				modOrder = 0;
-				calcingRows = false;
-				break;
+				CALC__END_OF_SONG
 			}
 
 			modPattern = song->header.order[modOrder];
@@ -320,11 +516,10 @@
 				modPattern = MAX_PATTERNS-1;
 		}
 
-		if (editor.rowVisitTable[(modOrder * MOD_ROWS) + modRow])
+		if (calcingRows && editor.rowVisitTable[(modOrder * MOD_ROWS) + modRow])
 		{
 			// row has been visited before, we're now done!
-			calcingRows = false;
-			break;
+			CALC__END_OF_SONG
 		}
 	}
 }
--- a/src/pt2_mod2wav.h
+++ b/src/pt2_mod2wav.h
@@ -2,4 +2,19 @@
 
 #include <stdbool.h>
 
-bool renderToWav(char *fileName, bool checkIfFileExist);
+#define MOD2WAV_CANCEL_BTN_X1 193
+#define MOD2WAV_CANCEL_BTN_X2 247
+#define MOD2WAV_CANCEL_BTN_Y1 81
+#define MOD2WAV_CANCEL_BTN_Y2 92
+
+void mod2WavDrawFadeoutToggle(void);
+void mod2WavDrawFadeoutSeconds(void);
+void mod2WavDrawLoopCount(void);
+void toggleMod2WavFadeout(void);
+void mod2WavFadeoutUp(void);
+void mod2WavFadeoutDown(void);
+void mod2WavLoopCountUp(void);
+void mod2WavLoopCountDown(void);
+
+void updateMod2WavDialog(void);
+bool mod2WavRender(char *filename);
--- a/src/pt2_module_loader.c
+++ b/src/pt2_module_loader.c
@@ -16,19 +16,17 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "pt2_mouse.h"
-#include "pt2_header.h"
-#include "pt2_config.h"
 #include "pt2_sampler.h"
+#include "pt2_replayer.h"
 #include "pt2_textout.h"
 #include "pt2_audio.h"
+#include "pt2_amigafilters.h"
 #include "pt2_helpers.h"
 #include "pt2_visuals.h"
-#include "pt2_unicode.h"
-#include "pt2_module_loader.h"
 #include "pt2_sample_loader.h"
 #include "pt2_config.h"
-#include "pt2_sampling.h"
 #include "pt2_xpk.h"
+#include "pt2_askbox.h"
 
 typedef struct mem_t
 {
@@ -37,10 +35,7 @@
 	uint32_t _cnt, _bufsiz;
 } MEMFILE;
 
-static bool oldAutoPlay;
-static char oldFullPath[(PATH_MAX * 2) + 2];
 static int32_t realSampleLengths[MOD_SAMPLES];
-static uint32_t oldFullPathLen;
 
 static MEMFILE *mopen(const uint8_t *src, uint32_t length);
 static void mclose(MEMFILE **buf);
@@ -50,16 +45,6 @@
 static void mrewind(MEMFILE *buf);
 static uint8_t ppdecrunch(uint8_t *src, uint8_t *dst, uint8_t *offsetLens, uint32_t srcLen, uint32_t dstLen, uint8_t skipBits);
 
-void showSongUnsavedAskBox(int8_t askScreenType)
-{
-	ui.askScreenShown = true;
-	ui.askScreenType = askScreenType;
-
-	pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-	setStatusMessage("SONG IS UNSAVED !", NO_CARRY);
-	renderAskDialog();
-}
-
 #define IS_ID(s, b) !strncmp(s, b, 4)
 
 static uint8_t getModType(uint8_t *numChannels, const char *id)
@@ -167,28 +152,19 @@
 
 module_t *modLoad(UNICHAR *fileName)
 {
-	bool mightBeSTK, lateSTKVerFlag, veryLateSTKVerFlag;
-	char modID[4], tmpChar;
-	int8_t numSamples;
-	uint8_t bytes[4], restartPos, modFormat;
-	uint8_t *modBuffer, numChannels;
-	int32_t i, j, k, loopStart, loopLength, loopOverflowVal, numPatterns;
-	uint32_t powerPackerID, filesize;
-	FILE *f;
-	MEMFILE *m;
-	module_t *newMod;
-	moduleSample_t *s;
-	note_t *note;
+	char modID[4];
+	uint8_t numChannels;
+	uint32_t powerPackerID;
 
-	veryLateSTKVerFlag = false; // "DFJ SoundTracker III" and later
-	lateSTKVerFlag = false; // "TJC SoundTracker II" and later
-	mightBeSTK = false;
+	bool veryLateSTKVerFlag = false; // "DFJ SoundTracker III" and later
+	bool lateSTKVerFlag = false; // "TJC SoundTracker II" and later
+	bool mightBeSTK = false;
 
-	m = NULL;
-	f = NULL;
-	modBuffer = NULL;
+	MEMFILE *m = NULL;
+	FILE *f = NULL;
+	uint8_t *modBuffer = NULL;
 
-	newMod = (module_t *)calloc(1, sizeof (module_t));
+	module_t *newMod = (module_t *)calloc(1, sizeof (module_t));
 	if (newMod == NULL)
 	{
 		statusOutOfMemory();
@@ -203,7 +179,7 @@
 	}
 
 	fseek(f, 0, SEEK_END);
-	filesize = ftell(f);
+	uint32_t filesize = ftell(f);
 	rewind(f);
 
 	// check if mod is a powerpacker mod
@@ -240,7 +216,6 @@
 		else
 		{
 			modBuffer = (uint8_t *)malloc(filesize);
-
 			if (modBuffer == NULL)
 			{
 				statusOutOfMemory();
@@ -274,8 +249,8 @@
 	mseek(m, 1080, SEEK_SET);
 	mread(modID, 1, 4, m);
 
-	modFormat = getModType(&numChannels, modID);
-	if (numChannels == 0 || numChannels > AMIGA_VOICES)
+	uint8_t modFormat = getModType(&numChannels, modID);
+	if (numChannels == 0 || numChannels > PAULA_VOICES)
 	{
 		displayErrorMsg("UNSUPPORTED MOD !");
 		goto modLoadError;
@@ -289,9 +264,9 @@
 	newMod->header.name[20] = '\0';
 
 	// convert illegal song name characters to space
-	for (i = 0; i < 20; i++)
+	for (int32_t i = 0; i < 20; i++)
 	{
-		tmpChar = newMod->header.name[i];
+		char tmpChar = newMod->header.name[i];
 		if ((tmpChar < ' ' || tmpChar > '~') && tmpChar != '\0')
 			tmpChar = ' ';
 
@@ -301,8 +276,8 @@
 	fixZeroesInString(newMod->header.name, 20);
 
 	// read sample headers
-	s = newMod->samples;
-	for (i = 0; i < MOD_SAMPLES; i++, s++)
+	moduleSample_t *s = newMod->samples;
+	for (int32_t i = 0; i < MOD_SAMPLES; i++, s++)
 	{
 		if (mightBeSTK && i >= 15) // skip reading sample headers past sample slot 15 in STK/UST modules
 		{
@@ -321,9 +296,9 @@
 		else
 		{
 			// convert illegal sample name characters to space
-			for (j = 0; j < 22; j++)
+			for (int32_t j = 0; j < 22; j++)
 			{
-				tmpChar = s->text[j];
+				char tmpChar = s->text[j];
 				if ((tmpChar < ' ' || tmpChar > '~') && tmpChar != '\0')
 					tmpChar = ' ';
 
@@ -354,8 +329,8 @@
 		if ((uint8_t)s->volume > 64)
 			s->volume = 64;
 
-		loopStart = ((mgetc(m) << 8) | mgetc(m)) * 2;
-		loopLength = ((mgetc(m) << 8) | mgetc(m)) * 2;
+		int32_t loopStart = ((mgetc(m) << 8) | mgetc(m)) * 2;
+		int32_t loopLength = ((mgetc(m) << 8) | mgetc(m)) * 2;
 
 		if (loopLength < 2)
 			loopLength = 2; // fixes empty samples in .MODs saved from FT2
@@ -401,7 +376,7 @@
 		goto modLoadError;
 	}
 
-	restartPos = (uint8_t)mgetc(m);
+	uint8_t restartPos = (uint8_t)mgetc(m);
 	if (mightBeSTK && restartPos > 220)
 	{
 		displayErrorMsg("NOT A MOD FILE !");
@@ -439,8 +414,8 @@
 	}
 
 	// read orders and count number of patterns
-	numPatterns = 0;
-	for (i = 0; i < MOD_ORDERS; i++)
+	int32_t numPatterns = 0;
+	for (int32_t i = 0; i < MOD_ORDERS; i++)
 	{
 		newMod->header.order[i] = (int16_t)mgetc(m);
 		if (newMod->header.order[i] > numPatterns)
@@ -459,9 +434,9 @@
 		mseek(m, 4, SEEK_CUR);
 
 	// allocate 100 patterns
-	for (i = 0; i < MAX_PATTERNS; i++)
+	for (int32_t i = 0; i < MAX_PATTERNS; i++)
 	{
-		newMod->patterns[i] = (note_t *)calloc(MOD_ROWS * AMIGA_VOICES, sizeof (note_t));
+		newMod->patterns[i] = (note_t *)calloc(MOD_ROWS * PAULA_VOICES, sizeof (note_t));
 		if (newMod->patterns[i] == NULL)
 		{
 			statusOutOfMemory();
@@ -470,13 +445,14 @@
 	}
 
 	// load pattern data
-	for (i = 0; i < numPatterns; i++)
+	for (int32_t i = 0; i < numPatterns; i++)
 	{
-		note = newMod->patterns[i];
-		for (j = 0; j < MOD_ROWS; j++)
+		note_t *note = newMod->patterns[i];
+		for (int32_t j = 0; j < MOD_ROWS; j++)
 		{
-			for (k = 0; k < numChannels; k++, note++)
+			for (int32_t k = 0; k < numChannels; k++, note++)
 			{
+				uint8_t bytes[4];
 				mread(bytes, 1, 4, m);
 
 				note->period = ((bytes[0] & 0x0F) << 8) | bytes[1];
@@ -501,8 +477,8 @@
 				}
 			}
 
-			if (numChannels < AMIGA_VOICES)
-				note += AMIGA_VOICES-numChannels;
+			if (numChannels < PAULA_VOICES)
+				note += PAULA_VOICES-numChannels;
 		}
 	}
 
@@ -509,10 +485,10 @@
 	// pattern command conversion for non-PT formats
 	if (modFormat == FORMAT_STK || modFormat == FORMAT_FT2 || modFormat == FORMAT_NT || modFormat == FORMAT_HMNT || modFormat == FORMAT_FLT)
 	{
-		for (i = 0; i < numPatterns; i++)
+		for (int32_t i = 0; i < numPatterns; i++)
 		{
-			note = newMod->patterns[i];
-			for (j = 0; j < MOD_ROWS*4; j++, note++)
+			note_t *note = newMod->patterns[i];
+			for (int32_t j = 0; j < MOD_ROWS*4; j++, note++)
 			{
 				if (modFormat == FORMAT_NT || modFormat == FORMAT_HMNT)
 				{
@@ -617,13 +593,13 @@
 	}
 
 	// set sample data offsets (sample data = one huge buffer to rule them all)
-	for (i = 0; i < MOD_SAMPLES; i++)
+	for (int32_t i = 0; i < MOD_SAMPLES; i++)
 		newMod->samples[i].offset = config.maxSampleLength * i;
 
 	// load sample data
-	numSamples = (modFormat == FORMAT_STK) ? 15 : 31;
+	int32_t numSamples = (modFormat == FORMAT_STK) ? 15 : 31;
 	s = newMod->samples;
-	for (i = 0; i < numSamples; i++, s++)
+	for (int32_t i = 0; i < numSamples; i++, s++)
 	{
 		/* For Ultimate SoundTracker modules, only the loop area of a looped sample is played.
 		** Skip loading of eventual data present before loop start.
@@ -664,7 +640,7 @@
 		// some modules are broken like this, adjust sample length if possible (this is ok if we have room)
 		if (s->length > 0 && s->loopLength > 2 && s->loopStart+s->loopLength > s->length)
 		{
-			loopOverflowVal = (s->loopStart + s->loopLength) - s->length;
+			int32_t loopOverflowVal = (s->loopStart + s->loopLength) - s->length;
 			if (s->length+loopOverflowVal <= config.maxSampleLength)
 			{
 				s->length += loopOverflowVal; // this is safe, we're allocating 65534 bytes per sample slot
@@ -680,8 +656,7 @@
 	mclose(&m);
 	free(modBuffer);
 
-	for (i = 0; i < AMIGA_VOICES; i++)
-		newMod->channels[i].n_chanindex = (int8_t)i;
+	initializeModuleChannels(newMod);
 
 	return newMod;
 
@@ -694,7 +669,7 @@
 
 	if (newMod != NULL)
 	{
-		for (i = 0; i < MAX_PATTERNS; i++)
+		for (int32_t i = 0; i < MAX_PATTERNS; i++)
 		{
 			if (newMod->patterns[i] != NULL)
 				free(newMod->patterns[i]);
@@ -708,12 +683,10 @@
 
 static MEMFILE *mopen(const uint8_t *src, uint32_t length)
 {
-	MEMFILE *b;
-
 	if (src == NULL || length == 0)
 		return NULL;
 
-	b = (MEMFILE *)malloc(sizeof (MEMFILE));
+	MEMFILE *b = (MEMFILE *)malloc(sizeof (MEMFILE));
 	if (b == NULL)
 		return NULL;
 
@@ -737,12 +710,10 @@
 
 static int32_t mgetc(MEMFILE *buf)
 {
-	int32_t b;
-
 	if (buf == NULL || buf->_ptr == NULL || buf->_cnt <= 0)
 		return 0;
 
-	b = *buf->_ptr;
+	int32_t b = *buf->_ptr;
 
 	buf->_cnt--;
 	buf->_ptr++;
@@ -759,17 +730,14 @@
 
 static size_t mread(void *buffer, size_t size, size_t count, MEMFILE *buf)
 {
-	int32_t pcnt;
-	size_t wrcnt;
-
 	if (buf == NULL || buf->_ptr == NULL)
 		return 0;
 
-	wrcnt = size * count;
+	size_t wrcnt = size * count;
 	if (size == 0 || buf->_eof)
 		return 0;
 
-	pcnt = (buf->_cnt > (uint32_t)wrcnt) ? (uint32_t)wrcnt : buf->_cnt;
+	int32_t pcnt = (buf->_cnt > (uint32_t)wrcnt) ? (uint32_t)wrcnt : buf->_cnt;
 	memcpy(buffer, buf->_ptr, pcnt);
 
 	buf->_cnt -= pcnt;
@@ -842,18 +810,18 @@
 
 static uint8_t ppdecrunch(uint8_t *src, uint8_t *dst, uint8_t *offsetLens, uint32_t srcLen, uint32_t dstLen, uint8_t skipBits)
 {
-	uint8_t *bufSrc, *dstEnd, *out, bitsLeft, bitCnt;
-	uint32_t x, todo, offBits, offset, written, bitBuffer;
+	uint8_t bitCnt;
+	uint32_t x, todo, offset;
 
 	if (src == NULL || dst == NULL || offsetLens == NULL)
 		return false;
 
-	bitsLeft = 0;
-	bitBuffer = 0;
-	written = 0;
-	bufSrc = src + srcLen;
-	out = dst + dstLen;
-	dstEnd = out;
+	uint8_t bitsLeft = 0;
+	uint32_t bitBuffer = 0;
+	uint32_t written = 0;
+	uint8_t *bufSrc = src + srcLen;
+	uint8_t *out = dst + dstLen;
+	uint8_t *dstEnd = out;
 
 	PP_READ_BITS(skipBits, x);
 	while (written < dstLen)
@@ -885,7 +853,7 @@
 		}
 
 		PP_READ_BITS(2, x);
-		offBits = offsetLens[x];
+		uint32_t offBits = offsetLens[x];
 		todo = x + 2;
 
 		if (x == 3)
@@ -925,10 +893,8 @@
 
 void setupLoadedMod(void)
 {
-	int8_t i;
-
 	// setup GUI text pointers
-	for (i = 0; i < MOD_SAMPLES; i++)
+	for (int32_t i = 0; i < MOD_SAMPLES; i++)
 	{
 		song->samples[i].volumeDisp = &song->samples[i].volume;
 		song->samples[i].lengthDisp = &song->samples[i].length;
@@ -935,7 +901,7 @@
 		song->samples[i].loopStartDisp = &song->samples[i].loopStart;
 		song->samples[i].loopLengthDisp = &song->samples[i].loopLength;
 
-		fillSampleRedoBuffer(i);
+		fillSampleRedoBuffer((uint8_t)i);
 	}
 
 	modSetPos(0, 0);
@@ -963,7 +929,9 @@
 	editor.sampleZero = false;
 	editor.hiLowInstr = 0;
 
-	setLEDFilter(false, false); // real PT doesn't do this, but that's insane
+	// disable LED filter after module load (real PT doesn't do this)
+	editor.useLEDFilter = false;
+	setLEDFilter(false);
 
 	updateWindowTitle(MOD_NOT_MODIFIED);
 
@@ -980,15 +948,12 @@
 
 void loadModFromArg(char *arg)
 {
-	uint32_t filenameLen;
-	UNICHAR *filenameU;
-
-	ui.introScreenShown = false;
+	ui.introTextShown = false;
 	statusAllRight();
 
-	filenameLen = (uint32_t)strlen(arg);
+	uint32_t filenameLen = (uint32_t)strlen(arg);
 
-	filenameU = (UNICHAR *)calloc(filenameLen + 2, sizeof (UNICHAR));
+	UNICHAR *filenameU = (UNICHAR *)calloc(filenameLen + 2, sizeof (UNICHAR));
 	if (filenameU == NULL)
 	{
 		statusOutOfMemory();
@@ -1026,20 +991,20 @@
 static bool testExtension(char *ext, uint8_t extLen, char *fullPath)
 {
 	// checks for EXT.filename and filename.EXT
-	char *fileName, begStr[8], endStr[8];
-	uint32_t fileNameLen;
 
 	extLen++; // add one to length (dot)
 
-	fileName = strrchr(fullPath, DIR_DELIMITER);
+	char *fileName = strrchr(fullPath, DIR_DELIMITER);
 	if (fileName != NULL)
 		fileName++;
 	else
 		fileName = fullPath;
 
-	fileNameLen = (uint32_t)strlen(fileName);
+	uint32_t fileNameLen = (uint32_t)strlen(fileName);
 	if (fileNameLen >= extLen)
 	{
+		char begStr[8], endStr[8];
+
 		sprintf(begStr, "%s.", ext);
 		if (!_strnicmp(begStr, fileName, extLen))
 			return true;
@@ -1054,20 +1019,15 @@
 
 void loadDroppedFile(char *fullPath, uint32_t fullPathLen, bool autoPlay, bool songModifiedCheck)
 {
-	bool isMod;
-	char *fileName, *ansiName;
-	uint8_t oldMode, oldPlayMode;
-	UNICHAR *fullPathU;
-
 	// don't allow drag n' drop if the tracker is busy
 	if (ui.pointerMode == POINTER_MODE_MSG1 || diskop.isFilling ||
-		editor.isWAVRendering || editor.isSMPRendering ||
+		editor.mod2WavOngoing || editor.pat2SmpOngoing ||
 		ui.samplerFiltersBoxShown || ui.samplerVolBoxShown || ui.samplingBoxShown)
 	{
 		return;
 	}
 
-	ansiName = (char *)calloc(fullPathLen + 10, sizeof (char));
+	char *ansiName = (char *)calloc(fullPathLen + 10, sizeof (char));
 	if (ansiName == NULL)
 	{
 		statusOutOfMemory();
@@ -1074,7 +1034,7 @@
 		return;
 	}
 
-	fullPathU = (UNICHAR *)calloc(fullPathLen + 2, sizeof (UNICHAR));
+	UNICHAR *fullPathU = (UNICHAR *)calloc(fullPathLen + 2, sizeof (UNICHAR));
 	if (fullPathU == NULL)
 	{
 		free(ansiName);
@@ -1091,7 +1051,7 @@
 	unicharToAnsi(ansiName, fullPathU, fullPathLen);
 
 	// make a new pointer point to filename (strip path)
-	fileName = strrchr(ansiName, DIR_DELIMITER);
+	char *fileName = strrchr(ansiName, DIR_DELIMITER);
 	if (fileName != NULL)
 		fileName++;
 	else
@@ -1098,7 +1058,7 @@
 		fileName = ansiName;
 
 	// check if the file extension is a module (FIXME: check module by content instead..?)
-	isMod = false;
+	bool isMod = false;
 	     if (testExtension("MOD", 3, fileName)) isMod = true;
 	else if (testExtension("M15", 3, fileName)) isMod = true;
 	else if (testExtension("STK", 3, fileName)) isMod = true;
@@ -1111,29 +1071,19 @@
 	{
 		if (songModifiedCheck && song->modified)
 		{
-			free(ansiName);
-			free(fullPathU);
-
-			memcpy(oldFullPath, fullPath, fullPathLen);
-			oldFullPath[fullPathLen+0] = 0;
-			oldFullPath[fullPathLen+1] = 0;
-
-			oldFullPathLen = fullPathLen;
-			oldAutoPlay = autoPlay;
-
 			// de-minimize window and set focus so that the user sees the message box
 			SDL_RestoreWindow(video.window);
 			SDL_RaiseWindow(video.window);
 
-			showSongUnsavedAskBox(ASK_DISCARD_SONG_DRAGNDROP);
-			return;
+			if (!askBox(ASKBOX_YES_NO, "SONG IS UNSAVED !"))
+				goto DropExit;
 		}
 
 		module_t *newSong = modLoad(fullPathU);
 		if (newSong != NULL)
 		{
-			oldMode = editor.currMode;
-			oldPlayMode = editor.playMode;
+			uint8_t oldMode = editor.currMode;
+			uint8_t oldPlayMode = editor.playMode;
 
 			modStop();
 			modFree();
@@ -1193,27 +1143,20 @@
 		loadSample(fullPathU, fileName);
 	}
 
+DropExit:
 	free(ansiName);
 	free(fullPathU);
 }
 
-void loadDroppedFile2(void)
-{
-	loadDroppedFile(oldFullPath, oldFullPathLen, oldAutoPlay, false);
-}
-
 module_t *createEmptyMod(void)
 {
-	uint8_t i;
-	module_t *newMod;
-
-	newMod = (module_t *)calloc(1, sizeof (module_t));
+	module_t *newMod = (module_t *)calloc(1, sizeof (module_t));
 	if (newMod == NULL)
 		goto oom;
 
-	for (i = 0; i < MAX_PATTERNS; i++)
+	for (int32_t i = 0; i < MAX_PATTERNS; i++)
 	{
-		newMod->patterns[i] = (note_t *)calloc(1, MOD_ROWS * sizeof (note_t) * AMIGA_VOICES);
+		newMod->patterns[i] = (note_t *)calloc(1, MOD_ROWS * sizeof (note_t) * PAULA_VOICES);
 		if (newMod->patterns[i] == NULL)
 			goto oom;
 	}
@@ -1225,7 +1168,7 @@
 	newMod->header.numOrders = 1;
 
 	moduleSample_t *s = newMod->samples;
-	for (i = 0; i < MOD_SAMPLES; i++, s++)
+	for (int32_t i = 0; i < MOD_SAMPLES; i++, s++)
 	{
 		s->offset = config.maxSampleLength * i;
 		s->loopLength = 2;
@@ -1237,8 +1180,7 @@
 		s->loopLengthDisp = &s->loopLength;
 	}
 
-	for (i = 0; i < AMIGA_VOICES; i++)
-		newMod->channels[i].n_chanindex = i;
+	initializeModuleChannels(newMod);
 
 	// setup GUI text pointers
 	editor.currEditPatternDisp = &newMod->currPattern;
--- a/src/pt2_module_loader.h
+++ b/src/pt2_module_loader.h
@@ -6,10 +6,8 @@
 #include "pt2_unicode.h"
 #include "pt2_structs.h"
 
-void showSongUnsavedAskBox(int8_t askScreenType);
 void loadModFromArg(char *arg);
 void loadDroppedFile(char *fullPath, uint32_t fullPathLen, bool autoPlay, bool songModifiedCheck);
-void loadDroppedFile2(void);
 module_t *createEmptyMod(void);
 module_t *modLoad(UNICHAR *fileName);
 void setupLoadedMod(void);
--- a/src/pt2_module_saver.c
+++ b/src/pt2_module_saver.c
@@ -1,8 +1,3 @@
-// for finding memory leaks in debug mode with Visual Studio 
-#if defined _DEBUG && defined _MSC_VER
-#include <crtdbg.h>
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -9,19 +4,15 @@
 #include <stdbool.h>
 #include <sys/stat.h>
 #include "pt2_mouse.h"
-#include "pt2_header.h"
 #include "pt2_textout.h"
 #include "pt2_helpers.h"
-#include "pt2_visuals.h"
 #include "pt2_sampler.h"
 #include "pt2_config.h"
+#include "pt2_askbox.h"
 
 bool modSave(char *fileName)
 {
-	int32_t i, j;
-	FILE *f;
-
-	f = fopen(fileName, "wb");
+	FILE *f = fopen(fileName, "wb");
 	if (f == NULL)
 	{
 		displayErrorMsg("FILE I/O ERROR !");
@@ -30,7 +21,7 @@
 
 	fwrite(song->header.name, 1, 20, f);
 
-	for (i = 0; i < MOD_SAMPLES; i++)
+	for (int32_t i = 0; i < MOD_SAMPLES; i++)
 	{
 		moduleSample_t *s = &song->samples[i];
 
@@ -64,11 +55,11 @@
 	fputc((uint8_t)song->header.numOrders, f);
 	fputc(0x7F, f); // ProTracker puts 0x7F at this place (restartPos/tempo in other trackers)
 
-	for (i = 0; i < MOD_ORDERS; i++)
+	for (int32_t i = 0; i < MOD_ORDERS; i++)
 		fputc((uint8_t)song->header.order[i], f);
 
 	int32_t numPatterns = 0;
-	for (i = 0; i < MOD_ORDERS; i++)
+	for (int32_t i = 0; i < MOD_ORDERS; i++)
 	{
 		if (song->header.order[i] > numPatterns)
 			numPatterns = song->header.order[i];
@@ -80,10 +71,10 @@
 
 	fwrite((numPatterns <= 64) ? "M.K." : "M!K!", 1, 4, f);
 
-	for (i = 0; i < numPatterns; i++)
+	for (int32_t i = 0; i < numPatterns; i++)
 	{
 		note_t *note = song->patterns[i];
-		for (j = 0; j < MOD_ROWS * AMIGA_VOICES; j++, note++)
+		for (int32_t j = 0; j < MOD_ROWS * PAULA_VOICES; j++, note++)
 		{
 			fputc((note->sample & 0xF0) | (note->period >> 8), f);
 			fputc(note->period & 0xFF, f);
@@ -92,12 +83,12 @@
 		}
 	}
 
-	for (i = 0; i < MOD_SAMPLES; i++)
+	for (int32_t i = 0; i < MOD_SAMPLES; i++)
 	{
 		moduleSample_t *s = &song->samples[i];
 		const int8_t *smpPtr8 = &song->sampleData[s->offset];
 
-		// clear first two bytes of non-looping samples (prevents stuck "BEEEEEP")
+		// clear first two bytes of non-looping samples (prevents stuck beep)
 		if (s->length >= 2 && s->loopStart+s->loopLength == 2)
 		{
 			fputc(0, f);
@@ -127,7 +118,6 @@
 bool saveModule(bool checkIfFileExist, bool giveNewFreeFilename)
 {
 	char fileName[128], tmpBuffer[64];
-	int32_t i, j;
 	struct stat statBuffer;
 
 	memset(tmpBuffer, 0, sizeof (tmpBuffer));
@@ -143,7 +133,7 @@
 		else
 		{
 			strcat(fileName, "mod.");
-			for (i = 4; i < 20+4; i++)
+			for (int32_t i = 4; i < 20+4; i++)
 			{
 				fileName[i] = (char)tolower(song->header.name[i-4]);
 				if (fileName[i] == '\0') break;
@@ -160,7 +150,7 @@
 		}
 		else
 		{
-			for (i = 0; i < 20; i++)
+			for (int32_t i = 0; i < 20; i++)
 			{
 				fileName[i] = (char)tolower(song->header.name[i]);
 				if (fileName[i] == '\0') break;
@@ -172,7 +162,7 @@
 
 	if (giveNewFreeFilename && stat(fileName, &statBuffer) == 0)
 	{
-		for (i = 1; i <= 999; i++)
+		for (int32_t i = 1; i <= 999; i++)
 		{
 			if (config.modDot)
 			{
@@ -183,7 +173,7 @@
 				}
 				else
 				{
-					for (j = 0; j < 20; j++)
+					for (int32_t j = 0; j < 20; j++)
 					{
 						tmpBuffer[j] = (char)tolower(song->header.name[j]);
 						if (tmpBuffer[j] == '\0') break;
@@ -201,7 +191,7 @@
 				}
 				else
 				{
-					for (j = 0; j < 20; j++)
+					for (int32_t j = 0; j < 20; j++)
 					{
 						tmpBuffer[j] = (char)tolower(song->header.name[j]);
 						if (tmpBuffer[j] == '\0') break;
@@ -218,21 +208,9 @@
 
 	if (checkIfFileExist && stat(fileName, &statBuffer) == 0)
 	{
-		ui.askScreenShown = true;
-		ui.askScreenType = ASK_SAVEMOD_OVERWRITE;
-		pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-		setStatusMessage("OVERWRITE FILE ?", NO_CARRY);
-		renderAskDialog();
-		return -1;
+		if (!askBox(ASKBOX_YES_NO, "OVERWRITE FILE ?"))
+			return false;
 	}
 
-	if (ui.askScreenShown)
-	{
-		ui.answerNo = false;
-		ui.answerYes = false;
-		ui.askScreenShown = false;
-	}
-
 	return modSave(fileName);
 }
-
--- a/src/pt2_module_saver.h
+++ b/src/pt2_module_saver.h
@@ -3,4 +3,5 @@
 #include <stdbool.h>
 
 bool saveModule(bool checkIfFileExist, bool giveNewFreeFilename);
-bool modSave(char *fileName);
+
+bool modSave(char *fileName); // used by saveModule() and crash handler
--- a/src/pt2_mouse.c
+++ b/src/pt2_mouse.c
@@ -9,14 +9,12 @@
 #include <unistd.h>
 #endif
 #include <stdio.h>
-#include "pt2_header.h"
-#include "pt2_mouse.h"
 #include "pt2_helpers.h"
 #include "pt2_diskop.h"
 #include "pt2_sampler.h"
-#include "pt2_module_loader.h"
+#include "pt2_module_saver.h"
 #include "pt2_edit.h"
-#include "pt2_sample_loader.h"
+#include "pt2_sample_saver.h"
 #include "pt2_visuals.h"
 #include "pt2_tables.h"
 #include "pt2_audio.h"
@@ -26,57 +24,45 @@
 #include "pt2_bmp.h"
 #include "pt2_sampling.h"
 #include "pt2_chordmaker.h"
+#include "pt2_pat2smp.h"
+#include "pt2_mod2wav.h"
+#include "pt2_askbox.h"
+#include "pt2_replayer.h"
 
-/* TODO: Move irrelevant routines outta here! Disgusting design!
-** Keep in mind that this was programmed in my early programming days...
-**/
+SDL_Cursor *cursors[NUM_CURSORS]; // globalized
 
-SDL_Cursor *cursors[NUM_CURSORS];
-
-void edNote1UpButton(void);
-void edNote1DownButton(void);
-void edNote2UpButton(void);
-void edNote2DownButton(void);
-void edNote3UpButton(void);
-void edNote3DownButton(void);
-void edNote4UpButton(void);
-void edNote4DownButton(void);
-void edPosUpButton(bool fast);
-void edPosDownButton(bool fast);
-void edModUpButton(void);
-void edModDownButton(void);
-void edVolUpButton(void);
-void edVolDownButton(void);
-void sampleUpButton(void);
-void sampleDownButton(void);
-void sampleFineTuneUpButton(void);
-void sampleFineTuneDownButton(void);
-void sampleVolumeUpButton(void);
-void sampleVolumeDownButton(void);
-void sampleLengthUpButton(bool fast);
-void sampleLengthDownButton(bool fast);
-void sampleRepeatUpButton(bool fast);
-void sampleRepeatDownButton(bool fast);
-void sampleRepeatLengthUpButton(bool fast);
-void sampleRepeatLengthDownButton(bool fast);
-void tempoUpButton(void);
-void tempoDownButton(void);
-void songLengthUpButton(void);
-void songLengthDownButton(void);
-void patternUpButton(void);
-void patternDownButton(void);
-void positionUpButton(void);
-void positionDownButton(void);
-void handleSamplerVolumeBox(void);
-
-int32_t checkGUIButtons(void);
-void handleTextEditing(uint8_t mouseButton);
-bool handleRightMouseButton(void);
-bool handleLeftMouseButton(void);
+static int32_t checkGUIButtons(void);
+static void handleTextEditing(uint8_t mouseButton);
+static bool handleRightMouseButton(void);
+static bool handleLeftMouseButton(void);
 static bool handleGUIButtons(int32_t button);
 static void handleRepeatedGUIButtons(void);
 static void handleRepeatedSamplerFilterButtons(void);
 
+void sampleUpButton(void)
+{
+	if (editor.sampleZero)
+	{
+		editor.sampleZero = false;
+		editor.currSample = 0;
+	}
+	else if (editor.currSample < 30)
+	{
+		editor.currSample++;
+	}
+
+	updateCurrSample();
+}
+
+void sampleDownButton(void)
+{
+	if (!editor.sampleZero && editor.currSample > 0)
+	{
+		editor.currSample--;
+		updateCurrSample();
+	}
+}
+
 static void pointerSetColor(uint8_t cursorColorIndex)
 {
 	assert(cursorColorIndex <= 5);
@@ -119,7 +105,7 @@
 
 void pointerSetPreviousMode(void)
 {
-	if (ui.editTextFlag || ui.askScreenShown || ui.clearScreenShown)
+	if (ui.editTextFlag || ui.askBoxShown)
 		pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
 	else
 		pointerSetMode(ui.previousPointerMode, NO_CARRY);
@@ -351,6 +337,7 @@
 	if (mouseButton == SDL_BUTTON_LEFT)
 	{
 		mouse.leftButtonPressed = false;
+
 		ui.forceSampleDrag = false;
 		ui.forceVolDrag = false;
 		ui.leftLoopPinMoving = false;
@@ -452,7 +439,7 @@
 	mouse.repeatCounter++;
 }
 
-void edNote1UpButton(void)
+static void edNote1UpButton(void)
 {
 	if (mouse.rightButtonPressed)
 		editor.note1 += 12;
@@ -466,7 +453,7 @@
 	recalcChordLength();
 }
 
-void edNote1DownButton(void)
+static void edNote1DownButton(void)
 {
 	if (mouse.rightButtonPressed)
 		editor.note1 -= 12;
@@ -480,7 +467,7 @@
 	recalcChordLength();
 }
 
-void edNote2UpButton(void)
+static void edNote2UpButton(void)
 {
 	if (mouse.rightButtonPressed)
 		editor.note2 += 12;
@@ -494,7 +481,7 @@
 	recalcChordLength();
 }
 
-void edNote2DownButton(void)
+static void edNote2DownButton(void)
 {
 	if (mouse.rightButtonPressed)
 		editor.note2 -= 12;
@@ -508,7 +495,7 @@
 	recalcChordLength();
 }
 
-void edNote3UpButton(void)
+static void edNote3UpButton(void)
 {
 	if (mouse.rightButtonPressed)
 		editor.note3 += 12;
@@ -522,7 +509,7 @@
 	recalcChordLength();
 }
 
-void edNote3DownButton(void)
+static void edNote3DownButton(void)
 {
 	if (mouse.rightButtonPressed)
 		editor.note3 -= 12;
@@ -536,7 +523,7 @@
 	recalcChordLength();
 }
 
-void edNote4UpButton(void)
+static void edNote4UpButton(void)
 {
 	if (mouse.rightButtonPressed)
 		editor.note4 += 12;
@@ -550,7 +537,7 @@
 	recalcChordLength();
 }
 
-void edNote4DownButton(void)
+static void edNote4DownButton(void)
 {
 	if (mouse.rightButtonPressed)
 		editor.note4 -= 12;
@@ -564,7 +551,7 @@
 	recalcChordLength();
 }
 
-void edPosUpButton(bool fast)
+static void edPosUpButton(bool fast)
 {
 	if (mouse.rightButtonPressed)
 	{
@@ -607,7 +594,7 @@
 	ui.updatePosText = true;
 }
 
-void edPosDownButton(bool fast)
+static void edPosDownButton(bool fast)
 {
 	if (mouse.rightButtonPressed)
 	{
@@ -647,7 +634,7 @@
 	ui.updatePosText = true;
 }
 
-void edModUpButton(void)
+static void edModUpButton(void)
 {
 	if (mouse.rightButtonPressed)
 		editor.modulateSpeed += 10;
@@ -660,7 +647,7 @@
 	ui.updateModText = true;
 }
 
-void edModDownButton(void)
+static void edModDownButton(void)
 {
 	if (mouse.rightButtonPressed)
 	{
@@ -677,7 +664,7 @@
 	ui.updateModText = true;
 }
 
-void edVolUpButton(void)
+static void edVolUpButton(void)
 {
 	if (mouse.rightButtonPressed)
 	{
@@ -695,7 +682,7 @@
 	ui.updateVolText = true;
 }
 
-void edVolDownButton(void)
+static void edVolDownButton(void)
 {
 	if (mouse.rightButtonPressed)
 	{
@@ -713,32 +700,8 @@
 	ui.updateVolText = true;
 }
 
-void sampleUpButton(void)
+static void sampleFineTuneUpButton(void)
 {
-	if (editor.sampleZero)
-	{
-		editor.sampleZero = false;
-		editor.currSample = 0;
-	}
-	else if (editor.currSample < 30)
-	{
-		editor.currSample++;
-	}
-
-	updateCurrSample();
-}
-
-void sampleDownButton(void)
-{
-	if (!editor.sampleZero && editor.currSample > 0)
-	{
-		editor.currSample--;
-		updateCurrSample();
-	}
-}
-
-void sampleFineTuneUpButton(void)
-{
 	int8_t finetune = song->samples[editor.currSample].fineTune & 0xF;
 	if (finetune != 7)
 		song->samples[editor.currSample].fineTune = (finetune + 1) & 0xF;
@@ -750,7 +713,7 @@
 	ui.updateCurrSampleFineTune = true;
 }
 
-void sampleFineTuneDownButton(void)
+static void sampleFineTuneDownButton(void)
 {
 	int8_t finetune = song->samples[editor.currSample].fineTune & 0xF;
 	if (finetune != 8)
@@ -763,7 +726,7 @@
 	ui.updateCurrSampleFineTune = true;
 }
 
-void sampleVolumeUpButton(void)
+static void sampleVolumeUpButton(void)
 {
 	int8_t val = song->samples[editor.currSample].volume;
 
@@ -779,7 +742,7 @@
 	ui.updateCurrSampleVolume = true;
 }
 
-void sampleVolumeDownButton(void)
+static void sampleVolumeDownButton(void)
 {
 	int8_t val = song->samples[editor.currSample].volume;
 
@@ -795,14 +758,12 @@
 	ui.updateCurrSampleVolume = true;
 }
 
-void sampleLengthUpButton(bool fast)
+static void sampleLengthUpButton(bool fast)
 {
-	int32_t val;
-
 	if (song->samples[editor.currSample].length == config.maxSampleLength)
 		return;
 
-	val = song->samples[editor.currSample].length;
+	int32_t val = song->samples[editor.currSample].length;
 	if (mouse.rightButtonPressed)
 	{
 		if (fast)
@@ -825,12 +786,9 @@
 	ui.updateCurrSampleLength = true;
 }
 
-void sampleLengthDownButton(bool fast)
+static void sampleLengthDownButton(bool fast)
 {
-	int32_t val;
-	moduleSample_t *s;
-
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->loopStart+s->loopLength > 2)
 	{
 		if (s->length == s->loopStart+s->loopLength)
@@ -842,7 +800,7 @@
 			return;
 	}
 
-	val = song->samples[editor.currSample].length;
+	int32_t val = song->samples[editor.currSample].length;
 	if (mouse.rightButtonPressed)
 	{
 		if (fast)
@@ -872,14 +830,12 @@
 	ui.updateCurrSampleLength = true;
 }
 
-void sampleRepeatUpButton(bool fast)
+static void sampleRepeatUpButton(bool fast)
 {
-	int32_t val, loopLen, len;
+	int32_t val = song->samples[editor.currSample].loopStart;
+	int32_t loopLen = song->samples[editor.currSample].loopLength;
+	int32_t len = song->samples[editor.currSample].length;
 
-	val = song->samples[editor.currSample].loopStart;
-	loopLen = song->samples[editor.currSample].loopLength;
-	len = song->samples[editor.currSample].length;
-
 	if (len == 0)
 	{
 		song->samples[editor.currSample].loopStart = 0;
@@ -907,7 +863,7 @@
 	song->samples[editor.currSample].loopStart = val;
 	ui.updateCurrSampleRepeat = true;
 
-	mixerUpdateLoops();
+	updatePaulaLoops();
 
 	if (ui.samplerScreenShown)
 		setLoopSprites();
@@ -916,13 +872,11 @@
 		ui.updateChordLengthText = true;
 }
 
-void sampleRepeatDownButton(bool fast)
+static void sampleRepeatDownButton(bool fast)
 {
-	int32_t val, len;
+	int32_t val = song->samples[editor.currSample].loopStart;
+	int32_t len = song->samples[editor.currSample].length;
 
-	val = song->samples[editor.currSample].loopStart;
-	len = song->samples[editor.currSample].length;
-
 	if (len == 0)
 	{
 		song->samples[editor.currSample].loopStart = 0;
@@ -950,7 +904,7 @@
 	song->samples[editor.currSample].loopStart = val;
 	ui.updateCurrSampleRepeat = true;
 
-	mixerUpdateLoops();
+	updatePaulaLoops();
 
 	if (ui.samplerScreenShown)
 		setLoopSprites();
@@ -959,14 +913,12 @@
 		ui.updateChordLengthText = true;
 }
 
-void sampleRepeatLengthUpButton(bool fast)
+static void sampleRepeatLengthUpButton(bool fast)
 {
-	int32_t val, loopStart, len;
+	int32_t val = song->samples[editor.currSample].loopLength;
+	int32_t loopStart = song->samples[editor.currSample].loopStart;
+	int32_t len = song->samples[editor.currSample].length;
 
-	val = song->samples[editor.currSample].loopLength;
-	loopStart = song->samples[editor.currSample].loopStart;
-	len = song->samples[editor.currSample].length;
-
 	if (len == 0)
 	{
 		song->samples[editor.currSample].loopLength = 2;
@@ -994,7 +946,7 @@
 	song->samples[editor.currSample].loopLength = val;
 	ui.updateCurrSampleReplen = true;
 
-	mixerUpdateLoops();
+	updatePaulaLoops();
 
 	if (ui.samplerScreenShown)
 		setLoopSprites();
@@ -1003,13 +955,11 @@
 		ui.updateChordLengthText = true;
 }
 
-void sampleRepeatLengthDownButton(bool fast)
+static void sampleRepeatLengthDownButton(bool fast)
 {
-	int32_t val, len;
+	int32_t val = song->samples[editor.currSample].loopLength;
+	int32_t len = song->samples[editor.currSample].length;
 
-	val = song->samples[editor.currSample].loopLength;
-	len = song->samples[editor.currSample].length;
-
 	if (len == 0)
 	{
 		song->samples[editor.currSample].loopLength = 2;
@@ -1037,7 +987,7 @@
 	song->samples[editor.currSample].loopLength = val;
 	ui.updateCurrSampleReplen = true;
 
-	mixerUpdateLoops();
+	updatePaulaLoops();
 
 	if (ui.samplerScreenShown)
 		setLoopSprites();
@@ -1046,14 +996,12 @@
 		ui.updateChordLengthText = true;
 }
 
-void tempoUpButton(void)
+static void tempoUpButton(void)
 {
-	int32_t val;
-
 	if (editor.timingMode == TEMPO_MODE_VBLANK)
 		return;
 
-	val = song->currBPM;
+	int32_t val = song->currBPM;
 	if (mouse.rightButtonPressed)
 		val += 10;
 	else
@@ -1067,14 +1015,12 @@
 	ui.updateSongBPM = true;
 }
 
-void tempoDownButton(void)
+static void tempoDownButton(void)
 {
-	int32_t val;
-
 	if (editor.timingMode == TEMPO_MODE_VBLANK)
 		return;
 
-	val = song->currBPM;
+	int32_t val = song->currBPM;
 	if (mouse.rightButtonPressed)
 		val -= 10;
 	else
@@ -1088,11 +1034,9 @@
 	ui.updateSongBPM = true;
 }
 
-void songLengthUpButton(void)
+static void songLengthUpButton(void)
 {
-	int16_t val;
-
-	val = song->header.numOrders;
+	int16_t val = song->header.numOrders;
 	if (mouse.rightButtonPressed)
 		val += 10;
 	else
@@ -1111,7 +1055,7 @@
 	ui.updateSongLength = true;
 }
 
-void songLengthDownButton(void)
+static void songLengthDownButton(void)
 {
 	int16_t val = song->header.numOrders;
 
@@ -1133,7 +1077,7 @@
 	ui.updateSongLength = true;
 }
 
-void patternUpButton(void)
+static void patternUpButton(void)
 {
 	int16_t val = song->header.order[song->currOrder];
 
@@ -1153,7 +1097,7 @@
 	ui.updateSongPattern = true;
 }
 
-void patternDownButton(void)
+static void patternDownButton(void)
 {
 	int16_t val = song->header.order[song->currOrder];
 
@@ -1173,7 +1117,7 @@
 	ui.updateSongPattern = true;
 }
 
-void positionUpButton(void)
+static void positionUpButton(void)
 {
 	int16_t val = song->currOrder;
 
@@ -1188,7 +1132,7 @@
 	modSetPos(val, DONT_SET_ROW);
 }
 
-void positionDownButton(void)
+static void positionDownButton(void)
 {
 	int16_t val = song->currOrder;
 
@@ -1203,15 +1147,8 @@
 	modSetPos(val, DONT_SET_ROW);
 }
 
-void handleSamplerVolumeBox(void)
+static void handleSamplerVolumeBox(void)
 {
-	int8_t *sampleData;
-	uint8_t i;
-	int16_t sample, sampleVol;
-	int32_t smp32, sampleIndex, sampleLength;
-	double dSmp;
-	moduleSample_t *s;
-
 	if (mouse.rightButtonPressed)
 	{
 		if (ui.editTextFlag)
@@ -1233,32 +1170,6 @@
 	// check buttons
 	if (mouse.leftButtonPressed)
 	{
-		// restore sample ask dialog
-		if (ui.askScreenShown && ui.askScreenType == ASK_RESTORE_SAMPLE)
-		{
-			if (mouse.y >= 71 && mouse.y <= 81)
-			{
-				if (mouse.x >= 171 && mouse.x <= 196)
-				{
-					// YES button
-					ui.askScreenShown = false;
-					ui.answerNo = false;
-					ui.answerYes = true;
-					handleAskYes();
-				}
-				else if (mouse.x >= 234 && mouse.x <= 252)
-				{
-					// NO button
-					ui.askScreenShown = false;
-					ui.answerNo = true;
-					ui.answerYes = false;
-					handleAskNo();
-				}
-			}
-
-			return;
-		}
-
 		// MAIN SCREEN STOP
 		if (!ui.diskOpScreenShown && !ui.posEdScreenShown)
 		{
@@ -1296,8 +1207,7 @@
 		// SAMPLER SCREEN STOP
 		if (mouse.x >= 0 && mouse.x <= 31 && mouse.y >= 222 && mouse.y <= 243)
 		{
-			for (i = 0; i < AMIGA_VOICES; i++)
-				mixerKillVoice(i);
+			turnOffVoices();
 			return;
 		}
 
@@ -1348,6 +1258,8 @@
 			// NORMALIZE
 			if (mouse.x >= 101 && mouse.x <= 143)
 			{
+				int32_t sampleLength;
+
 				if (editor.sampleZero)
 				{
 					statusNotSampleZero();
@@ -1354,7 +1266,7 @@
 					return;
 				}
 
-				s = &song->samples[editor.currSample];
+				moduleSample_t *s = &song->samples[editor.currSample];
 				if (s->length == 0)
 				{
 					statusSampleIsEmpty();
@@ -1361,7 +1273,7 @@
 					return;
 				}
 
-				sampleData = &song->sampleData[s->offset];
+				int8_t *sampleData = &song->sampleData[s->offset];
 				if (editor.markStartOfs != -1)
 				{
 					sampleData += editor.markStartOfs;
@@ -1372,12 +1284,12 @@
 					sampleLength = s->length;
 				}
 
-				sampleVol = 0;
-				sampleIndex = 0;
+				int16_t sampleVol = 0;
+				int32_t sampleIndex = 0;
 
 				while (sampleIndex < sampleLength)
 				{
-					sample = *sampleData++;
+					int16_t sample = *sampleData++;
 					sample = ABS(sample);
 
 					if (sampleVol < sample)
@@ -1457,6 +1369,8 @@
 			// RAMP
 			else if (mouse.x >= 72 && mouse.x <= 100)
 			{
+				int32_t sampleLength;
+
 				if (editor.sampleZero)
 				{
 					statusNotSampleZero();
@@ -1463,7 +1377,7 @@
 					return;
 				}
 
-				s = &song->samples[editor.currSample];
+				moduleSample_t *s = &song->samples[editor.currSample];
 				if (s->length == 0)
 				{
 					statusSampleIsEmpty();
@@ -1477,7 +1391,7 @@
 					return;
 				}
 
-				sampleData = &song->sampleData[s->offset];
+				int8_t *sampleData = &song->sampleData[s->offset];
 				if (editor.markStartOfs != -1 && editor.markEndOfs-editor.markStartOfs >= 1)
 				{
 					sampleData += editor.markStartOfs;
@@ -1492,15 +1406,15 @@
 				{
 					double dSampleLengthMul = 1.0 / sampleLength;
 
-					sampleIndex = 0;
+					int32_t sampleIndex = 0;
 					while (sampleIndex < sampleLength)
 					{
-						dSmp = (sampleIndex * editor.vol2) * dSampleLengthMul;
+						double dSmp = (sampleIndex * editor.vol2) * dSampleLengthMul;
 						dSmp += ((sampleLength - sampleIndex) * editor.vol1) * dSampleLengthMul;
 						dSmp *= *sampleData;
 						dSmp *= (1.0 / 100.0);
 
-						smp32 = (int32_t)dSmp;
+						int32_t smp32 = (int32_t)dSmp;
 						CLAMP8(smp32);
 
 						*sampleData++ = (int8_t)smp32;
@@ -1620,11 +1534,8 @@
 	}
 }
 
-void handleSamplerFiltersBox(void)
+static void handleSamplerFiltersBox(void)
 {
-	uint8_t i;
-	moduleSample_t *s;
-
 	if (mouse.rightButtonPressed && ui.editTextFlag)
 	{
 		exitGetTextLine(EDIT_TEXT_NO_UPDATE);
@@ -1634,32 +1545,6 @@
 	if (ui.editTextFlag || mouse.lastSmpFilterButton > -1 || !mouse.leftButtonPressed)
 		return;
 
-	// restore sample ask dialog
-	if (ui.askScreenShown && ui.askScreenType == ASK_RESTORE_SAMPLE)
-	{
-		if (mouse.y >= 71 && mouse.y <= 81)
-		{
-			if (mouse.x >= 171 && mouse.x <= 196)
-			{
-				// YES button
-				ui.askScreenShown = false;
-				ui.answerNo = false;
-				ui.answerYes = true;
-				handleAskYes();
-			}
-			else if ((mouse.x >= 234) && (mouse.x <= 252))
-			{
-				// NO button
-				ui.askScreenShown = false;
-				ui.answerNo = true;
-				ui.answerYes = false;
-				handleAskNo();
-			}
-		}
-
-		return;
-	}
-
 	// FILTERS button (toggle)
 	if (mouse.x >= 211 && mouse.x <= 245 && mouse.y >= 244 && mouse.y <= 254)
 	{
@@ -1705,8 +1590,7 @@
 	// SAMPLER SCREEN STOP
 	if (mouse.x >= 0 && mouse.x <= 31 && mouse.y >= 222 && mouse.y <= 243)
 	{
-		for (i = 0; i < AMIGA_VOICES; i++)
-			mixerKillVoice(i);
+		turnOffVoices();
 		return;
 	}
 
@@ -1719,7 +1603,7 @@
 			return;
 		}
 
-		s = &song->samples[editor.currSample];
+		moduleSample_t *s = &song->samples[editor.currSample];
 		if (s->length == 0)
 		{
 			statusSampleIsEmpty();
@@ -1926,28 +1810,8 @@
 	if (withinButtonRect(&bStruct[i])) \
 		return bStruct[i].b; \
 
-int32_t checkGUIButtons(void)
+static int32_t checkGUIButtons(void)
 {
-	// these two makes *no other* buttons clickable
-	if (ui.askScreenShown)
-	{
-		if (ui.pat2SmpDialogShown)
-		{
-			TEST_BUTTONS(bPat2SmpAsk, PAT2SMP_ASK_BUTTONS);
-		}
-		else
-		{
-			TEST_BUTTONS(bAsk, ASK_BUTTONS);
-		}
-
-		return -1;
-	}
-	else if (ui.clearScreenShown)
-	{
-		TEST_BUTTONS(bClear, CLEAR_BUTTONS);
-		return -1;
-	}
-
 	// QUIT (xy 0,0) works on all screens except for ask/clear screen
 	if (mouse.x == 0 && mouse.y == 0)
 		return PTB_QUIT;
@@ -1994,90 +1858,88 @@
 	return -1;
 }
 
-void handleTextEditing(uint8_t mouseButton)
+static void handleTextEditing(uint8_t mouseButton)
 {
-	char *tmpRead;
-	int32_t tmp32;
-
 	// handle mouse while editing text/numbers
-	if (ui.editTextFlag)
+
+	if (!ui.editTextFlag)
+		return;
+
+	if (ui.editTextType != TEXT_EDIT_STRING)
 	{
-		if (ui.editTextType != TEXT_EDIT_STRING)
+		if (mouseButton == SDL_BUTTON_RIGHT)
+			exitGetTextLine(EDIT_TEXT_NO_UPDATE);
+	}
+	else if (mouseButton == SDL_BUTTON_LEFT && !editor.mixFlag)
+	{
+		int32_t tmp32 = mouse.y - ui.lineCurY;
+		if (tmp32 <= 2 && tmp32 >= -9)
 		{
-			if (mouseButton == SDL_BUTTON_RIGHT)
-				exitGetTextLine(EDIT_TEXT_NO_UPDATE);
-		}
-		else if (mouseButton == SDL_BUTTON_LEFT && !editor.mixFlag)
-		{
-			tmp32 = mouse.y - ui.lineCurY;
-			if (tmp32 <= 2 && tmp32 >= -9)
+			tmp32 = (int32_t)((mouse.x - ui.lineCurX) + 4) >> 3;
+			while (tmp32 != 0) // 0 = pos we want
 			{
-				tmp32 = (int32_t)((mouse.x - ui.lineCurX) + 4) >> 3;
-				while (tmp32 != 0) // 0 = pos we want
+				if (tmp32 > 0)
 				{
-					if (tmp32 > 0)
+					if (ui.editPos < ui.textEndPtr && *ui.editPos != '\0')
 					{
-						if (ui.editPos < ui.textEndPtr && *ui.editPos != '\0')
-						{
-							ui.editPos++;
-							textMarkerMoveRight();
-						}
-						tmp32--;
+						ui.editPos++;
+						textMarkerMoveRight();
 					}
-					else if (tmp32 < 0)
+					tmp32--;
+				}
+				else if (tmp32 < 0)
+				{
+					if (ui.editPos > ui.dstPtr)
 					{
-						if (ui.editPos > ui.dstPtr)
-						{
-							ui.editPos--;
-							textMarkerMoveLeft();
-						}
-						tmp32++;
+						ui.editPos--;
+						textMarkerMoveLeft();
 					}
+					tmp32++;
 				}
 			}
-			else
-			{
-				exitGetTextLine(EDIT_TEXT_UPDATE);
-			}
 		}
-		else if (mouseButton == SDL_BUTTON_RIGHT)
+		else
 		{
-			if (editor.mixFlag)
-			{
-				exitGetTextLine(EDIT_TEXT_UPDATE);
-				editor.mixFlag = false;
-				ui.updateMixText = true;
-			}
-			else
-			{
-				tmpRead = ui.dstPtr;
-				while (tmpRead < ui.textEndPtr)
-					*tmpRead++ = '\0';
+			exitGetTextLine(EDIT_TEXT_UPDATE);
+		}
+	}
+	else if (mouseButton == SDL_BUTTON_RIGHT)
+	{
+		if (editor.mixFlag)
+		{
+			exitGetTextLine(EDIT_TEXT_UPDATE);
+			editor.mixFlag = false;
+			ui.updateMixText = true;
+		}
+		else
+		{
+			char *tmpRead = ui.dstPtr;
+			while (tmpRead < ui.textEndPtr)
+				*tmpRead++ = '\0';
 
-				*ui.textEndPtr = '\0';
+			*ui.textEndPtr = '\0';
 
-				// don't exit text edit mode if the disk op. path was about to be deleted
-				if (ui.editObject == PTB_DO_DATAPATH)
+			// don't exit text edit mode if the disk op. path was about to be deleted
+			if (ui.editObject == PTB_DO_DATAPATH)
+			{
+				// move text cursor to pos 0
+				while (ui.editPos > ui.dstPtr)
 				{
-					// move text cursor to pos 0
-					while (ui.editPos > ui.dstPtr)
-					{
-						ui.editPos--;
-						textMarkerMoveLeft();
-					}
-
-					ui.updateDiskOpPathText = true;
+					ui.editPos--;
+					textMarkerMoveLeft();
 				}
-				else
-				{
-					if (ui.editObject == PTB_SONGNAME)
-						ui.updateSongName = true;
-					else if (ui.editObject == PTB_SAMPLENAME)
-						ui.updateCurrSampleName = true;
 
-					exitGetTextLine(EDIT_TEXT_UPDATE);
-				}
+				ui.updateDiskOpPathText = true;
 			}
+			else
+			{
+				if (ui.editObject == PTB_SONGNAME)
+					ui.updateSongName = true;
+				else if (ui.editObject == PTB_SAMPLENAME)
+					ui.updateCurrSampleName = true;
+
+				exitGetTextLine(EDIT_TEXT_UPDATE);
+			}
 		}
 	}
 }
@@ -2084,7 +1946,7 @@
 
 void mouseWheelUpHandler(void)
 {
-	if (ui.editTextFlag || ui.askScreenShown || ui.clearScreenShown || editor.swapChannelFlag ||
+	if (ui.editTextFlag || ui.askBoxShown || editor.swapChannelFlag ||
 		ui.samplingBoxShown || ui.samplerVolBoxShown || ui.samplerFiltersBoxShown)
 		return;
 
@@ -2106,7 +1968,7 @@
 	}
 	else if (ui.samplerScreenShown) // lower part of screen
 	{
-			samplerZoomInMouseWheel();
+		samplerZoomInMouseWheel();
 	}
 	else if (!editor.songPlaying && song->currRow > 0)
 	{
@@ -2116,7 +1978,7 @@
 
 void mouseWheelDownHandler(void)
 {
-	if (ui.editTextFlag || ui.askScreenShown || ui.clearScreenShown || editor.swapChannelFlag ||
+	if (ui.editTextFlag || ui.askBoxShown || editor.swapChannelFlag ||
 		ui.samplingBoxShown || ui.samplerVolBoxShown || ui.samplerFiltersBoxShown)
 		return;
 
@@ -2147,7 +2009,7 @@
 	}
 }
 
-bool handleRightMouseButton(void)
+static bool handleRightMouseButton(void)
 {
 	if (!mouse.rightButtonPressed)
 		return false;
@@ -2161,26 +2023,6 @@
 		return true;
 	}
 
-	// close clear dialog with right mouse button
-	if (ui.clearScreenShown)
-	{
-		ui.clearScreenShown = false;
-		setPrevStatusMessage();
-		pointerSetPreviousMode();
-		removeClearScreen();
-		return true;
-	}
-
-	// close ask dialogs with right mouse button
-	if (ui.askScreenShown)
-	{
-		ui.askScreenShown = false;
-		ui.answerNo = true;
-		ui.answerYes = false;
-		handleAskNo(); // mouse pointer is set to error (red) in here
-		return true;
-	}
-
 	// toggle channel muting with right mouse button
 	if (ui.visualizerMode == VISUAL_QUADRASCOPE && mouse.y >= 55 && mouse.y <= 87)
 	{
@@ -2187,7 +2029,7 @@
 		if (!ui.posEdScreenShown && !ui.editOpScreenShown && !ui.diskOpScreenShown &&
 			!ui.aboutScreenShown && !ui.samplerVolBoxShown &&
 			!ui.samplerFiltersBoxShown && !ui.samplingBoxShown &&
-			!editor.isWAVRendering)
+			!editor.mod2WavOngoing)
 		{
 			     if (mouse.x > 127 && mouse.x <= 167) editor.muted[0] ^= 1;
 			else if (mouse.x > 175 && mouse.x <= 215) editor.muted[1] ^= 1;
@@ -2208,10 +2050,8 @@
 	return false;
 }
 
-bool handleLeftMouseButton(void)
+static bool handleLeftMouseButton(void)
 {
-	int32_t guiButton;
-
 	if (editor.swapChannelFlag || ui.editTextFlag)
 		return false;
 
@@ -2236,34 +2076,6 @@
 		return true;
 	}
 
-	// "downsample before loading sample" ask dialog
-	if (ui.askScreenShown && ui.askScreenType == ASK_LOAD_DOWNSAMPLE)
-	{
-		if (mouse.y >= 83 && mouse.y <= 93)
-		{
-			if (mouse.x >= 179 && mouse.x <= 204)
-			{
-				// YES button
-				ui.askScreenShown = false;
-				ui.answerNo = false;
-				ui.answerYes = true;
-				handleAskYes();
-				return true;
-			}
-			else if (mouse.x >= 242 && mouse.x <= 260)
-			{
-				// NO button
-				ui.askScreenShown = false;
-				ui.answerNo = true;
-				ui.answerYes = false;
-				handleAskNo();
-				return true;
-			}
-		}
-
-		return false;
-	}
-
 	// cancel note input gadgets with left/right mouse button
 	if (ui.changingSmpResample || ui.changingChordNote || ui.changingDrumPadNote || ui.changingSamplingNote)
 	{
@@ -2290,70 +2102,16 @@
 	if (!mouse.leftButtonPressed)
 		return false;
 
-	// handle QUIT ask dialog while Disk Op. filling is ongoing
-	if (diskop.isFilling)
+	// if MOD2WAV is ongoing, only check CANCEL button
+	if (editor.mod2WavOngoing)
 	{
-		if (ui.askScreenShown && ui.askScreenType == ASK_QUIT)
+		if (mouse.x >= MOD2WAV_CANCEL_BTN_X1 && mouse.x <= MOD2WAV_CANCEL_BTN_X2 &&
+			mouse.y >= MOD2WAV_CANCEL_BTN_Y1 && mouse.y <= MOD2WAV_CANCEL_BTN_Y2)
 		{
-			if (mouse.y >= 71 && mouse.y <= 81)
-			{
-				if (mouse.x >= 171 && mouse.x <= 196)
-				{
-					// YES button
-					ui.askScreenShown = false;
-					ui.answerNo = false;
-					ui.answerYes = true;
-					handleAskYes();
-				}
-				else if (mouse.x >= 234 && mouse.x <= 252)
-				{
-					// NO button
-					ui.askScreenShown = false;
-					ui.answerNo = true;
-					ui.answerYes = false;
-					handleAskNo();
-				}
-			}
-		}
-
-		return true;
-	}
-
-	// CANCEL and YES/NO (ask exit) buttons while MOD2WAV is ongoing
-	if (editor.isWAVRendering)
-	{
-		if (ui.askScreenShown && ui.askScreenType == ASK_QUIT)
-		{
-			if (mouse.x >= 171 && mouse.x <= 196)
-			{
-				// YES button
-				editor.isWAVRendering = false;
-				SDL_WaitThread(editor.mod2WavThread, NULL);
-
-				ui.askScreenShown = false;
-				ui.answerNo = false;
-				ui.answerYes = true;
-				handleAskYes();
-			}
-			else if (mouse.x >= 234 && mouse.x <= 252)
-			{
-				// NO button
-				ui.askScreenShown = false;
-				ui.answerNo = true;
-				ui.answerYes = false;
-				handleAskNo();
-
-				pointerSetMode(POINTER_MODE_MSG2, NO_CARRY);
-				setStatusMessage("RENDERING MOD...", NO_CARRY);
-			}
-		}
-		else if (mouse.y >= 58 && mouse.y <= 68 && mouse.x >= 133 && mouse.x <= 186)
-		{
-			// CANCEL button
 			editor.abortMod2Wav = true;
 		}
 
-		return true;
+		return true; // don't handle other buttons
 	}
 
 	// if in fullscreen mode and the image isn't filling the whole screen, handle top left corner as quit
@@ -2360,7 +2118,7 @@
 	if (video.fullscreen && (video.renderX > 0 || video.renderY > 0) && (mouse.rawX == 0 && mouse.rawY == 0))
 		return handleGUIButtons(PTB_QUIT);
 
-	guiButton = checkGUIButtons();
+	int32_t guiButton = checkGUIButtons();
 	if (guiButton == -1)
 		return false;
 
@@ -2380,15 +2138,13 @@
 
 	if (editor.errorMsgActive)
 	{
-		if (++editor.errorMsgCounter >= 55)
+		if (++editor.errorMsgCounter >= VBLANK_HZ) // 1 second
 		{
 			editor.errorMsgCounter = 0;
 
 			// don't reset status text/mouse color during certain modes
-			if (!ui.askScreenShown && !ui.clearScreenShown &&
-				!ui.pat2SmpDialogShown && !ui.changingChordNote &&
-				!ui.changingDrumPadNote && !ui.changingSmpResample &&
-				!editor.swapChannelFlag && !ui.changingSamplingNote)
+			if (!ui.askBoxShown         && !ui.changingChordNote   && !ui.changingDrumPadNote &&
+				!ui.changingSmpResample && !editor.swapChannelFlag && !ui.changingSamplingNote)
 			{
 				pointerSetPreviousMode();
 				setPrevStatusMessage();
@@ -2397,7 +2153,8 @@
 			editor.errorMsgActive = false;
 			editor.errorMsgBlock = false;
 
-			diskOpShowSelectText();
+			if (ui.diskOpScreenShown)
+				diskOpShowSelectText();
 		}
 	}
 }
@@ -2404,34 +2161,16 @@
 
 static bool handleGUIButtons(int32_t button) // are you prepared to enter the jungle?
 {
-	char pat2SmpText[24];
-	int8_t *ptr8_1, *ptr8_2, *ptr8_3, *ptr8_4, tmpSmp, modTmp, modDat;
-	uint8_t i;
-	int16_t tmp16;
-	int32_t smp32, j, modPos, oldVal, tmp32;
-	double dSmp;
-	moduleSample_t *s;
-	
 	ui.force32BitNumPtr = false;
 
 	switch (button)
 	{
-		case PTB_DUMMY: return false; // for gaps/empty spaces/dummies
+		case PTB_DUMMY: return false; // for gaps / empty spaces / dummies
 
 		case PTB_PAT2SMP:
 		{
-			ui.askScreenShown = true;
-			ui.askScreenType = ASK_PAT2SMP;
-			ui.pat2SmpDialogShown = true;
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-
-			if (editor.songPlaying)
-				sprintf(pat2SmpText, "ROW 00 TO SMP %02X?", editor.currSample + 1);
-			else
-				sprintf(pat2SmpText, "ROW %02d TO SMP %02X?", song->currRow, editor.currSample + 1);
-
-			setStatusMessage(pat2SmpText, NO_CARRY);
-			renderAskDialog();
+			if (askBox(ASKBOX_PAT2SMP, "PLEASE SELECT"))
+				pat2SmpRender();
 		}
 		break;
 
@@ -2516,11 +2255,8 @@
 
 		case PTB_EO_KILL:
 		{
-			ui.askScreenShown = true;
-			ui.askScreenType = ASK_KILL_SAMPLE;
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-			setStatusMessage("KILL SAMPLE ?", NO_CARRY);
-			renderAskDialog();
+			if (askBox(ASKBOX_YES_NO, "KILL SAMPLE ?"))
+				killSample();
 		}
 		break;
 
@@ -2654,7 +2390,7 @@
 					break;
 				}
 
-				s = &song->samples[editor.currSample];
+				moduleSample_t *s = &song->samples[editor.currSample];
 				if (s->length == 0)
 				{
 					statusSampleIsEmpty();
@@ -2667,7 +2403,7 @@
 					break;
 				}
 
-				ptr8_1 = (int8_t *)malloc(config.maxSampleLength);
+				int8_t *ptr8_1 = (int8_t *)malloc(config.maxSampleLength);
 				if (ptr8_1 == NULL)
 				{
 					statusOutOfMemory();
@@ -2676,9 +2412,9 @@
 
 				memcpy(ptr8_1, &song->sampleData[s->offset], config.maxSampleLength);
 
-				ptr8_2 = &song->sampleData[s->offset+editor.samplePos];
-				ptr8_3 = &song->sampleData[s->offset+s->length-1];
-				ptr8_4 = ptr8_1;
+				int8_t *ptr8_2 = &song->sampleData[s->offset+editor.samplePos];
+				int8_t *ptr8_3 = &song->sampleData[s->offset+s->length-1];
+				int8_t *ptr8_4 = ptr8_1;
 
 				editor.modulateOffset = 0;
 				editor.modulatePos = 0;
@@ -2685,7 +2421,7 @@
 
 				do
 				{
-					tmp16 = *ptr8_2 + *ptr8_1;
+					int16_t tmp16 = *ptr8_2 + *ptr8_1;
 					if (editor.halfClipFlag == 0)
 						tmp16 >>= 1;
 
@@ -2700,9 +2436,9 @@
 					{
 						editor.modulatePos += editor.modulateSpeed;
 
-						modTmp = (editor.modulatePos >> 12) & 0xFF;
-						modDat = vibratoTable[modTmp & 0x1F] >> 2;
-						modPos = ((modTmp & 32) ? (editor.modulateOffset - modDat) : (editor.modulateOffset + modDat)) + 2048;
+						int8_t modTmp = (editor.modulatePos >> 12) & 0xFF;
+						int8_t modDat = vibratoTable[modTmp & 0x1F] >> 2;
+						int32_t modPos = ((modTmp & 32) ? (editor.modulateOffset - modDat) : (editor.modulateOffset + modDat)) + 2048;
 
 						editor.modulateOffset = modPos;
 						modPos >>= 11;
@@ -2730,7 +2466,7 @@
 				break;
 			}
 
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 			if (s->length == 0)
 			{
 				statusSampleIsEmpty();
@@ -2749,16 +2485,16 @@
 				break;
 			}
 
-			ptr8_1 = &song->sampleData[s->offset+editor.samplePos];
-			ptr8_2 = &song->sampleData[s->offset];
-			ptr8_3 = ptr8_2;
+			int8_t *ptr8_1 = &song->sampleData[s->offset+editor.samplePos];
+			int8_t *ptr8_2 = &song->sampleData[s->offset];
+			int8_t *ptr8_3 = ptr8_2;
 
 			editor.modulateOffset = 0;
 			editor.modulatePos = 0;
 
-			for (j = 0; j < s->length; j++)
+			for (int32_t j = 0; j < s->length; j++)
 			{
-				tmp16 = (*ptr8_2 + *ptr8_1) >> 1;
+				int16_t tmp16 = (*ptr8_2 + *ptr8_1) >> 1;
 				CLAMP8(tmp16);
 
 				*ptr8_1++ = (int8_t)tmp16;
@@ -2771,9 +2507,9 @@
 				{
 					editor.modulatePos += editor.modulateSpeed;
 
-					modTmp = (editor.modulatePos >> 12) & 0xFF;
-					modDat = vibratoTable[modTmp & 0x1F] >> 2;
-					modPos = ((modTmp & 32) ? (editor.modulateOffset - modDat) : (editor.modulateOffset + modDat)) + 2048;
+					int8_t modTmp = (editor.modulatePos >> 12) & 0xFF;
+					int8_t modDat = vibratoTable[modTmp & 0x1F] >> 2;
+					int32_t modPos = ((modTmp & 32) ? (editor.modulateOffset - modDat) : (editor.modulateOffset + modDat)) + 2048;
 
 					editor.modulateOffset = modPos;
 					modPos >>= 11;
@@ -2784,9 +2520,9 @@
 
 			if (editor.halfClipFlag != 0)
 			{
-				for (j = 0; j < s->length; j++)
+				for (int32_t j = 0; j < s->length; j++)
 				{
-					tmp16 = ptr8_3[j] + ptr8_3[j];
+					int16_t tmp16 = ptr8_3[j] + ptr8_3[j];
 					CLAMP8(tmp16);
 					ptr8_3[j] = (int8_t)tmp16;
 				}
@@ -2847,7 +2583,7 @@
 				break;
 			}
 
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 			if (s->length == 0)
 			{
 				statusSampleIsEmpty();
@@ -2870,7 +2606,7 @@
 				break;
 			}
 
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 			if (s->length == 0)
 			{
 				statusSampleIsEmpty();
@@ -2903,7 +2639,7 @@
 				break;
 			}
 
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 			if (s->length == 0)
 			{
 				statusSampleIsEmpty();
@@ -2916,9 +2652,9 @@
 				break;
 			}
 
-			ptr8_1 = &song->sampleData[s->offset];
+			int8_t *ptr8_1 = &song->sampleData[s->offset];
 
-			ptr8_3 = (int8_t *)malloc(config.maxSampleLength);
+			int8_t *ptr8_3 = (int8_t *)malloc(config.maxSampleLength);
 			if (ptr8_3 == NULL)
 			{
 				statusOutOfMemory();
@@ -2925,7 +2661,7 @@
 				return true;
 			}
 
-			ptr8_2 = ptr8_3;
+			int8_t *ptr8_2 = ptr8_3;
 
 			memcpy(ptr8_2, ptr8_1, config.maxSampleLength);
 
@@ -2932,15 +2668,15 @@
 			editor.modulateOffset = 0;
 			editor.modulatePos = 0;
 
-			for (j = 0; j < s->length; j++)
+			for (int32_t j = 0; j < s->length; j++)
 			{
 				*ptr8_1++ = *ptr8_2;
 
 				editor.modulatePos += editor.modulateSpeed;
 
-				modTmp = (editor.modulatePos >> 12) & 0xFF;
-				modDat = vibratoTable[modTmp & 0x1F] >> 2;
-				modPos = ((modTmp & 32) ? (editor.modulateOffset - modDat) : (editor.modulateOffset + modDat)) + 2048;
+				int8_t modTmp = (editor.modulatePos >> 12) & 0xFF;
+				int8_t modDat = vibratoTable[modTmp & 0x1F] >> 2;
+				int32_t modPos = ((modTmp & 32) ? (editor.modulateOffset - modDat) : (editor.modulateOffset + modDat)) + 2048;
 
 				editor.modulateOffset = modPos;
 
@@ -2970,7 +2706,7 @@
 				break;
 			}
 
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 
 			if (s->length == 0)
 			{
@@ -2978,17 +2714,17 @@
 				break;
 			}
 
-			ptr8_1 = &song->sampleData[s->offset];
-			ptr8_2 = &song->sampleData[s->offset+s->length-1];
+			int8_t *ptr8_1 = &song->sampleData[s->offset];
+			int8_t *ptr8_2 = &song->sampleData[s->offset+s->length-1];
 
 			do
 			{
-				tmp16 = *ptr8_1 + *ptr8_2;
+				int16_t tmp16 = *ptr8_1 + *ptr8_2;
 				if (editor.halfClipFlag == 0)
 					tmp16 >>= 1;
 
 				CLAMP8(tmp16);
-				tmpSmp = (int8_t)tmp16;
+				int8_t tmpSmp = (int8_t)tmp16;
 
 				*ptr8_1++ = tmpSmp;
 				*ptr8_2-- = tmpSmp;
@@ -3005,6 +2741,8 @@
 
 		case PTB_EO_BACKWD:
 		{
+			int8_t *ptr8_1, *ptr8_2;
+
 			if (editor.sampleZero)
 			{
 				statusNotSampleZero();
@@ -3011,7 +2749,7 @@
 				break;
 			}
 
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 			if (s->length == 0)
 			{
 				statusSampleIsEmpty();
@@ -3031,7 +2769,7 @@
 
 			do
 			{
-				tmpSmp = *ptr8_1;
+				int8_t tmpSmp = *ptr8_1;
 				*ptr8_1++ = *ptr8_2;
 				*ptr8_2-- = tmpSmp;
 			}
@@ -3053,7 +2791,7 @@
 				break;
 			}
 
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 			if (s->length == 0)
 			{
 				statusSampleIsEmpty();
@@ -3113,7 +2851,7 @@
 				break;
 			}
 
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 			if (s->length == 0)
 			{
 				statusSampleIsEmpty();
@@ -3128,13 +2866,13 @@
 
 			double dSamplePosMul = 1.0 / editor.samplePos;
 
-			ptr8_1 = &song->sampleData[s->offset];
-			for (j = 0; j < editor.samplePos; j++)
+			int8_t *ptr8 = &song->sampleData[s->offset];
+			for (int32_t j = 0; j < editor.samplePos; j++)
 			{
-				dSmp = ((*ptr8_1) * j) * dSamplePosMul;
-				smp32 = (int32_t)dSmp;
+				double dSmp = ((*ptr8) * j) * dSamplePosMul;
+				int32_t smp32 = (int32_t)dSmp;
 				CLAMP8(smp32);
-				*ptr8_1++ = (int8_t)smp32;
+				*ptr8++ = (int8_t)smp32;
 			}
 
 			fixSampleBeep(s);
@@ -3154,7 +2892,7 @@
 				break;
 			}
 
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 			if (s->length == 0)
 			{
 				statusSampleIsEmpty();
@@ -3167,21 +2905,21 @@
 				break;
 			}
 
-			tmp32 = (s->length - 1) - editor.samplePos;
+			int32_t tmp32 = (s->length - 1) - editor.samplePos;
 			if (tmp32 == 0)
 				tmp32 = 1;
 
 			double dSampleMul = 1.0 / tmp32;
 
-			ptr8_1 = &song->sampleData[s->offset+s->length-1];
+			int8_t *ptr8 = &song->sampleData[s->offset+s->length-1];
 
 			int32_t idx = 0;
-			for (j = editor.samplePos; j < s->length; j++)
+			for (int32_t j = editor.samplePos; j < s->length; j++)
 			{
-				dSmp = ((*ptr8_1) * idx) * dSampleMul;
-				smp32 = (int32_t)dSmp;
+				double dSmp = ((*ptr8) * idx) * dSampleMul;
+				int32_t smp32 = (int32_t)dSmp;
 				CLAMP8(smp32);
-				*ptr8_1-- = (int8_t)smp32;
+				*ptr8-- = (int8_t)smp32;
 
 				idx++;
 			}
@@ -3196,7 +2934,7 @@
 
 		case PTB_EO_UPSAMP:
 		{
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 			if (s->length == 0)
 			{
 				statusSampleIsEmpty();
@@ -3203,17 +2941,14 @@
 				break;
 			}
 
-			ui.askScreenShown = true;
-			ui.askScreenType = ASK_UPSAMPLE;
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-			setStatusMessage("UPSAMPLE ?", NO_CARRY);
-			renderAskDialog();
+			if (askBox(ASKBOX_YES_NO, "DOWNSAMPLE ?"))
+				upSample();
 		}
 		break;
 
 		case PTB_EO_DNSAMP:
 		{
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 			if (s->length == 0)
 			{
 				statusSampleIsEmpty();
@@ -3220,11 +2955,8 @@
 				break;
 			}
 
-			ui.askScreenShown = true;
-			ui.askScreenType = ASK_DOWNSAMPLE;
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-			setStatusMessage("DOWNSAMPLE ?", NO_CARRY);
-			renderAskDialog();
+			if (askBox(ASKBOX_YES_NO, "DOWNSAMPLE ?"))
+				downSample();
 		}
 		break;
 
@@ -3255,7 +2987,7 @@
 				break;
 			}
 
-			s = &song->samples[editor.currSample];
+			moduleSample_t *s = &song->samples[editor.currSample];
 			if (s->length == 0)
 			{
 				statusSampleIsEmpty();
@@ -3264,14 +2996,14 @@
 
 			if (editor.sampleVol != 100)
 			{
-				ptr8_1 = &song->sampleData[s->offset];
+				int8_t *ptr8 = &song->sampleData[s->offset];
 				int32_t sampleMul = (((1UL << 19) * editor.sampleVol) + 50) / 100;
 
-				for (j = 0; j < s->length; j++)
+				for (int32_t j = 0; j < s->length; j++)
 				{
-					tmp16 = (ptr8_1[j] * sampleMul) >> 19;
+					int16_t tmp16 = (ptr8[j] * sampleMul) >> 19;
 					CLAMP8(tmp16);
-					ptr8_1[j] = (int8_t)tmp16;
+					ptr8[j] = (int8_t)tmp16;
 				}
 
 				fixSampleBeep(s);
@@ -3289,7 +3021,13 @@
 
 		// Edit Op. Screen #4 (chord maker)
 
-		case PTB_EO_DOCHORD: makeChord(); break;
+		case PTB_EO_DOCHORD:
+		{
+			if (askBox(ASKBOX_YES_NO, "MAKE CHORD?"))
+				mixChordSample();
+		}
+		break;
+
 		case PTB_EO_NOTE1: selectChordNote1(); break;
 		case PTB_EO_NOTE2: selectChordNote2(); break;
 		case PTB_EO_NOTE3: selectChordNote3(); break;
@@ -3466,7 +3204,7 @@
 				{
 					song->header.numOrders = 1;
 
-					tmp16 = song->currOrder;
+					int16_t tmp16 = song->currOrder;
 					if (tmp16 > song->header.numOrders-1)
 						tmp16 = song->header.numOrders-1;
 
@@ -3494,7 +3232,7 @@
 		case PTB_PATTBOX:
 		case PTB_PATTDATA:
 		{
-			if (!ui.introScreenShown && (editor.currMode == MODE_IDLE || editor.currMode == MODE_EDIT || editor.playMode != PLAY_MODE_NORMAL))
+			if (!ui.introTextShown && (editor.currMode == MODE_IDLE || editor.currMode == MODE_EDIT || editor.playMode != PLAY_MODE_NORMAL))
 			{
 				ui.tmpDisp16 = song->currPattern;
 				editor.currEditPatternDisp = &ui.tmpDisp16;
@@ -3562,7 +3300,7 @@
 
 			if (mouse.rightButtonPressed)
 			{
-				s = &song->samples[editor.currSample];
+				moduleSample_t *s = &song->samples[editor.currSample];
 
 				turnOffVoices();
 
@@ -3621,7 +3359,7 @@
 
 			if (mouse.rightButtonPressed)
 			{
-				s = &song->samples[editor.currSample];
+				moduleSample_t *s = &song->samples[editor.currSample];
 
 				s->loopStart = 0;
 				if (s->length >= s->loopLength)
@@ -3641,7 +3379,7 @@
 				if (ui.samplerScreenShown)
 					setLoopSprites();
 
-				mixerUpdateLoops();
+				updatePaulaLoops();
 				updateWindowTitle(MOD_IS_MODIFIED);
 			}
 			else
@@ -3683,7 +3421,7 @@
 
 			if (mouse.rightButtonPressed)
 			{
-				s = &song->samples[editor.currSample];
+				moduleSample_t *s = &song->samples[editor.currSample];
 
 				s->loopLength = 0;
 				if (s->length >= s->loopStart)
@@ -3706,7 +3444,7 @@
 				if (ui.samplerScreenShown)
 					setLoopSprites();
 
-				mixerUpdateLoops();
+				updatePaulaLoops();
 				updateWindowTitle(MOD_IS_MODIFIED);
 			}
 			else
@@ -3807,21 +3545,37 @@
 				ui.updateLoadMode = true;
 			}
 
-			ui.askScreenShown = true;
-			ui.askScreenType = ASK_SAVE_SAMPLE;
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-			setStatusMessage("SAVE SAMPLE ?", NO_CARRY);
-			renderAskDialog();
+			if (askBox(ASKBOX_YES_NO, "SAVE SAMPLE ?"))
+				saveSample(CHECK_IF_FILE_EXIST, DONT_GIVE_NEW_FILENAME);
 		}
 		break;
 
 		case PTB_MOD2WAV:
 		{
-			ui.askScreenShown = true;
-			ui.askScreenType = ASK_MOD2WAV;
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-			setStatusMessage("RENDER WAV FILE?", NO_CARRY);
-			renderAskDialog();
+			if (askBox(ASKBOX_MOD2WAV, "PLEASE SELECT"))
+			{
+				char fileName[20 + 4 + 1];
+
+				memset(fileName, 0, sizeof (fileName));
+
+				if (song->header.name[0] != '\0')
+				{
+					for (int32_t i = 0; i < 20; i++)
+					{
+						fileName[i] = (char)tolower(song->header.name[i]);
+						if (fileName[i] == '\0') break;
+						sanitizeFilenameChar(&fileName[i]);
+					}
+
+					strcat(fileName, ".wav");
+				}
+				else
+				{
+					strcpy(fileName, "untitled.wav");
+				}
+
+				mod2WavRender(fileName);
+			}
 		}
 		break;
 
@@ -3834,11 +3588,8 @@
 
 		case PTB_SA_RESAMPLE:
 		{
-			ui.askScreenShown = true;
-			ui.askScreenType = ASK_RESAMPLE;
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-			setStatusMessage("RESAMPLE?", NO_CARRY);
-			renderAskDialog();
+			if (askBox(ASKBOX_YES_NO, "RESAMPLE?"))
+				samplerResample();
 		}
 		break;
 
@@ -3903,12 +3654,7 @@
 		}
 		break;
 
-		case PTB_SA_STOP:
-		{
-			for (i = 0; i < AMIGA_VOICES; i++)
-				mixerKillVoice(i);
-		}
-		break;
+		case PTB_SA_STOP: turnOffVoices(); break;
 
 		case PTB_DO_REFRESH:
 		{
@@ -3954,7 +3700,7 @@
 		{
 			if ((editor.currMode == MODE_IDLE || editor.currMode == MODE_EDIT) && song->header.numOrders < 128)
 			{
-				for (i = 0; i < 127-song->currOrder; i++)
+				for (int32_t i = 0; i < 127-song->currOrder; i++)
 					song->header.order[127-i] = song->header.order[(127-i)-1];
 				song->header.order[song->currOrder] = 0;
 
@@ -3978,7 +3724,7 @@
 		{
 			if ((editor.currMode == MODE_IDLE || editor.currMode == MODE_EDIT) && song->header.numOrders > 1)
 			{
-				for (i = 0; i < 128-song->currOrder; i++)
+				for (int32_t i = 0; i < 128-song->currOrder; i++)
 					song->header.order[song->currOrder+i] = song->header.order[song->currOrder+i+1];
 				song->header.order[127] = 0;
 
@@ -4009,11 +3755,8 @@
 				ui.updateLoadMode = true;
 			}
 
-			ui.askScreenShown = true;
-			ui.askScreenType = ASK_SAVE_MODULE;
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-			setStatusMessage("SAVE MODULE ?", NO_CARRY);
-			renderAskDialog();
+			if (askBox(ASKBOX_YES_NO, "SAVE MODULE ?"))
+				saveModule(CHECK_IF_FILE_EXIST, DONT_GIVE_NEW_FILENAME);
 		}
 		break;
 
@@ -4077,45 +3820,6 @@
 		}
 		break;
 
-		case PTB_PAT2SMP_HI:
-		{
-			ui.askScreenShown = false;
-			ui.answerNo = false;
-			ui.answerYes = true;
-			editor.pat2SmpHQ = true;
-			handleAskYes();
-		}
-		break;
-
-		case PTB_PAT2SMP_LO:
-		{
-			ui.askScreenShown = false;
-			ui.answerNo = false;
-			ui.answerYes = true;
-			editor.pat2SmpHQ = false;
-			handleAskYes();
-		}
-		break;
-
-		case PTB_SUREY:
-		{
-			ui.askScreenShown = false;
-			ui.answerNo = false;
-			ui.answerYes = true;
-			handleAskYes();
-		}
-		break;
-
-		case PTB_PAT2SMP_ABORT:
-		case PTB_SUREN:
-		{
-			ui.askScreenShown = false;
-			ui.answerNo = true;
-			ui.answerYes = false;
-			handleAskNo();
-		}
-		break;
-
 		case PTB_VISUALS:
 		{
 			if (ui.aboutScreenShown)
@@ -4138,11 +3842,8 @@
 
 		case PTB_QUIT:
 		{
-			ui.askScreenShown = true;
-			ui.askScreenType = ASK_QUIT;
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-			setStatusMessage("REALLY QUIT ?", NO_CARRY);
-			renderAskDialog();
+			if (askBox(ASKBOX_YES_NO, "REALLY QUIT ?"))
+				ui.throwExit = true;
 		}
 		break;
 
@@ -4361,58 +4062,32 @@
 
 		case PTB_CLEAR:
 		{
-			ui.clearScreenShown = true;
-			pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-			setStatusMessage("PLEASE SELECT", NO_CARRY);
-			renderClearScreen();
-		}
-		break;
+			int32_t result = askBox(ASKBOX_CLEAR, "PLEASE SELECT");
+			if (result == ASKBOX_CLEAR_CANCEL)
+				break;
 
-		case PTB_CLEARSONG:
-		{
-			ui.clearScreenShown = false;
-			removeClearScreen();
 			editor.playMode = PLAY_MODE_NORMAL;
 			modStop();
-			clearSong();
-			editor.currMode = MODE_IDLE;
-			pointerSetMode(POINTER_MODE_IDLE, DO_CARRY);
-			statusAllRight();
-		}
-		break;
 
-		case PTB_CLEARSAMPLES:
-		{
-			ui.clearScreenShown = false;
-			removeClearScreen();
-			editor.playMode = PLAY_MODE_NORMAL;
-			modStop();
-			clearSamples();
-			editor.currMode = MODE_IDLE;
-			pointerSetMode(POINTER_MODE_IDLE, DO_CARRY);
-			statusAllRight();
-		}
-		break;
+			if (result == ASKBOX_CLEAR_SONG)
+			{
+				clearSong();
+			}
+			else if (result == ASKBOX_CLEAR_SAMPLES)
+			{
+				clearSamples();
+			}
+			else if (result == ASKBOX_CLEAR_ALL)
+			{
+				clearSong();
+				clearSamples();
+			}
 
-		case PTB_CLEARALL:
-		{
-			ui.clearScreenShown = false;
-			removeClearScreen();
-			editor.playMode = PLAY_MODE_NORMAL;
-			modStop();
-			clearAll();
 			editor.currMode = MODE_IDLE;
 			pointerSetMode(POINTER_MODE_IDLE, DO_CARRY);
 			statusAllRight();
-		}
-		break;
 
-		case PTB_CLEARCANCEL:
-		{
-			ui.clearScreenShown = false;
-			removeClearScreen();
-			setPrevStatusMessage();
-			pointerSetPreviousMode();
+			updateWindowTitle(MOD_IS_MODIFIED);
 		}
 		break;
 
@@ -4508,7 +4183,7 @@
 		{
 			if (!editor.sampleZero)
 			{
-				oldVal = song->samples[editor.currSample].loopStart;
+				int32_t oldVal = song->samples[editor.currSample].loopStart;
 				sampleRepeatUpButton(INCREMENT_SLOW);
 				if (song->samples[editor.currSample].loopStart != oldVal)
 					updateWindowTitle(MOD_IS_MODIFIED);
@@ -4520,7 +4195,7 @@
 		{
 			if (!editor.sampleZero)
 			{
-				oldVal = song->samples[editor.currSample].loopStart;
+				int32_t oldVal = song->samples[editor.currSample].loopStart;
 				sampleRepeatDownButton(INCREMENT_SLOW);
 				if (song->samples[editor.currSample].loopStart != oldVal)
 					updateWindowTitle(MOD_IS_MODIFIED);
@@ -4532,7 +4207,7 @@
 		{
 			if (!editor.sampleZero)
 			{
-				oldVal = song->samples[editor.currSample].loopLength;
+				int32_t oldVal = song->samples[editor.currSample].loopLength;
 				sampleRepeatLengthUpButton(INCREMENT_SLOW);
 				if (song->samples[editor.currSample].loopLength != oldVal)
 					updateWindowTitle(MOD_IS_MODIFIED);
@@ -4544,7 +4219,7 @@
 		{
 			if (!editor.sampleZero)
 			{
-				oldVal = song->samples[editor.currSample].loopLength;
+				int32_t oldVal = song->samples[editor.currSample].loopLength;
 				sampleRepeatLengthDownButton(INCREMENT_SLOW);
 				if (song->samples[editor.currSample].loopLength != oldVal)
 					updateWindowTitle(MOD_IS_MODIFIED);
--- a/src/pt2_mouse.h
+++ b/src/pt2_mouse.h
@@ -14,15 +14,6 @@
 	PTB_SAMPLENAME,
 	PTB_LOADSAMPLE,
 
-	// ASK DIALOG
-	PTB_SUREY,
-	PTB_SUREN,
-
-	// PAT2SMP ASK DIALOG
-	PTB_PAT2SMP_HI,
-	PTB_PAT2SMP_LO,
-	PTB_PAT2SMP_ABORT,
-
 	// POS ED. SCREEN
 	PTB_PE_BADGE,
 	PTB_PE_PATT,
@@ -138,12 +129,6 @@
 	PTB_DO_SCROLLBOT,
 	PTB_DO_FILEAREA,
 
-	// CLEAR
-	PTB_CLEARSONG,
-	PTB_CLEARSAMPLES,
-	PTB_CLEARALL,
-	PTB_CLEARCANCEL,
-
 	// MAIN SCREEN
 	PTB_QUIT,
 	PTB_PLAY,
@@ -257,8 +242,8 @@
 
 #define NUM_CURSORS 6
 
-extern SDL_Cursor *cursors[NUM_CURSORS];
-
+void sampleUpButton(void);
+void sampleDownButton(void);
 void setMsgPointer(void);
 void setErrPointer(void);
 void pointerSetMode(uint8_t pointerMode, bool carry);
@@ -267,7 +252,6 @@
 bool setSystemCursor(SDL_Cursor *cur);
 void freeMouseCursors(void);
 bool createMouseCursors(void);
-
 void readMouseXY(void);
 void updateMouseScaling(void);
 void mouseWheelUpHandler(void);
@@ -276,3 +260,5 @@
 void mouseButtonDownHandler(uint8_t mouseButton);
 void handleGUIButtonRepeat(void);
 void updateMouseCounters(void);
+
+extern SDL_Cursor *cursors[NUM_CURSORS];
--- a/src/pt2_pat2smp.c
+++ b/src/pt2_pat2smp.c
@@ -3,29 +3,213 @@
 #include <crtdbg.h>
 #endif
 
+#include <stdio.h>
 #include <stdint.h>
 #include <stdbool.h>
-#include "pt2_header.h"
+#include <math.h>
 #include "pt2_config.h"
 #include "pt2_helpers.h"
 #include "pt2_visuals.h"
-#include "pt2_mouse.h"
 #include "pt2_audio.h"
 #include "pt2_sampler.h"
 #include "pt2_textout.h"
-#include "pt2_rcfilter.h"
-#include "pt2_pat2smp.h"
+#include "pt2_tables.h"
 #include "pt2_downsample2x.h"
+#include "pt2_replayer.h"
 
-bool intMusic(void); // pt2_replayer.c
-void storeTempVariables(void); // pt2_replayer.c
+static const char *noteStr[12] =
+{
+	"c-", "c#", "d-", "d#", "e-", "f-", "f#", "g-", "g#", "a-", "a#", "b-"
+};
 
-void doPat2Smp(void)
+static bool pat2SmpEndReached;
+static uint8_t pat2SmpFinetune = 4, pat2SmpNote = 33; // A-3 finetune +4 (default, max safe frequency)
+static uint8_t pat2SmpStartRow = 0, pat2SmpRows = 32;
+static int32_t pat2SmpPos;
+static double *dMixBufferL, *dMixBufferR, *dPat2SmpBuf, dPat2SmpFreq, dSeconds;
+
+static void pat2SmpOutputAudio(int32_t numSamples)
 {
-	moduleSample_t *s;
+	int32_t samplesTodo = numSamples;
+	if (pat2SmpPos+samplesTodo > config.maxSampleLength)
+		samplesTodo = config.maxSampleLength - pat2SmpPos;
 
-	ui.pat2SmpDialogShown = false;
+	paulaGenerateSamples(dMixBufferL, dMixBufferR, samplesTodo*2); // 2x oversampling
 
+	for (int32_t i = 0; i < samplesTodo; i++)
+	{
+		// 2x downsampling (decimation)
+		double dL = decimate2x_L(dMixBufferL[(i << 1) + 0], dMixBufferL[(i << 1) + 1]);
+		double dR = decimate2x_R(dMixBufferR[(i << 1) + 0], dMixBufferR[(i << 1) + 1]);
+
+		dPat2SmpBuf[pat2SmpPos+i] = (dL + dR) * 0.5; // stereo -> mono, normalized to -128..127 later
+	}
+
+	pat2SmpPos += samplesTodo;
+	if (pat2SmpPos >= config.maxSampleLength)
+		pat2SmpEndReached = true;
+}
+
+void pat2SmpDrawNote(void)
+{
+	fillRect(165, 51, FONT_CHAR_W*3, FONT_CHAR_H, video.palette[PAL_GENBKG]);
+	textOut(165, 51, noteNames1[2+pat2SmpNote], video.palette[PAL_GENTXT]);
+}
+
+void pat2SmpDrawFinetune(void)
+{
+	fillRect(173, 62, FONT_CHAR_W*2, FONT_CHAR_H, video.palette[PAL_GENBKG]);
+	textOut(173, 62, ftuneStrTab[pat2SmpFinetune], video.palette[PAL_GENTXT]);
+}
+
+void pat2SmpDrawFrequency(void)
+{
+	const int32_t maxTextWidth = 19 * FONT_CHAR_W;
+	fillRect(164, 74, maxTextWidth, FONT_CHAR_H, video.palette[PAL_GENBKG]);
+
+	if (dPat2SmpFreq*2.0 < PAL_PAULA_MAX_HZ)
+	{
+		textOut(164, 74, "TOO LOW!", video.palette[PAL_GENTXT]);
+	}
+	else
+	{
+		char textBuf[32];
+		sprintf(textBuf, "%dHz (%.1f secs)", (int32_t)(dPat2SmpFreq + 0.5), dSeconds);
+		textOut(164, 74, textBuf, video.palette[PAL_GENTXT]);
+	}
+}
+
+void pat2SmpDrawStartRow(void)
+{
+	fillRect(276, 51, FONT_CHAR_W*2, FONT_CHAR_H, video.palette[PAL_GENBKG]);
+	printTwoDecimals(276, 51, pat2SmpStartRow, video.palette[PAL_GENTXT]);
+}
+
+void pat2SmpDrawRows(void)
+{
+	fillRect(276, 62, FONT_CHAR_W*2, FONT_CHAR_H, video.palette[PAL_GENBKG]);
+	printTwoDecimals(276, 62, pat2SmpRows, video.palette[PAL_GENTXT]);
+}
+
+void pat2SmpCalculateFreq(void)
+{
+	if (pat2SmpFinetune > 15)
+		pat2SmpFinetune = 15;
+
+	if (pat2SmpNote > 35)
+		pat2SmpNote = 35;
+
+	dPat2SmpFreq = PAULA_PAL_CLK / (double)periodTable[(pat2SmpFinetune * 37) + pat2SmpNote];
+	if (dPat2SmpFreq > PAL_PAULA_MAX_HZ)
+		dPat2SmpFreq = PAL_PAULA_MAX_HZ;
+
+	dSeconds = config.maxSampleLength / dPat2SmpFreq;
+	pat2SmpDrawFrequency();
+}
+
+void pat2SmpNoteUp(void)
+{
+	if (pat2SmpNote < 35)
+	{
+		pat2SmpNote++;
+		pat2SmpDrawNote();
+
+		if (pat2SmpNote == 35 && pat2SmpFinetune < 8) // high-limit to B-3 finetune 0
+		{
+			pat2SmpFinetune = 0;
+			pat2SmpDrawFinetune();
+		}
+
+		pat2SmpCalculateFreq();
+	}
+}
+
+void pat2SmpNoteDown(void)
+{
+	if (pat2SmpNote > 23)
+	{
+		pat2SmpNote--;
+		pat2SmpDrawNote();
+
+		if (pat2SmpNote == 23 && pat2SmpFinetune > 7) // low-limit to B-2 finetune 0
+		{
+			pat2SmpFinetune = 0;
+			pat2SmpDrawFinetune();
+		}
+
+		pat2SmpCalculateFreq();
+	}
+}
+
+void pat2SmpSetFinetune(uint8_t finetune)
+{
+	pat2SmpFinetune = finetune & 0x0F;
+	pat2SmpDrawFinetune();
+	pat2SmpCalculateFreq();
+}
+
+void pat2SmpFinetuneUp(void)
+{
+	if ((pat2SmpFinetune & 0xF) != 7)
+		pat2SmpFinetune = (pat2SmpFinetune + 1) & 0xF;
+
+	if (pat2SmpNote == 35 && pat2SmpFinetune < 8) // for B-3, high-limit finetune to 0
+		pat2SmpFinetune = 0;
+
+	pat2SmpDrawFinetune();
+	pat2SmpCalculateFreq();
+}
+
+void pat2SmpFinetuneDown(void)
+{
+	if ((pat2SmpFinetune & 0xF) != 8)
+		pat2SmpFinetune = (pat2SmpFinetune - 1) & 0xF;
+
+	if (pat2SmpNote == 23 && pat2SmpFinetune > 7) // for B-2, low-limit finetune to 0
+		pat2SmpFinetune = 0;
+
+	pat2SmpDrawFinetune();
+	pat2SmpCalculateFreq();
+}
+
+void pat2SmpStartRowUp(void)
+{
+	if (pat2SmpStartRow+pat2SmpRows < 64)
+	{
+		pat2SmpStartRow++;
+		pat2SmpDrawStartRow();
+	}
+}
+
+void pat2SmpStartRowDown(void)
+{
+	if (pat2SmpStartRow > 0)
+	{
+		pat2SmpStartRow--;
+		pat2SmpDrawStartRow();
+	}
+}
+
+void pat2SmpRowsUp(void)
+{
+	if (pat2SmpStartRow+pat2SmpRows < 64)
+	{
+		pat2SmpRows++;
+		pat2SmpDrawRows();
+	}
+}
+
+void pat2SmpRowsDown(void)
+{
+	if (pat2SmpRows > 1)
+	{
+		pat2SmpRows--;
+		pat2SmpDrawRows();
+	}
+}
+
+void pat2SmpRender(void)
+{
 	if (editor.sampleZero)
 	{
 		statusNotSampleZero();
@@ -32,100 +216,141 @@
 		return;
 	}
 
-	editor.dPat2SmpBuf = (double *)malloc(config.maxSampleLength * sizeof (double));
-	if (editor.dPat2SmpBuf == NULL)
+	dPat2SmpBuf = (double *)malloc(config.maxSampleLength * sizeof (double));
+	if (dPat2SmpBuf == NULL)
 	{
 		statusOutOfMemory();
 		return;
 	}
 
+	const double dAudioFrequency = dPat2SmpFreq * 2.0; // *2 for oversampling
+	const uint32_t maxSamplesToMix = (int32_t)ceil(dAudioFrequency / (REPLAYER_MIN_BPM / 2.5)); // *2 for oversampling
+
+	dMixBufferL = (double *)malloc((maxSamplesToMix + 1) * sizeof (double));
+	dMixBufferR = (double *)malloc((maxSamplesToMix + 1) * sizeof (double));
+
+	if (dMixBufferL == NULL || dMixBufferR == NULL)
+	{
+		free(dPat2SmpBuf);
+
+		if (dMixBufferL != NULL) free(dMixBufferL);
+		if (dMixBufferR != NULL) free(dMixBufferR);
+
+		statusOutOfMemory();
+		return;
+	}
+
 	const int8_t oldRow = editor.songPlaying ? 0 : song->currRow;
 
-	editor.isSMPRendering = true; // this must be set before restartSong()
+	editor.pat2SmpOngoing = true; // this must be set first
+
+	// do some prep work
+	generateBpmTable(dPat2SmpFreq, editor.timingMode == TEMPO_MODE_VBLANK);
+	paulaSetOutputFrequency(dPat2SmpFreq, AUDIO_2X_OVERSAMPLING);
 	storeTempVariables();
-	restartSong();
-	song->row = oldRow;
-	song->currRow = song->row;
+	restartSong(); // this also updates BPM (samples per tick) with the PAT2SMP audio output rate
+	clearMixerDownsamplerStates();
 
-	editor.blockMarkFlag = false;
-	pointerSetMode(POINTER_MODE_MSG2, NO_CARRY);
-	setStatusMessage("RENDERING...", NO_CARRY);
-	modSetTempo(song->currBPM, true);
-	editor.pat2SmpPos = 0;
-
+	song->currRow = song->row = 0;
+	pat2SmpPos = 0;
 	int64_t tickSampleCounter64 = 0;
 
-	clearMixerDownsamplerStates();
+	bool lastRow = false;
 
-	editor.smpRenderingDone = false;
-	while (!editor.smpRenderingDone && editor.songPlaying)
+	pat2SmpEndReached = false;
+	while (!pat2SmpEndReached && editor.songPlaying)
 	{
+		//int8_t prevRow = song->row;
 		if (tickSampleCounter64 <= 0) // new replayer tick
 		{
 			if (!intMusic())
-				editor.smpRenderingDone = true; // this tick is the last tick
+				lastRow = true;
 
+			if (song->row > pat2SmpStartRow+pat2SmpRows)
+				break; // we rendered as many rows as requested (don't write this tick to output)
+
 			tickSampleCounter64 += audio.samplesPerTick64;
 		}
 
-		int32_t remainingTick = (tickSampleCounter64 + UINT32_MAX) >> 32; // ceil (rounded upwards)
-		outputAudio(NULL, remainingTick);
-		tickSampleCounter64 -= (int64_t)remainingTick << 32;
+		if (lastRow && song->tick == song->speed-1)
+			pat2SmpEndReached = true;
+
+		const uint32_t samplesTodo = ((uint64_t)tickSampleCounter64 + UINT32_MAX) >> 32; // ceil (rounded upwards)
+		if (lastRow || song->row > pat2SmpStartRow)
+			pat2SmpOutputAudio(samplesTodo);
+
+		tickSampleCounter64 -= (uint64_t)samplesTodo << 32;
 	}
-	editor.isSMPRendering = false;
+	editor.pat2SmpOngoing = false;
 
-	clearMixerDownsamplerStates();
-	resetSong();
+	free(dMixBufferL);
+	free(dMixBufferR);
 
-	int32_t renderLength = editor.pat2SmpPos;
+	song->currRow = song->row = oldRow; // set back old row
 
-	s = &song->samples[editor.currSample];
+	// set back audio configurations
+	paulaSetOutputFrequency(audio.outputRate, audio.oversamplingFlag);
+	generateBpmTable(audio.outputRate, editor.timingMode == TEMPO_MODE_VBLANK);
+	clearMixerDownsamplerStates();
+	resetSong(); // this also updates BPM (samples per tick) with the tracker's audio output rate
 
-	// set back old row
-	song->currRow = song->row = oldRow;
+	moduleSample_t *s = &song->samples[editor.currSample];
 
 	// normalize and quantize to 8-bit
 
-	double dAmp = 1.0;
-	const double dPeak = getDoublePeak(editor.dPat2SmpBuf, renderLength);
+	const double dPeak = getDoublePeak(dPat2SmpBuf, pat2SmpPos);
+
+	double dAmp = INT8_MAX;
 	if (dPeak > 0.0)
 		dAmp = INT8_MAX / dPeak;
 
 	int8_t *smpPtr = &song->sampleData[s->offset];
-	for (int32_t i = 0; i < renderLength; i++)
+	for (int32_t i = 0; i < pat2SmpPos; i++)
 	{
-		const int32_t smp = (const int32_t)round(editor.dPat2SmpBuf[i] * dAmp);
+		double dSmp = dPat2SmpBuf[i] * dAmp;
+
+		// faster than calling round()
+		     if (dSmp < 0.0) dSmp -= 0.5;
+		else if (dSmp > 0.0) dSmp += 0.5;
+
+		int32_t smp = (int32_t)dSmp;
 		assert(smp >= -128 && smp <= 127); // shouldn't happen according to dAmp
 		smpPtr[i] = (int8_t)smp;
 	}
 
-	free(editor.dPat2SmpBuf);
+	free(dPat2SmpBuf);
+
+	int32_t newSampleLength = (pat2SmpPos + 1) & ~1;
+	if (newSampleLength > config.maxSampleLength)
+		newSampleLength = config.maxSampleLength;
 	
 	// clear the rest of the sample (if not full)
-	if (renderLength < config.maxSampleLength)
-		memset(&song->sampleData[s->offset+renderLength], 0, config.maxSampleLength - renderLength);
+	if (newSampleLength < config.maxSampleLength)
+		memset(&song->sampleData[s->offset+newSampleLength], 0, config.maxSampleLength - newSampleLength);
 
-	if (editor.pat2SmpHQ)
-	{
-		strcpy(s->text, "pat2smp(a-3 ftune:+4)");
-		s->fineTune = 4;
-	}
-	else
-	{
-		strcpy(s->text, "pat2smp(e-3 ftune: 0)");
-		s->fineTune = 0;
-	}
+	// set sample attributes
 
-	s->length = renderLength;
+	s->length = newSampleLength;
 	s->volume = 64;
+	s->fineTune = pat2SmpFinetune;
 	s->loopStart = 0;
 	s->loopLength = 2;
 
-	editor.samplePos = 0;
+	// set sample name
+
+	const int32_t note = pat2SmpNote % 12;
+	const int32_t octave = (pat2SmpNote / 12) + 1;
+
+	if (pat2SmpFinetune == 0)
+		sprintf(s->text, "pat2smp(%s%d ftune: 0)", noteStr[note], octave);
+	else if (pat2SmpFinetune < 8)
+		sprintf(s->text, "pat2smp(%s%d ftune:+%d)", noteStr[note], octave, pat2SmpFinetune);
+	else
+		sprintf(s->text, "pat2smp(%s%d ftune:-%d)", noteStr[note], octave, (pat2SmpFinetune^7)-7);
+
 	fixSampleBeep(s);
 	updateCurrSample();
 
-	pointerSetMode(POINTER_MODE_IDLE, DO_CARRY);
-	displayMsg("ROWS RENDERED!");
-	setMsgPointer();
+	editor.samplePos = 0; // reset Edit Op. sample position
+	updateWindowTitle(MOD_IS_MODIFIED);
 }
--- a/src/pt2_pat2smp.h
+++ b/src/pt2_pat2smp.h
@@ -1,11 +1,21 @@
 #pragma once
 
-#include "pt2_header.h"
+#include <stdint.h>
 
-#define PAT2SMP_HI_PERIOD 124 /* A-3 finetune +4, 28603.99Hz */
-#define PAT2SMP_LO_PERIOD 170 /* E-3 finetune  0, 20864.08Hz */
-
-#define PAT2SMP_HI_FREQ ((double)PAULA_PAL_CLK / PAT2SMP_HI_PERIOD)
-#define PAT2SMP_LO_FREQ ((double)PAULA_PAL_CLK / PAT2SMP_LO_PERIOD)
-
-void doPat2Smp(void);
+void pat2SmpDrawNote(void);
+void pat2SmpDrawFinetune(void);
+void pat2SmpDrawFrequency(void);
+void pat2SmpDrawFinetune(void);
+void pat2SmpDrawStartRow(void);
+void pat2SmpDrawRows(void);
+void pat2SmpCalculateFreq(void);
+void pat2SmpNoteUp(void);
+void pat2SmpNoteDown(void);
+void pat2SmpSetFinetune(uint8_t finetune);
+void pat2SmpFinetuneUp(void);
+void pat2SmpFinetuneDown(void);
+void pat2SmpStartRowUp(void);
+void pat2SmpStartRowDown(void);
+void pat2SmpRowsUp(void);
+void pat2SmpRowsDown(void);
+void pat2SmpRender(void);
--- a/src/pt2_pattern_viewer.c
+++ b/src/pt2_pattern_viewer.c
@@ -1,6 +1,4 @@
 #include <stdint.h>
-#include <stdbool.h>
-#include "pt2_header.h"
 #include "pt2_tables.h"
 #include "pt2_textout.h"
 #include "pt2_structs.h"
@@ -15,13 +13,11 @@
 
 static int32_t periodToNote(int32_t period) // 0 = no note, 1 = illegal note, 2..37 = note
 {
-	int32_t beg, end, tableVal;
-
 	if (period == 0)
 		return 0;
 
-	beg = 0;
-	end = 36 - 1;
+	int32_t beg = 0;
+	int32_t end = 36 - 1;
 
 	// do binary search
 	while (beg <= end)
@@ -28,7 +24,7 @@
 	{
 		const int32_t mid = (beg + end) >> 1;
 
-		tableVal = periodTable[mid];
+		int32_t tableVal = periodTable[mid];
 		if (period == tableVal)
 			return 2+mid;
 
@@ -44,18 +40,14 @@
 static void drawPatternNormal(void)
 {
 	const char **noteNames;
-	char smpChar;
-	int32_t row, j, x, y;
-	note_t *patt, *note;
-
 	if (config.accidental)
 		noteNames = (const char **)noteNames2;
 	else
 		noteNames = (const char **)noteNames1;
 
-	patt = song->patterns[song->currPattern];
-	row = song->currRow - MIDDLE_ROW;
-	y = 140;
+	note_t *patt = song->patterns[song->currPattern];
+	int32_t row = song->currRow - MIDDLE_ROW;
+	int32_t y = 140;
 
 	for (int32_t i = 0; i < VISIBLE_ROWS; i++, y += 7, row++)
 	{
@@ -75,14 +67,14 @@
 				y++;
 				printTwoDecimalsBigBg(8, y, row, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 
-				note = patt + (row << 2);
-				x = 32;
-				for (j = 0; j < AMIGA_VOICES; j++, note++)
+				note_t *note = patt + (row << 2);
+				int32_t x = 32;
+				for (int32_t j = 0; j < PAULA_VOICES; j++, note++)
 				{
 					textOutBigBg(x, y, noteNames[periodToNote(note->period)], video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 					x += 8*3;
 
-					smpChar = (config.blankZeroFlag && !(note->sample & 0xF0)) ? ' ' : hexTable[note->sample >> 4];
+					char smpChar = (config.blankZeroFlag && !(note->sample & 0xF0)) ? ' ' : hexTable[note->sample >> 4];
 					charOutBigBg(x, y, smpChar, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 					x += 8;
 
@@ -101,14 +93,14 @@
 			{
 				printTwoDecimalsBg(8, y, row, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
 
-				note = patt + (row << 2);
-				x = 32;
-				for (j = 0; j < AMIGA_VOICES; j++, note++)
+				note_t *note = patt + (row << 2);
+				int32_t x = 32;
+				for (int32_t j = 0; j < PAULA_VOICES; j++, note++)
 				{
 					textOutBg(x, y, noteNames[periodToNote(note->period)], video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
 					x += 8*3;
 
-					smpChar = (config.blankZeroFlag && !(note->sample & 0xF0)) ? ' ' : hexTable[note->sample >> 4];
+					char smpChar = (config.blankZeroFlag && !(note->sample & 0xF0)) ? ' ' : hexTable[note->sample >> 4];
 					charOutBg(x, y, smpChar, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
 					x += 8;
 
@@ -128,19 +120,15 @@
 
 static void drawPatternDotted(void)
 {
-	char smpChar;
 	const char **noteNames;
-	int32_t row, j, x, y;
-	note_t *patt, *note;
-
 	if (config.accidental)
 		noteNames = (const char **)noteNames4;
 	else
 		noteNames = (const char **)noteNames3;
 
-	patt = song->patterns[song->currPattern];
-	row = song->currRow - MIDDLE_ROW;
-	y = 140; 
+	note_t *patt = song->patterns[song->currPattern];
+	int32_t row = song->currRow - MIDDLE_ROW;
+	int32_t y = 140;
 
 	for (int32_t i = 0; i < VISIBLE_ROWS; i++, y += 7, row++)
 	{
@@ -160,9 +148,9 @@
 				y++;
 				printTwoDecimalsBigBg(8, y, row, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 
-				note = patt + (row << 2);
-				x = 32;
-				for (j = 0; j < AMIGA_VOICES; j++, note++)
+				note_t *note = patt + (row << 2);
+				int32_t x = 32;
+				for (int32_t j = 0; j < PAULA_VOICES; j++, note++)
 				{
 					textOutBigBg(x, y, noteNames[periodToNote(note->period)], video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 					x += 8*3;
@@ -174,7 +162,7 @@
 					}
 					else
 					{
-						smpChar = (note->sample & 0xF0) ? hexTable[note->sample >> 4] : 0x02;
+						char smpChar = (note->sample & 0xF0) ? hexTable[note->sample >> 4] : 0x02;
 						charOutBigBg(x, y, smpChar, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 						x += 8;
 						printOneHexBigBg(x, y, note->sample & 0x0F, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
@@ -201,9 +189,9 @@
 				printTwoDecimalsBg(8, y, row, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
 
 				// pattern data
-				note = patt + (row << 2);
-				x = 32;
-				for (j = 0; j < AMIGA_VOICES; j++, note++)
+				note_t *note = patt + (row << 2);
+				int32_t x = 32;
+				for (int32_t j = 0; j < PAULA_VOICES; j++, note++)
 				{
 					textOutBg(x, y, noteNames[periodToNote(note->period)], video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
 					x += 8*3;
@@ -215,7 +203,7 @@
 					}
 					else
 					{
-						smpChar = (note->sample & 0xF0) ? hexTable[note->sample >> 4] : 0x02;
+						char smpChar = (note->sample & 0xF0) ? hexTable[note->sample >> 4] : 0x02;
 						charOutBg(x, y, smpChar, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
 						x += 8;
 						printOneHexBg(x, y, note->sample & 0x0F, video.palette[PAL_PATTXT], video.palette[PAL_BACKGRD]);
--- /dev/null
+++ b/src/pt2_paula.c
@@ -1,0 +1,289 @@
+/* Simple Paula emulator by 8bitbubsy (with BLEP synthesis by aciddose).
+** The Amiga filters are handled in pt2_amigafilters.c
+**
+** Limitation: The audio output frequency can't be below 31389Hz ( ceil(PAULA_PAL_CLK / 113.0) )
+*/
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "pt2_audio.h"
+#include "pt2_paula.h"
+#include "pt2_blep.h"
+#include "pt2_sync.h"
+#include "pt2_scopes.h" 
+#include "pt2_config.h"
+
+paulaVoice_t paula[PAULA_VOICES]; // globalized
+
+static blep_t blep[PAULA_VOICES];
+static double dPeriodToDeltaDiv;
+
+void paulaSetOutputFrequency(double dAudioFreq, bool oversampling2x)
+{
+	dPeriodToDeltaDiv = PAULA_PAL_CLK / dAudioFreq;
+	if (oversampling2x)
+		dPeriodToDeltaDiv /= 2.0;
+}
+
+void paulaSetPeriod(int32_t ch, uint16_t period)
+{
+	paulaVoice_t *v = &paula[ch];
+
+	int32_t realPeriod = period;
+	if (realPeriod == 0)
+		realPeriod = 1+65535; // confirmed behavior on real Amiga
+	else if (realPeriod < 113)
+		realPeriod = 113; // close to what happens on real Amiga (and needed for BLEP synthesis)
+
+	// to be read on next sampling step (or on DMA trigger)
+	v->AUD_PER_delta = dPeriodToDeltaDiv / realPeriod;
+	v->AUD_PER_deltamul = 1.0 / v->AUD_PER_delta; // for BLEP synthesis (prevents division in inner mixing loop)
+
+	// handle BLEP synthesis edge-cases
+
+	if (v->dLastDelta == 0.0)
+		v->dLastDelta = v->AUD_PER_delta;
+
+	if (v->dLastDeltaMul == 0.0)
+		v->dLastDeltaMul = v->AUD_PER_deltamul;
+
+	// handle visualizers
+
+	if (editor.songPlaying)
+	{
+		v->syncPeriod = realPeriod;
+		v->syncFlags |= SET_SCOPE_PERIOD;
+	}
+	else
+	{
+		scopeSetPeriod(ch, realPeriod);
+	}
+}
+
+void paulaSetVolume(int32_t ch, uint16_t vol)
+{
+	paulaVoice_t *v = &paula[ch];
+
+	int32_t realVol = vol & 127;
+	if (realVol > 64)
+		realVol = 64;
+
+	// multiplying sample point by this also scales the sample from -128..127 -> -1.0 .. ~0.99
+	v->AUD_VOL = realVol * (1.0 / (128.0 * 64.0));
+
+	// handle visualizers
+
+	if (editor.songPlaying)
+	{
+		v->syncVolume = (uint8_t)realVol;
+		v->syncFlags |= SET_SCOPE_VOLUME;
+	}
+	else
+	{
+		scope[ch].volume = (uint8_t)realVol;
+	}
+}
+
+void paulaSetLength(int32_t ch, uint16_t len)
+{
+	paulaVoice_t *v = &paula[ch];
+
+	v->AUD_LEN = len;
+
+	// handle visualizers
+
+	if (editor.songPlaying)
+		v->syncFlags |= SET_SCOPE_LENGTH;
+	else
+		scope[ch].newLength = len * 2;
+}
+
+void paulaSetData(int32_t ch, const int8_t *src)
+{
+	paulaVoice_t *v = &paula[ch];
+
+	// if pointer is NULL, use empty 128kB sample slot after sample 31 in the tracker
+	if (src == NULL)
+		src = &song->sampleData[config.reservedSampleOffset];
+
+	v->AUD_LC = src;
+
+	// handle visualizers
+
+	if (editor.songPlaying)
+		v->syncFlags |= SET_SCOPE_DATA;
+	else
+		scope[ch].newData = src;
+}
+
+static inline void refetchPeriod(paulaVoice_t *v) // Paula stage
+{
+	// set BLEP stuff
+	v->dLastPhase = v->dPhase;
+	v->dLastDelta = v->dDelta;
+	v->dLastDeltaMul = v->dDeltaMul;
+	v->dBlepOffset = v->dLastPhase * v->dLastDeltaMul;
+
+	// Paula only updates period (delta) during period refetching (this stage)
+	v->dDelta = v->AUD_PER_delta;
+	v->dDeltaMul = v->AUD_PER_deltamul;
+
+	v->nextSampleStage = true;
+}
+
+static void startPaulaDMA(int32_t ch)
+{
+	paulaVoice_t *v = &paula[ch];
+
+	// if pointer is NULL, use empty 128kB sample slot after sample 31 in the tracker
+	if (v->AUD_LC == NULL)
+		v->AUD_LC = &song->sampleData[config.reservedSampleOffset];
+
+	// immediately update AUD_LC/AUD_LEN
+	v->location = v->AUD_LC;
+	v->lengthCounter = v->AUD_LEN;
+
+	// make Paula fetch new samples immediately
+	v->sampleCounter = 0;
+	v->DMATriggerFlag = true;
+
+	refetchPeriod(v);
+	v->dPhase = 0.0; // kludge: must be cleared *after* refetchPeriod()
+
+	v->DMA_active = true;
+
+	// handle visualizers
+
+	if (editor.songPlaying)
+	{
+		v->syncTriggerData = v->AUD_LC;
+		v->syncTriggerLength = v->AUD_LEN * 2;
+		v->syncFlags |= TRIGGER_SCOPE;
+	}
+	else
+	{
+		scope_t *s = &scope[ch];
+		s->newData = v->AUD_LC;
+		s->newLength = v->AUD_LEN * 2;
+		scopeTrigger(ch);
+	}
+}
+
+static void stopPaulaDMA(int32_t ch)
+{
+	paulaVoice_t *v = &paula[ch];
+
+	v->DMA_active = false;
+
+	// handle visualizers
+ 
+	if (editor.songPlaying)
+		v->syncFlags |= STOP_SCOPE;
+	else
+		scope[ch].active = false;
+}
+
+void paulaSetDMACON(uint16_t bits) // $DFF096 register write (only controls paula DMAs)
+{
+	if (bits & 0x8000)
+	{
+		// set
+		if (bits & 1) startPaulaDMA(0);
+		if (bits & 2) startPaulaDMA(1);
+		if (bits & 4) startPaulaDMA(2);
+		if (bits & 8) startPaulaDMA(3);
+	}
+	else
+	{
+		// clear
+		if (bits & 1) stopPaulaDMA(0);
+		if (bits & 2) stopPaulaDMA(1);
+		if (bits & 4) stopPaulaDMA(2);
+		if (bits & 8) stopPaulaDMA(3);
+	}
+}
+
+static inline void nextSample(paulaVoice_t *v, blep_t *b)
+{
+	if (v->sampleCounter == 0)
+	{
+		// it's time to read new samples from DMA
+
+		// don't update AUD_LEN/AUD_LC yet on DMA trigger
+		if (!v->DMATriggerFlag)
+		{
+			if (--v->lengthCounter == 0)
+			{
+				v->lengthCounter = v->AUD_LEN;
+				v->location = v->AUD_LC;
+			}
+		}
+
+		v->DMATriggerFlag = false;
+
+		// fill DMA data buffer
+		v->AUD_DAT[0] = *v->location++;
+		v->AUD_DAT[1] = *v->location++;
+		v->sampleCounter = 2;
+	}
+
+	/* Pre-compute current sample point.
+	** Output volume is only read from AUDxVOL at this stage,
+	** and we don't emulate volume PWM anyway, so we can
+	** pre-multiply by volume here.
+	*/
+	v->dSample = v->AUD_DAT[0] * v->AUD_VOL; // -128..127 * 0.0 .. 1.0
+
+	// fill BLEP buffer if the new sample differs from the old one
+	if (v->dSample != b->dLastValue)
+	{
+		if (v->dLastDelta > v->dLastPhase)
+			blepAdd(b, v->dBlepOffset, b->dLastValue - v->dSample);
+
+		b->dLastValue = v->dSample;
+	}
+
+	// progress AUD_DAT buffer
+	v->AUD_DAT[0] = v->AUD_DAT[1];
+	v->sampleCounter--;
+}
+
+void paulaGenerateSamples(double *dOutL, double *dOutR, int32_t numSamples)
+{
+	double *dMixBufSelect[PAULA_VOICES] = { dOutL, dOutR, dOutR, dOutL };
+
+	memset(dOutL, 0, numSamples * sizeof (double));
+	memset(dOutR, 0, numSamples * sizeof (double));
+
+	paulaVoice_t *v = paula;
+	blep_t *b = blep;
+
+	for (int32_t i = 0; i < PAULA_VOICES; i++, v++, b++)
+	{
+		if (!v->DMA_active || v->location == NULL || v->AUD_LC == NULL)
+			continue;
+
+		double *dMixBuffer = dMixBufSelect[i]; // what output channel to mix into (L, R, R, L)
+		for (int32_t j = 0; j < numSamples; j++)
+		{
+			if (v->nextSampleStage)
+			{
+				v->nextSampleStage = false;
+				nextSample(v, b); // inlined
+			}
+
+			double dSample = v->dSample; // current Paula sample, pre-multiplied by volume, scaled to -1.0 .. 0.9921875
+			if (b->samplesLeft > 0)
+				dSample = blepRun(b, dSample);
+
+			dMixBuffer[j] += dSample;
+
+			v->dPhase += v->dDelta;
+			if (v->dPhase >= 1.0)
+			{
+				v->dPhase -= 1.0;
+				refetchPeriod(v); // inlined
+			}
+		}
+	}
+}
--- /dev/null
+++ b/src/pt2_paula.h
@@ -1,0 +1,53 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "pt2_header.h"
+
+typedef struct voice_t
+{
+	volatile bool DMA_active;
+
+	// internal values (don't modify directly!)
+	bool DMATriggerFlag, nextSampleStage;
+	int8_t AUD_DAT[2]; // DMA data buffer
+	const int8_t *location; // current location
+	uint16_t lengthCounter; // current length
+	int32_t sampleCounter; // how many bytes left in AUD_DAT
+	double dSample; // current sample point
+
+	// registers modified by Paula functions
+	const int8_t *AUD_LC; // location
+	uint16_t AUD_LEN; // length (in words)
+	double AUD_PER_delta, AUD_PER_deltamul; // delta
+	double AUD_VOL; // volume
+
+	double dDelta, dPhase;
+
+	// for BLEP synthesis
+	double dLastDelta, dLastPhase, dLastDeltaMul, dBlepOffset, dDeltaMul;
+
+	// used for pt2_sync.c (visualizers)
+	uint8_t syncFlags;
+	uint8_t syncVolume;
+	int32_t syncPeriod;
+	int32_t syncTriggerLength;
+	const int8_t *syncTriggerData;
+} paulaVoice_t;
+
+#define PAULA_VOICES 4
+#define PAULA_PAL_CLK AMIGA_PAL_CCK_HZ
+#define PAL_PAULA_MIN_PERIOD 113
+#define PAL_PAULA_MIN_SAFE_PERIOD 124
+#define PAL_PAULA_MAX_HZ (PAULA_PAL_CLK / (double)PAL_PAULA_MIN_PERIOD)
+#define PAL_PAULA_MAX_SAFE_HZ (PAULA_PAL_CLK / (double)PAL_PAULA_MIN_SAFE_PERIOD)
+
+void paulaSetOutputFrequency(double dAudioFreq, bool oversampling2x);
+void paulaSetDMACON(uint16_t bits); // $DFF096 register write (only controls paula DMA)
+void paulaSetPeriod(int32_t ch, uint16_t period);
+void paulaSetVolume(int32_t ch, uint16_t vol);
+void paulaSetLength(int32_t ch, uint16_t len);
+void paulaSetData(int32_t ch, const int8_t *src);
+void paulaGenerateSamples(double *dOutL, double *dOutR, int32_t numSamples);
+
+extern paulaVoice_t paula[PAULA_VOICES]; // pt2_paula.c
--- a/src/pt2_replayer.c
+++ b/src/pt2_replayer.c
@@ -5,22 +5,16 @@
 #include <crtdbg.h>
 #endif
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <stdint.h>
 #include <stdbool.h>
-#include <math.h>
-#include "pt2_header.h"
 #include "pt2_audio.h"
 #include "pt2_helpers.h"
 #include "pt2_tables.h"
-#include "pt2_module_loader.h"
 #include "pt2_config.h"
-#include "pt2_sampler.h"
 #include "pt2_visuals.h"
-#include "pt2_textout.h"
 #include "pt2_scopes.h"
 #include "pt2_sync.h"
+#include "pt2_amigafilters.h"
 
 static bool posJumpAssert, pBreakFlag, modRenderDone;
 static bool doStopSong; // from F00 (Set Speed)
@@ -27,6 +21,7 @@
 static int8_t pBreakPosition, oldRow, modPattern;
 static uint8_t pattDelTime, lowMask = 0xFF, pattDelTime2;
 static int16_t modOrder, oldPattern, oldOrder;
+static uint16_t DMACONtemp;
 static int32_t modBPM, oldBPM, oldSpeed, ciaSetBPM;
 
 static const uint8_t funkTable[16] = // EFx (FunkRepeat/InvertLoop)
@@ -35,6 +30,72 @@
 	0x10, 0x13, 0x16, 0x1A, 0x20, 0x2B, 0x40, 0x80
 };
 
+double ciaBpm2Hz(int32_t bpm)
+{
+	if (bpm == 0)
+		return 0.0;
+
+	const uint32_t ciaPeriod = 1773447 / bpm; // yes, PT truncates here
+	return (double)CIA_PAL_CLK / (ciaPeriod+1); // +1, CIA triggers on underflow
+}
+
+void updatePaulaLoops(void) // used after manipulating sample loop points while Paula is live
+{
+	const bool audioWasntLocked = !audio.locked;
+	if (audioWasntLocked)
+		lockAudio();
+
+	for (int32_t i = 0; i < PAULA_VOICES; i++)
+	{
+		const moduleChannel_t *ch = &song->channels[i];
+		if (ch->n_samplenum == editor.currSample) // selected sample matches channel's sample?
+		{
+			const moduleSample_t *s = &song->samples[editor.currSample];
+
+			paulaSetData(i, ch->n_start + s->loopStart);
+			paulaSetLength(i, (uint16_t)(s->loopLength >> 1));
+		}
+	}
+
+	if (audioWasntLocked)
+		unlockAudio();
+}
+
+void turnOffVoices(void)
+{
+	const bool audioWasntLocked = !audio.locked;
+	if (audioWasntLocked)
+		lockAudio();
+
+	paulaSetDMACON(0x000F); // turn off all voice DMAs
+
+	for (int32_t i = 0; i < PAULA_VOICES; i++)
+		paulaSetVolume(i, 0);
+
+	// reset dithering/filter states (so that every playback session is identical)
+	resetAmigaFilterStates();
+	resetAudioDithering();
+
+	if (audioWasntLocked)
+		unlockAudio();
+
+	editor.tuningToneFlag = false;
+}
+
+void initializeModuleChannels(module_t *s)
+{
+	assert(s != NULL);
+
+	memset(s->channels, 0, sizeof (s->channels));
+
+	moduleChannel_t *ch = s->channels;
+	for (uint8_t i = 0; i < PAULA_VOICES; i++, ch++)
+	{
+		ch->n_chanindex = i;
+		ch->n_dmabit = 1 << i;
+	}
+}
+
 void setReplayerPosToTrackerPos(void)
 {
 	if (song == NULL)
@@ -50,7 +111,6 @@
 {
 	// allocate memory for all sample data blocks (+ 2 extra, for quirk + safety)
 	const size_t allocLen = (MOD_SAMPLES + 2) * config.maxSampleLength;
-
 	return (int8_t *)calloc(allocLen, 1);
 }
 
@@ -64,12 +124,8 @@
 {
 	editor.songPlaying = false;
 
-	resetCachedMixerPeriod();
-	resetCachedScopePeriod();
+	pattDelTime = pattDelTime2 = 0;
 
-	pattDelTime = 0;
-	pattDelTime2 = 0;
-
 	if (resetPlayMode)
 	{
 		editor.playMode = PLAY_MODE_NORMAL;
@@ -80,13 +136,13 @@
 
 	if (song != NULL)
 	{
-		moduleChannel_t *c = song->channels;
-		for (int32_t i = 0; i < AMIGA_VOICES; i++, c++)
+		moduleChannel_t *ch = song->channels;
+		for (int32_t i = 0; i < PAULA_VOICES; i++, ch++)
 		{
-			c->n_wavecontrol = 0;
-			c->n_glissfunk = 0;
-			c->n_finetune = 0;
-			c->n_loopcount = 0;
+			ch->n_wavecontrol = 0;
+			ch->n_glissfunk = 0;
+			ch->n_finetune = 0;
+			ch->n_loopcount = 0;
 		}
 	}
 
@@ -112,12 +168,10 @@
 
 static void setVUMeterHeight(moduleChannel_t *ch)
 {
-	uint8_t vol;
-
 	if (editor.muted[ch->n_chanindex])
 		return;
 
-	vol = ch->n_volume;
+	uint8_t vol = ch->n_volume;
 	if ((ch->n_cmd & 0xF00) == 0xC00) // handle Cxx effect
 		vol = ch->n_cmd & 0xFF;
 
@@ -173,8 +227,6 @@
 
 static void jumpLoop(moduleChannel_t *ch)
 {
-	uint8_t tempParam;
-
 	if (song->tick != 0)
 		return;
 
@@ -193,9 +245,9 @@
 		pBreakFlag = true;
 
 		// stuff used for MOD2WAV to determine if the song has reached its end
-		if (editor.isWAVRendering)
+		if (editor.mod2WavOngoing)
 		{
-			for (tempParam = pBreakPosition; tempParam <= song->row; tempParam++)
+			for (int32_t tempParam = pBreakPosition; tempParam <= song->row; tempParam++)
 				editor.rowVisitTable[(modOrder * MOD_ROWS) + tempParam] = false;
 		}
 	}
@@ -238,15 +290,20 @@
 
 static void doRetrg(moduleChannel_t *ch)
 {
+	paulaSetDMACON(ch->n_dmabit); // voice DMA off
+
 	paulaSetData(ch->n_chanindex, ch->n_start); // n_start is increased on 9xx
 	paulaSetLength(ch->n_chanindex, ch->n_length);
 	paulaSetPeriod(ch->n_chanindex, ch->n_period);
-	paulaStartDMA(ch->n_chanindex);
 
+	paulaSetDMACON(0x8000 | ch->n_dmabit); // voice DMA on
+
 	// these take effect after the current DMA cycle is done
 	paulaSetData(ch->n_chanindex, ch->n_loopstart);
 	paulaSetLength(ch->n_chanindex, ch->n_replen);
 
+	// set visuals
+
 	ch->syncAnalyzerVolume = ch->n_volume;
 	ch->syncAnalyzerPeriod = ch->n_period;
 	ch->syncFlags |= UPDATE_ANALYZER;
@@ -376,13 +433,12 @@
 
 static void arpeggio(moduleChannel_t *ch)
 {
-	uint8_t arpTick, arpNote;
-	const int16_t *periods;
+	int32_t arpNote;
 
-	arpTick = song->tick % 3; // 0, 1, 2
+	int32_t arpTick = song->tick % 3; // 0, 1, 2
 	if (arpTick == 1)
 	{
-		arpNote = (uint8_t)(ch->n_cmd >> 4);
+		arpNote = ch->n_cmd >> 4;
 	}
 	else if (arpTick == 2)
 	{
@@ -399,7 +455,7 @@
 	** the correct overflow values to allow this to safely happen
 	** and sound correct at the same time.
 	*/
-	periods = &periodTable[ch->n_finetune * 37];
+	const int16_t *periods = &periodTable[ch->n_finetune * 37];
 	for (int32_t baseNote = 0; baseNote < 37; baseNote++)
 	{
 		if (ch->n_period >= periods[baseNote])
@@ -437,7 +493,16 @@
 	if (song->tick == 0) // added this (just pointless to call this during all ticks!)
 	{
 		const bool filterOn = (ch->n_cmd & 1) ^ 1;
-		setLEDFilter(filterOn, false);
+		if (filterOn)
+		{
+			editor.useLEDFilter = true;
+			setLEDFilter(true);
+		}
+		else
+		{
+			editor.useLEDFilter = false;
+			setLEDFilter(false);
+		}
 	}
 }
 
@@ -461,14 +526,10 @@
 
 static void setTonePorta(moduleChannel_t *ch)
 {
-	uint8_t i;
-	const int16_t *portaPointer;
-	uint16_t note;
+	uint16_t note = ch->n_note & 0xFFF;
+	const int16_t *portaPointer = &periodTable[ch->n_finetune * 37];
 
-	note = ch->n_note & 0xFFF;
-	portaPointer = &periodTable[ch->n_finetune * 37];
-
-	i = 0;
+	int32_t i = 0;
 	while (true)
 	{
 		// portaPointer[36] = 0, so i=36 is safe
@@ -494,9 +555,6 @@
 
 static void tonePortNoChange(moduleChannel_t *ch)
 {
-	uint8_t i;
-	const int16_t *portaPointer;
-
 	if (ch->n_wantedperiod <= 0)
 		return;
 
@@ -525,9 +583,9 @@
 	}
 	else
 	{
-		portaPointer = &periodTable[ch->n_finetune * 37];
+		const int16_t *portaPointer = &periodTable[ch->n_finetune * 37];
 
-		i = 0;
+		int32_t i = 0;
 		while (true)
 		{
 			// portaPointer[36] = 0, so i=36 is safe
@@ -805,6 +863,8 @@
 
 	if ((ch->n_cmd & 0xFF0) != 0xED0) // no note delay
 	{
+		paulaSetDMACON(ch->n_dmabit); // voice DMA off (turned on in setDMA() later)
+
 		if ((ch->n_wavecontrol & 0x04) == 0) ch->n_vibratopos = 0;
 		if ((ch->n_wavecontrol & 0x40) == 0) ch->n_tremolopos = 0;
 
@@ -820,20 +880,7 @@
 
 		paulaSetPeriod(ch->n_chanindex, ch->n_period);
 
-		if (!editor.muted[ch->n_chanindex])
-		{
-			paulaStartDMA(ch->n_chanindex);
-
-			ch->syncAnalyzerVolume = ch->n_volume;
-			ch->syncAnalyzerPeriod = ch->n_period;
-			ch->syncFlags |= UPDATE_ANALYZER;
-
-			setVUMeterHeight(ch);
-		}
-		else
-		{
-			paulaStopDMA(ch->n_chanindex);
-		}
+		DMACONtemp |= ch->n_dmabit;
 	}
 
 	checkMoreEffects(ch);
@@ -845,7 +892,7 @@
 	{
 		if (ch->n_chanindex == editor.metroChannel-1 && (song->row % editor.metroSpeed) == 0)
 		{
-			note->sample = 0x1F;
+			note->sample = 31;
 			note->period = (((song->row / editor.metroSpeed) % editor.metroSpeed) == 0) ? 160 : 214;
 		}
 	}
@@ -853,14 +900,11 @@
 
 static void playVoice(moduleChannel_t *ch)
 {
-	uint8_t cmd;
-	moduleSample_t *s;
-	note_t note;
-
-	if (ch->n_note == 0 && ch->n_cmd == 0)
+	if (ch->n_note == 0 && ch->n_cmd == 0) // test period, command and command parameter
 		paulaSetPeriod(ch->n_chanindex, ch->n_period);
 
-	note = song->patterns[modPattern][(song->row * AMIGA_VOICES) + ch->n_chanindex];
+	note_t note = song->patterns[modPattern][(song->row * PAULA_VOICES) + ch->n_chanindex];
+
 	checkMetronome(ch, &note);
 
 	ch->n_note = note.period;
@@ -869,7 +913,7 @@
 	if (note.sample >= 1 && note.sample <= 31) // SAFETY BUG FIX: don't handle sample-numbers >31
 	{
 		ch->n_samplenum = note.sample - 1;
-		s = &song->samples[ch->n_samplenum];
+		moduleSample_t *s = &song->samples[ch->n_samplenum];
 
 		ch->n_start = &song->sampleData[s->offset];
 		ch->n_finetune = s->fineTune & 0xF;
@@ -904,7 +948,7 @@
 		}
 		else
 		{
-			cmd = (ch->n_cmd & 0x0F00) >> 8;
+			uint8_t cmd = (ch->n_cmd & 0x0F00) >> 8;
 			if (cmd == 3 || cmd == 5)
 			{
 				setVUMeterHeight(ch);
@@ -930,9 +974,8 @@
 
 static void updateUIPositions(void)
 {
-	// don't update UI under MOD2WAV/PAT2SMP rendering
-	if (editor.isWAVRendering || editor.isSMPRendering)
-		return;
+	if (editor.mod2WavOngoing || editor.pat2SmpOngoing)
+		return; // don't update UI under MOD2WAV/PAT2SMP rendering
 
 	song->currRow = song->row;
 	song->currOrder = modOrder;
@@ -955,7 +998,7 @@
 
 static void nextPosition(void)
 {
-	if (editor.isSMPRendering)
+	if (editor.pat2SmpOngoing)
 		modRenderDone = true;
 
 	song->row = pBreakPosition;
@@ -985,13 +1028,13 @@
 
 			if (editor.stepPlayLastMode == MODE_EDIT || editor.stepPlayLastMode == MODE_IDLE)
 			{
-				song->row &= 0x3F;
+				song->row &= 63;
 				song->currRow = song->row;
 			}
 			else
 			{
 				// if we were playing, set replayer row to tracker row (stay in sync)
-				song->currRow &= 0x3F;
+				song->currRow &= 63;
 				song->row = song->currRow;
 			}
 
@@ -998,7 +1041,7 @@
 			return;
 		}
 
-		modOrder = (modOrder + 1) & 0x7F;
+		modOrder = (modOrder + 1) & 127;
 		if (modOrder >= song->header.numOrders)
 		{
 			modOrder = 0;
@@ -1015,7 +1058,7 @@
 				updateUIPositions();
 			}
 
-			if (editor.isWAVRendering)
+			if (editor.mod2WavOngoing)
 				modRenderDone = true;
 		}
 
@@ -1029,34 +1072,42 @@
 {
 	// the timer is not counting in "play pattern" mode
 	if (editor.playMode != PLAY_MODE_PATTERN && modBPM >= 32 && modBPM <= 255)
-		editor.musicTime64 += musicTimeTab64[modBPM-32];
+	{
+		if (editor.timingMode == TEMPO_MODE_CIA)
+			editor.musicTime64 += musicTimeTab64[modBPM-32];
+		else
+			editor.musicTime64 += musicTimeTab64[(255-32)+1]; // vblank tempo mode
+	}
 }
 
 static void setCurrRowToVisited(void) // for MOD2WAV
 {
-	if (editor.isWAVRendering)
+	if (editor.mod2WavOngoing)
 		editor.rowVisitTable[(modOrder * MOD_ROWS) + song->row] = true;
 }
 
 static bool renderEndCheck(void) // for MOD2WAV/PAT2SMP
 {
-	if (!editor.isWAVRendering && !editor.isSMPRendering)
+	if (!editor.mod2WavOngoing && !editor.pat2SmpOngoing)
 		return true; // we're not doing MOD2WAV/PAT2SMP
 
-	bool noPatternDelay = pattDelTime2 == 0;
-	if (noPatternDelay && song->tick == song->speed-1)
+	bool noPatternDelay = (pattDelTime2 == 0);
+	if (noPatternDelay)
 	{
-		if (editor.isSMPRendering)
+		if (editor.pat2SmpOngoing)
 		{
 			if (modRenderDone)
 				return false; // we're done rendering
 		}
-		
-		if (editor.isWAVRendering)
+
+		if (editor.mod2WavOngoing && song->tick == song->speed-1)
 		{
 			bool rowVisited = editor.rowVisitTable[(modOrder * MOD_ROWS) + song->row];
 			if (rowVisited || modRenderDone)
+			{
+				modRenderDone = false;
 				return false; // we're done rendering
+			}
 		}
 	}
 
@@ -1063,6 +1114,66 @@
 	return true;
 }
 
+static void setDMA(void)
+{
+	if (editor.muted[0]) DMACONtemp &= ~1;
+	if (editor.muted[1]) DMACONtemp &= ~2;
+	if (editor.muted[2]) DMACONtemp &= ~4;
+	if (editor.muted[3]) DMACONtemp &= ~8;
+
+	paulaSetDMACON(0x8000 | DMACONtemp);
+
+	moduleChannel_t *ch = song->channels;
+	for (int32_t i = 0; i < PAULA_VOICES; i++, ch++)
+	{
+		if (DMACONtemp & ch->n_dmabit) // sample trigger
+		{
+			ch->syncAnalyzerVolume = ch->n_volume;
+			ch->syncAnalyzerPeriod = ch->n_period;
+			ch->syncFlags |= UPDATE_ANALYZER;
+
+			setVUMeterHeight(ch);
+		}
+
+		// these take effect after the current DMA cycle is done
+		paulaSetData(i, ch->n_loopstart);
+		paulaSetLength(i, ch->n_replen);
+	}
+}
+
+void modSetTempo(int32_t bpm, bool doLockAudio)
+{
+	if (bpm < 32 || bpm > 255)
+		return;
+
+	const bool audioWasntLocked = !audio.locked;
+	if (doLockAudio && audioWasntLocked)
+		lockAudio();
+	
+	modBPM = bpm;
+	if (!editor.pat2SmpOngoing && !editor.mod2WavOngoing)
+	{
+		song->currBPM = bpm;
+		ui.updateSongBPM = true;
+	}
+
+	bpm -= 32; // 32..255 -> 0..223
+	audio.samplesPerTick64 = audio.samplesPerTickTable[bpm];
+
+	// calculate tick time length for audio/video sync timestamp (visualizers)
+	if (!editor.pat2SmpOngoing && !editor.mod2WavOngoing)
+	{
+		const uint64_t tickTimeLen64 = audio.tickLengthTable[bpm];
+		const uint32_t tickTimeLen = tickTimeLen64 >> 32;
+		const uint32_t tickTimeLenFrac = (uint32_t)tickTimeLen64;
+
+		setSyncTickTimeLen(tickTimeLen, tickTimeLenFrac);
+	}
+
+	if (doLockAudio && audioWasntLocked)
+		unlockAudio();
+}
+
 bool intMusic(void) // replayer ticker
 {
 	// quirk: CIA BPM changes are delayed by one tick in PT, so handle previous tick's BPM change now
@@ -1089,26 +1200,26 @@
 	{
 		if (pattDelTime2 == 0) // no pattern delay, time to read note data
 		{
-			setCurrRowToVisited(); // for MOD2WAV/PAT2SMP
+			DMACONtemp = 0; // reset Paula DMA trigger states
+
+			setCurrRowToVisited(); // for MOD2WAV
 			updateUIPositions(); // update current song positions in UI
 
 			// read note data and trigger voices
-			moduleChannel_t *c = song->channels;
-			for (int32_t i = 0; i < AMIGA_VOICES; i++, c++)
+			moduleChannel_t *ch = song->channels;
+			for (int32_t i = 0; i < PAULA_VOICES; i++, ch++)
 			{
-				playVoice(c);
-				paulaSetVolume(i, c->n_volume);
-
-				// these take effect after the current DMA cycle is done
-				paulaSetData(i, c->n_loopstart);
-				paulaSetLength(i, c->n_replen);
+				playVoice(ch);
+				paulaSetVolume(i, ch->n_volume);
 			}
+
+			setDMA();
 		}
 		else // pattern delay is on-going
 		{
-			moduleChannel_t *c = song->channels;
-			for (int32_t i = 0; i < AMIGA_VOICES; i++, c++)
-				checkEffects(c);
+			moduleChannel_t *ch = song->channels;
+			for (int32_t i = 0; i < PAULA_VOICES; i++, ch++)
+				checkEffects(ch);
 		}
 
 		// increase row
@@ -1186,9 +1297,9 @@
 	}
 	else // tick > 0 (handle effects)
 	{
-		moduleChannel_t *c = song->channels;
-		for (int32_t i = 0; i < AMIGA_VOICES; i++, c++)
-			checkEffects(c);
+		moduleChannel_t *ch = song->channels;
+		for (int32_t i = 0; i < PAULA_VOICES; i++, ch++)
+			checkEffects(ch);
 
 		if (posJumpAssert)
 			nextPosition();
@@ -1218,8 +1329,6 @@
 
 void modSetPos(int16_t order, int16_t row)
 {
-	int16_t posEdPos;
-
 	if (row != -1)
 	{
 		row = CLAMP(row, 0, 63);
@@ -1250,7 +1359,7 @@
 			ui.updateSongPattern = true;
 			editor.currPatternDisp = &song->header.order[modOrder];
 
-			posEdPos = song->currOrder;
+			int16_t posEdPos = song->currOrder;
 			if (posEdPos > song->header.numOrders-1)
 				posEdPos = song->header.numOrders-1;
 
@@ -1267,43 +1376,6 @@
 		ui.updateStatusText = true;
 }
 
-void modSetTempo(int32_t bpm, bool doLockAudio)
-{
-	if (bpm < 32 || bpm > 255)
-		return;
-
-	const bool audioWasntLocked = !audio.locked;
-	if (doLockAudio && audioWasntLocked)
-		lockAudio();
-	
-	modBPM = bpm;
-	if (!editor.isSMPRendering && !editor.isWAVRendering)
-	{
-		song->currBPM = bpm;
-		ui.updateSongBPM = true;
-	}
-
-	bpm -= 32; // 32..255 -> 0..223
-
-	int64_t samplesPerTick64;
-	if (editor.isSMPRendering)
-		samplesPerTick64 = editor.pat2SmpHQ ? audio.bpmTable28kHz[bpm] : audio.bpmTable20kHz[bpm];
-	else
-		samplesPerTick64 = audio.bpmTable[bpm];
-
-	audio.samplesPerTick64 = samplesPerTick64;
-
-	// calculate tick time length for audio/video sync timestamp
-	const uint64_t tickTimeLen64 = audio.tickLengthTable[bpm];
-	const uint32_t tickTimeLen = tickTimeLen64 >> 32;
-	const uint32_t tickTimeLenFrac = (uint32_t)tickTimeLen64;
-
-	setSyncTickTimeLen(tickTimeLen, tickTimeLenFrac);
-
-	if (doLockAudio && audioWasntLocked)
-		unlockAudio();
-}
-
 void modStop(void)
 {
 	editor.songPlaying = false;
@@ -1311,13 +1383,13 @@
 
 	if (song != NULL)
 	{
-		moduleChannel_t *c = song->channels;
-		for (int32_t i = 0; i < AMIGA_VOICES; i++, c++)
+		moduleChannel_t *ch = song->channels;
+		for (int32_t i = 0; i < PAULA_VOICES; i++, ch++)
 		{
-			c->n_wavecontrol = 0;
-			c->n_glissfunk = 0;
-			c->n_finetune = 0;
-			c->n_loopcount = 0;
+			ch->n_wavecontrol = 0;
+			ch->n_glissfunk = 0;
+			ch->n_finetune = 0;
+			ch->n_loopcount = 0;
 		}
 	}
 
@@ -1385,8 +1457,6 @@
 
 void modPlay(int16_t patt, int16_t order, int8_t row)
 {
-	uint8_t oldPlayMode, oldMode;
-
 	const bool audioWasntLocked = !audio.locked;
 	if (audioWasntLocked)
 		lockAudio();
@@ -1437,12 +1507,6 @@
 	editor.currPatternDisp = &song->header.order[modOrder];
 	editor.currPosEdPattDisp = &song->header.order[modOrder];
 
-	oldPlayMode = editor.playMode;
-	oldMode = editor.currMode;
-
-	editor.playMode = oldPlayMode;
-	editor.currMode = oldMode;
-
 	song->tick = song->speed-1;
 	ciaSetBPM = -1; // fix possibly stuck "set BPM" flag
 
@@ -1458,7 +1522,7 @@
 	if (audioWasntLocked)
 		unlockAudio();
 
-	if (!editor.isSMPRendering && !editor.isWAVRendering)
+	if (!editor.pat2SmpOngoing && !editor.mod2WavOngoing)
 	{
 		ui.updateSongPos = true;
 		ui.updatePatternData = true;
@@ -1469,9 +1533,6 @@
 
 void clearSong(void)
 {
-	uint8_t i;
-	moduleChannel_t *ch;
-
 	assert(song != NULL);
 	if (song == NULL)
 		return;
@@ -1500,13 +1561,12 @@
 
 	song->header.numOrders = 1;
 
-	for (i = 0; i < MAX_PATTERNS; i++)
-		memset(song->patterns[i], 0, (MOD_ROWS * AMIGA_VOICES) * sizeof (note_t));
+	for (int32_t i = 0; i < MAX_PATTERNS; i++)
+		memset(song->patterns[i], 0, (MOD_ROWS * PAULA_VOICES) * sizeof (note_t));
 
-	for (i = 0; i < AMIGA_VOICES; i++)
+	moduleChannel_t *ch = song->channels;
+	for (int32_t i = 0; i < PAULA_VOICES; i++, ch++)
 	{
-		ch = &song->channels[i];
-
 		ch->n_wavecontrol = 0;
 		ch->n_glissfunk = 0;
 		ch->n_finetune = 0;
@@ -1523,26 +1583,27 @@
 	modSetTempo(editor.initialTempo, true);
 	modSetSpeed(editor.initialSpeed);
 
-	setLEDFilter(false, true); // real PT doesn't do this there, but that's insane
+	// disable the LED filter after clearing the song (real PT2 doesn't do this)
+	editor.useLEDFilter = false;
+	setLEDFilter(false);
+
 	updateCurrSample();
 
 	ui.updateSongSize = true;
+	ui.updateSongLength = true;
+	ui.updateSongName = true;
 	renderMuteButtons();
-	updateWindowTitle(MOD_IS_MODIFIED);
 }
 
 void clearSamples(void)
 {
-	moduleSample_t *s;
-
 	assert(song != NULL);
 	if (song == NULL)
 		return;
 
-	for (uint8_t i = 0; i < MOD_SAMPLES; i++)
+	moduleSample_t *s = song->samples;
+	for (int32_t i = 0; i < MOD_SAMPLES; i++, s++)
 	{
-		s = &song->samples[i];
-
 		s->fineTune = 0;
 		s->length = 0;
 		s->loopLength = 2;
@@ -1563,22 +1624,10 @@
 
 	editor.samplePos = 0;
 	updateCurrSample();
-
-	updateWindowTitle(MOD_IS_MODIFIED);
 }
 
-void clearAll(void)
-{
-	clearSamples();
-	clearSong();
-
-	updateWindowTitle(MOD_NOT_MODIFIED);
-}
-
 void modFree(void)
 {
-	uint8_t i;
-
 	if (song == NULL)
 		return; // not allocated
 
@@ -1588,7 +1637,7 @@
 
 	turnOffVoices();
 
-	for (i = 0; i < MAX_PATTERNS; i++)
+	for (int32_t i = 0; i < MAX_PATTERNS; i++)
 	{
 		if (song->patterns[i] != NULL)
 			free(song->patterns[i]);
@@ -1611,7 +1660,6 @@
 
 	editor.playMode = PLAY_MODE_NORMAL;
 	editor.blockMarkFlag = false;
-	audio.forceSoundCardSilence = true;
 
 	song->row = 0;
 	song->currRow = 0;
@@ -1619,16 +1667,18 @@
 
 	memset(editor.rowVisitTable, 0, MOD_ORDERS * MOD_ROWS); // for MOD2WAV
 
-	if (editor.isSMPRendering)
+	if (editor.pat2SmpOngoing)
 	{
-		modPlay(DONT_SET_PATTERN, DONT_SET_ORDER, DONT_SET_ROW);
+		modSetSpeed(song->currSpeed);
+		modSetTempo(song->currBPM, true);
+		modPlay(DONT_SET_PATTERN, DONT_SET_ORDER, 0);
 	}
 	else
 	{
 		song->currSpeed = 6;
 		song->currBPM = 125;
-		modSetSpeed(6);
-		modSetTempo(125, true);
+		modSetSpeed(song->currSpeed);
+		modSetTempo(song->currBPM, true);
 
 		modPlay(DONT_SET_PATTERN, 0, 0);
 	}
@@ -1649,9 +1699,7 @@
 	memset((int8_t *)editor.realVuMeterVolumes, 0, sizeof (editor.realVuMeterVolumes));
 	memset((int8_t *)editor.spectrumVolumes,    0, sizeof (editor.spectrumVolumes));
 
-	memset(song->channels, 0, sizeof (song->channels));
-	for (uint8_t i = 0; i < AMIGA_VOICES; i++)
-		song->channels[i].n_chanindex = i;
+	initializeModuleChannels(song);
 
 	modOrder = oldOrder;
 	modPattern = (int8_t)oldPattern;
@@ -1674,5 +1722,4 @@
 
 	song->tick = 0;
 	modRenderDone = false;
-	audio.forceSoundCardSilence = false;
 }
--- /dev/null
+++ b/src/pt2_replayer.h
@@ -1,0 +1,32 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "pt2_structs.h"
+
+#define REPLAYER_MIN_BPM 32
+
+double ciaBpm2Hz(int32_t bpm);
+void updatePaulaLoops(void); // used after manipulating sample loop points while Paula is live
+void turnOffVoices(void);
+void initializeModuleChannels(module_t *s);
+int8_t *allocMemForAllSamples(void);
+void setReplayerPosToTrackerPos(void);
+void setPattern(int16_t pattern);
+bool intMusic(void);
+void storeTempVariables(void);
+void restartSong(void);
+void resetSong(void);
+void incPatt(void);
+void decPatt(void);
+void modSetPos(int16_t order, int16_t row);
+void modStop(void);
+void doStopIt(bool resetPlayMode);
+void playPattern(int8_t startRow);
+void modPlay(int16_t patt, int16_t order, int8_t row);
+void modSetSpeed(int32_t speed);
+void modSetTempo(int32_t bpm, bool doLockAudio);
+void modFree(void);
+void clearSong(void);
+void clearSamples(void);
+void modSetPattern(uint8_t pattern);
--- a/src/pt2_sample_loader.c
+++ b/src/pt2_sample_loader.c
@@ -7,18 +7,16 @@
 #include <string.h>
 #include <stdint.h>
 #include <stdbool.h>
-#include "pt2_header.h"
 #include "pt2_textout.h"
-#include "pt2_mouse.h"
-#include "pt2_structs.h"
 #include "pt2_sampler.h" // fixSampleBeep()
 #include "pt2_audio.h"
 #include "pt2_visuals.h"
 #include "pt2_helpers.h"
-#include "pt2_unicode.h"
 #include "pt2_config.h"
 #include "pt2_sampling.h"
 #include "pt2_downsample2x.h"
+#include "pt2_askbox.h"
+#include "pt2_replayer.h"
 
 enum
 {
@@ -33,64 +31,23 @@
 	SAMPLE_WAV = 2
 };
 
-
-static int8_t loadedSampleType;
-
-static bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling);
-static bool loadIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling);
-static bool loadRAWSample(UNICHAR *fileName, char *entryName);
-static bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling);
-
-void extLoadWAVOrAIFFSampleCallback(bool downsample)
+static bool loadWAVSample(UNICHAR *fileName, char *entryName)
 {
-	switch (loadedSampleType)
-	{
-		case SAMPLE_IFF:   loadIFFSample(editor.fileNameTmpU, editor.entryNameTmp, downsample); break;
-		case SAMPLE_AIFF: loadAIFFSample(editor.fileNameTmpU, editor.entryNameTmp, downsample); break;
-		case SAMPLE_WAV:   loadWAVSample(editor.fileNameTmpU, editor.entryNameTmp, downsample); break;
-		default: break;
-	}
-}
-
-bool loadWAVSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling)
-{
-	bool wavSampleNameFound;
-	uint8_t *audioDataU8;
-	int16_t *audioDataS16, tempVol;
 	uint16_t audioFormat, numChannels, bitsPerSample;
-	int32_t *audioDataS32, smp32, sampleLength, loopStart, loopEnd, inamLen, nameLen, i;
-	uint32_t *audioDataU32, chunkID, chunkSize;
-	uint32_t sampleRate, filesize, loopFlags;
-	uint32_t dataPtr, dataLen, fmtPtr, endOfChunk, bytesRead;
-	uint32_t fmtLen, inamPtr, smplPtr, smplLen, xtraPtr, xtraLen;
-	float *fAudioDataFloat;
-	double *dAudioDataDouble;
-	FILE *f;
-	moduleSample_t *s;
+	uint32_t sampleRate;
 
-	loadedSampleType = SAMPLE_WAV;
-
 	// zero out chunk pointers and lengths
-	fmtPtr  = 0; fmtLen = 0;
-	dataPtr = 0; dataLen = 0;
-	inamPtr = 0; inamLen = 0;
-	xtraPtr = 0; xtraLen = 0;
-	smplPtr = 0; smplLen = 0;
+	uint32_t fmtPtr  = 0; uint32_t fmtLen = 0;
+	uint32_t dataPtr = 0; uint32_t dataLen = 0;
+	uint32_t inamPtr = 0;  int32_t inamLen = 0;
+	uint32_t xtraPtr = 0; uint32_t xtraLen = 0;
+	uint32_t smplPtr = 0; uint32_t smplLen = 0;
 
-	wavSampleNameFound = false;
+	bool wavSampleNameFound = false;
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 
-	if (forceDownSampling == -1)
-	{
-		// these two *must* be fully wiped, for outputting reasons
-		memset(editor.fileNameTmpU, 0, PATH_MAX);
-		memset(editor.entryNameTmp, 0, PATH_MAX);
-		UNICHAR_STRCPY(editor.fileNameTmpU, fileName);
-		strcpy(editor.entryNameTmp, entryName);
-	}
-
-	f = UNICHAR_FOPEN(fileName, "rb");
+	FILE *f = UNICHAR_FOPEN(fileName, "rb");
 	if (f == NULL)
 	{
 		displayErrorMsg("FILE I/O ERROR !");
@@ -98,8 +55,8 @@
 	}
 
 	fseek(f, 0, SEEK_END);
-	filesize = ftell(f);
-	if (filesize == 0)
+	uint32_t fileSize = ftell(f);
+	if (fileSize == 0)
 	{
 		fclose(f);
 
@@ -110,13 +67,15 @@
 	// look for wanted chunks and set up pointers + lengths
 	fseek(f, 12, SEEK_SET);
 
-	bytesRead = 0;
-	while (!feof(f) && bytesRead < filesize-12)
+	uint32_t bytesRead = 0;
+	while (!feof(f) && bytesRead < fileSize-12)
 	{
+		uint32_t chunkID, chunkSize;
+
 		fread(&chunkID, 4, 1, f); if (feof(f)) break;
 		fread(&chunkSize, 4, 1, f); if (feof(f)) break;
 
-		endOfChunk = (ftell(f) + chunkSize) + (chunkSize & 1);
+		uint32_t endOfChunk = (ftell(f) + chunkSize) + (chunkSize & 1);
 		switch (chunkID)
 		{
 			case 0x20746D66: // "fmt "
@@ -201,10 +160,10 @@
 	fread(&sampleRate,  4, 1, f);
 	fseek(f, 6, SEEK_CUR);
 	fread(&bitsPerSample, 2, 1, f);
-	sampleLength = dataLen;
+	int32_t sampleLength = dataLen;
 	// ---------------------------
 
-	if (sampleRate == 0 || sampleLength == 0 || sampleLength >= (int32_t)filesize*(bitsPerSample/8))
+	if (sampleRate == 0 || sampleLength == 0 || sampleLength >= (int32_t)fileSize*(bitsPerSample/8))
 	{
 		fclose(f);
 		displayErrorMsg("WAV CORRUPT !");
@@ -239,19 +198,12 @@
 		return false;
 	}
 
+	bool forceDownSampling = false;
 	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
 	{
-		if (forceDownSampling == -1)
-		{
-			showDownsampleAskDialog();
-			fclose(f);
-			return true;
-		}
+		if (askBox(ASKBOX_DOWNSAMPLE, "DOWNSAMPLE ?"))
+			forceDownSampling = true;
 	}
-	else
-	{
-		forceDownSampling = false;
-	}
 
 	// ---- READ SAMPLE DATA ----
 	fseek(f, dataPtr, SEEK_SET);
@@ -263,7 +215,7 @@
 		if (sampleLength > config.maxSampleLength*4)
 			sampleLength = config.maxSampleLength*4;
 
-		audioDataU8 = (uint8_t *)malloc(sampleLength * sizeof (uint8_t));
+		uint8_t *audioDataU8 = (uint8_t *)malloc(sampleLength * sizeof (uint8_t));
 		if (audioDataU8 == NULL)
 		{
 			fclose(f);
@@ -284,9 +236,9 @@
 		if (numChannels == 2)
 		{
 			sampleLength >>= 1;
-			for (i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
 			{
-				smp32 = (audioDataU8[(i << 1) + 0] - 128) + (audioDataU8[(i << 1) + 1] - 128);
+				int32_t smp32 = (audioDataU8[(i << 1) + 0] - 128) + (audioDataU8[(i << 1) + 1] - 128);
 				smp32 = 128 + (smp32 >> 1);
 				audioDataU8[i] = (uint8_t)smp32;
 			}
@@ -303,7 +255,7 @@
 			sampleLength = config.maxSampleLength;
 
 		turnOffVoices();
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 			smpPtr[i] = audioDataU8[i] - 128;
 
 		free(audioDataU8);
@@ -314,7 +266,7 @@
 		if (sampleLength > config.maxSampleLength*4)
 			sampleLength = config.maxSampleLength*4;
 
-		audioDataS16 = (int16_t *)malloc(sampleLength * sizeof (int16_t));
+		int16_t *audioDataS16 = (int16_t *)malloc(sampleLength * sizeof (int16_t));
 		if (audioDataS16 == NULL)
 		{
 			fclose(f);
@@ -335,7 +287,7 @@
 		if (numChannels == 2)
 		{
 			sampleLength >>= 1;
-			for (i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
 				audioDataS16[i] = (audioDataS16[(i << 1) + 0] + audioDataS16[(i << 1) + 1]) >> 1;;
 		}
 
@@ -362,9 +314,9 @@
 		}
 
 		turnOffVoices();
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 		{
-			smp32 = (int32_t)round(audioDataS16[i] * dAmp);
+			int32_t smp32 = (int32_t)round(audioDataS16[i] * dAmp);
 			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
 			smpPtr[i] = (int8_t)smp32;
 		}
@@ -377,7 +329,7 @@
 		if (sampleLength > config.maxSampleLength*4)
 			sampleLength = config.maxSampleLength*4;
 
-		audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
+		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
 		if (audioDataS32 == NULL)
 		{
 			fclose(f);
@@ -386,8 +338,8 @@
 		}
 
 		// read sample data
-		audioDataU8 = (uint8_t *)audioDataS32;
-		for (i = 0; i < sampleLength; i++)
+		uint8_t *audioDataU8 = (uint8_t *)audioDataS32;
+		for (int32_t i = 0; i < sampleLength; i++)
 		{
 			audioDataU8[0] = 0;
 			fread(&audioDataU8[1], 3, 1, f);
@@ -398,7 +350,7 @@
 		if (numChannels == 2)
 		{
 			sampleLength >>= 1;
-			for (i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
 			{
 				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
 				audioDataS32[i] = (int32_t)smp;
@@ -428,9 +380,9 @@
 		}
 
 		turnOffVoices();
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 		{
-			smp32 = (int32_t)round(audioDataS32[i] * dAmp);
+			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
 			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
 			smpPtr[i] = (int8_t)smp32;
 		}
@@ -443,7 +395,7 @@
 		if (sampleLength > config.maxSampleLength*4)
 			sampleLength = config.maxSampleLength*4;
 
-		audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
+		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
 		if (audioDataS32 == NULL)
 		{
 			fclose(f);
@@ -464,7 +416,7 @@
 		if (numChannels == 2)
 		{
 			sampleLength >>= 1;
-			for (i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
 			{
 				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
 				audioDataS32[i] = (int32_t)smp;
@@ -494,9 +446,9 @@
 		}
 
 		turnOffVoices();
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 		{
-			smp32 = (int32_t)round(audioDataS32[i] * dAmp);
+			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
 			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
 			smpPtr[i] = (int8_t)smp32;
 		}
@@ -509,7 +461,7 @@
 		if (sampleLength > config.maxSampleLength*4)
 			sampleLength = config.maxSampleLength*4;
 
-		audioDataU32 = (uint32_t *)malloc(sampleLength * sizeof (uint32_t));
+		uint32_t *audioDataU32 = (uint32_t *)malloc(sampleLength * sizeof (uint32_t));
 		if (audioDataU32 == NULL)
 		{
 			fclose(f);
@@ -526,13 +478,13 @@
 			return false;
 		}
 
-		fAudioDataFloat = (float *)audioDataU32;
+		float *fAudioDataFloat = (float *)audioDataU32;
 
 		// convert from stereo to mono (if needed)
 		if (numChannels == 2)
 		{
 			sampleLength >>= 1;
-			for (i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
 				fAudioDataFloat[i] = (fAudioDataFloat[(i * 2) + 0] + fAudioDataFloat[(i * 2) + 1]) * 0.5f;
 		}
 
@@ -552,9 +504,9 @@
 			fAmp = INT8_MAX / fPeak;
 
 		turnOffVoices();
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 		{
-			smp32 = (int32_t)roundf(fAudioDataFloat[i] * fAmp);
+			int32_t smp32 = (int32_t)roundf(fAudioDataFloat[i] * fAmp);
 			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
 			smpPtr[i] = (int8_t)smp32;
 		}
@@ -567,7 +519,7 @@
 		if (sampleLength > config.maxSampleLength*4)
 			sampleLength = config.maxSampleLength*4;
 
-		audioDataU32 = (uint32_t *)malloc(sampleLength * (sizeof (uint32_t) * 2));
+		uint32_t *audioDataU32 = (uint32_t *)malloc(sampleLength * (sizeof (uint32_t) * 2));
 		if (audioDataU32 == NULL)
 		{
 			fclose(f);
@@ -584,13 +536,13 @@
 			return false;
 		}
 
-		dAudioDataDouble = (double *)audioDataU32;
+		double *dAudioDataDouble = (double *)audioDataU32;
 
 		// convert from stereo to mono (if needed)
 		if (numChannels == 2)
 		{
 			sampleLength >>= 1;
-			for (i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
 				dAudioDataDouble[i] = (dAudioDataDouble[(i * 2) + 0] + dAudioDataDouble[(i * 2) + 1]) * 0.5;
 		}
 
@@ -610,9 +562,9 @@
 			dAmp = INT8_MAX / dPeak;
 
 		turnOffVoices();
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 		{
-			smp32 = (int32_t)round(dAudioDataDouble[i] * dAmp);
+			int32_t smp32 = (int32_t)round(dAudioDataDouble[i] * dAmp);
 			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
 			smpPtr[i] = (int8_t)smp32;
 		}
@@ -639,6 +591,9 @@
 	// ---- READ "smpl" chunk ----
 	if (smplPtr != 0 && smplLen > 52)
 	{
+		int32_t loopStart, loopEnd;
+		uint32_t loopFlags;
+
 		fseek(f, smplPtr + 28, SEEK_SET); // seek to first wanted byte
 
 		fread(&loopFlags, 4, 1, f);
@@ -677,6 +632,8 @@
 	// ---- READ "xtra" chunk ----
 	if (xtraPtr != 0 && xtraLen >= 8)
 	{
+		int16_t tempVol;
+
 		fseek(f, xtraPtr + 4, SEEK_SET); // seek to first wanted byte
 
 		// volume (0..256)
@@ -696,7 +653,7 @@
 	{
 		fseek(f, inamPtr, SEEK_SET); // seek to first wanted byte
 
-		for (i = 0; i < 21; i++)
+		for (int32_t i = 0; i < 21; i++)
 		{
 			if (i < inamLen)
 				s->text[i] = (char)fgetc(f);
@@ -716,8 +673,8 @@
 	// copy over sample name
 	if (!wavSampleNameFound)
 	{
-		nameLen = (int32_t)strlen(entryName);
-		for (i = 0; i < 21; i++)
+		int32_t nameLen = (int32_t)strlen(entryName);
+		for (int32_t i = 0; i < 21; i++)
 			s->text[i] = (i < nameLen) ? (char)entryName[i] : '\0';
 
 		s->text[21] = '\0';
@@ -725,7 +682,7 @@
 	}
 
 	// remove .wav from end of sample name (if present)
-	nameLen = (uint32_t)strlen(s->text);
+	int32_t nameLen = (uint32_t)strlen(s->text);
 	if (nameLen >= 4 && !_strnicmp(&s->text[nameLen-4], ".WAV", 4))
 		 memset(&s->text[nameLen-4], '\0', 4);
 
@@ -747,38 +704,20 @@
 	return true;
 }
 
-bool loadIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling)
+static bool loadIFFSample(UNICHAR *fileName, char *entryName)
 {
-	bool nameFound, is16Bit;
 	char tmpCharBuf[23];
-	int8_t *sampleData;
-	int16_t *ptr16;
-	int32_t filesize, smp32;
 	uint16_t sampleRate;
-	int32_t i, sampleLength, sampleLoopStart, sampleLoopLength, nameLen;
-	uint32_t sampleVolume, blockName, blockSize;
-	uint32_t vhdrPtr, vhdrLen, bodyPtr, bodyLen, namePtr;
-	FILE *f;
-	moduleSample_t *s;
+	int32_t sampleLoopStart, sampleLoopLength;
 
-	loadedSampleType = SAMPLE_IFF;
+	// zero out chunk pointers and lengths
+	uint32_t vhdrPtr = 0; uint32_t vhdrLen = 0;
+	uint32_t bodyPtr = 0; uint32_t bodyLen = 0;
+	uint32_t namePtr = 0;  int32_t nameLen = 0;
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 
-	vhdrPtr = 0; vhdrLen = 0;
-	bodyPtr = 0; bodyLen = 0;
-	namePtr = 0; nameLen = 0;
-
-	if (forceDownSampling == -1)
-	{
-		// these two *must* be fully wiped, for outputting reasons
-		memset(editor.fileNameTmpU, 0, PATH_MAX);
-		memset(editor.entryNameTmp, 0, PATH_MAX);
-		UNICHAR_STRCPY(editor.fileNameTmpU, fileName);
-		strcpy(editor.entryNameTmp, entryName);
-	}
-
-	f = UNICHAR_FOPEN(fileName, "rb");
+	FILE *f = UNICHAR_FOPEN(fileName, "rb");
 	if (f == NULL)
 	{
 		displayErrorMsg("FILE I/O ERROR !");
@@ -786,8 +725,8 @@
 	}
 
 	fseek(f, 0, SEEK_END);
-	filesize = ftell(f);
-	if (filesize == 0)
+	int32_t fileSize = ftell(f);
+	if (fileSize == 0)
 	{
 		displayErrorMsg("IFF IS CORRUPT !");
 		return false;
@@ -795,15 +734,17 @@
 
 	fseek(f, 8, SEEK_SET);
 	fread(tmpCharBuf, 1, 4, f);
-	is16Bit = !strncmp(tmpCharBuf, "16SV", 4);
+	bool is16Bit = !strncmp(tmpCharBuf, "16SV", 4);
 
-	sampleLength = 0;
-	nameFound = false;
-	sampleVolume = 65536; // max volume
+	int32_t sampleLength = 0;
+	bool nameFound = false;
+	uint32_t sampleVolume = 65536; // max volume
 
 	fseek(f, 12, SEEK_SET);
-	while (!feof(f) && ftell(f) < filesize-12)
+	while (!feof(f) && ftell(f) < fileSize-12)
 	{
+		uint32_t blockName, blockSize;
+
 		fread(&blockName, 4, 1, f); if (feof(f)) break;
 		fread(&blockSize, 4, 1, f); if (feof(f)) break;
 
@@ -848,10 +789,10 @@
 
 	// kludge for some really strange IFFs
 	if (bodyLen == 0)
-		bodyLen = filesize - bodyPtr;
+		bodyLen = fileSize - bodyPtr;
 
-	if (bodyPtr+bodyLen > (uint32_t)filesize)
-		bodyLen = filesize - bodyPtr;
+	if (bodyPtr+bodyLen > (uint32_t)fileSize)
+		bodyLen = fileSize - bodyPtr;
 
 	fseek(f, vhdrPtr, SEEK_SET);
 	fread(&sampleLoopStart,  4, 1, f); sampleLoopStart  = SWAP32(sampleLoopStart);
@@ -884,19 +825,12 @@
 		return false;
 	}
 
+	bool forceDownSampling = false;
 	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
 	{
-		if (forceDownSampling == -1)
-		{
-			showDownsampleAskDialog();
-			fclose(f);
-			return true;
-		}
+		if (askBox(ASKBOX_DOWNSAMPLE, "DOWNSAMPLE ?"))
+			forceDownSampling = true;
 	}
-	else
-	{
-		forceDownSampling = false;
-	}
 
 	int32_t maxSampleLength = config.maxSampleLength;
 	if (is16Bit)
@@ -908,7 +842,7 @@
 	if (sampleLength > maxSampleLength)
 		sampleLength = maxSampleLength;
 
-	sampleData = (int8_t *)malloc(sampleLength);
+	int8_t *sampleData = (int8_t *)malloc(sampleLength);
 	if (sampleData == NULL)
 	{
 		fclose(f);
@@ -935,7 +869,7 @@
 	if (is16Bit) // FT2-specific 16SV format (little-endian samples)
 	{
 		fread(sampleData, 1, sampleLength << 1, f);
-		ptr16 = (int16_t *)sampleData;
+		int16_t *ptr16 = (int16_t *)sampleData;
 
 		// 2x downsampling
 		if (forceDownSampling)
@@ -960,9 +894,9 @@
 		}
 
 		int8_t *smpPtr = &song->sampleData[s->offset];
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 		{
-			smp32 = (int32_t)round(ptr16[i] * dAmp);
+			int32_t smp32 = (int32_t)round(ptr16[i] * dAmp);
 			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
 			smpPtr[i] = (int8_t)smp32;
 		}
@@ -1087,16 +1021,11 @@
 	return false;
 }
 
-bool loadRAWSample(UNICHAR *fileName, char *entryName)
+static bool loadRAWSample(UNICHAR *fileName, char *entryName)
 {
-	uint8_t i;
-	int32_t nameLen, fileSize;
-	FILE *f;
-	moduleSample_t *s;
+	moduleSample_t *s = &song->samples[editor.currSample];
 
-	s = &song->samples[editor.currSample];
-
-	f = UNICHAR_FOPEN(fileName, "rb");
+	FILE *f = UNICHAR_FOPEN(fileName, "rb");
 	if (f == NULL)
 	{
 		displayErrorMsg("FILE I/O ERROR !");
@@ -1104,7 +1033,7 @@
 	}
 
 	fseek(f, 0, SEEK_END);
-	fileSize = ftell(f);
+	int32_t fileSize = ftell(f);
 	fseek(f, 0, SEEK_SET);
 
 	fileSize &= ~1;
@@ -1127,8 +1056,8 @@
 	s->loopLength = 2;
 
 	// copy over sample name
-	nameLen = (uint32_t)strlen(entryName);
-	for (i = 0; i < 21; i++)
+	int32_t nameLen = (uint32_t)strlen(entryName);
+	for (int32_t i = 0; i < 21; i++)
 		s->text[i] = (i < nameLen) ? (char)entryName[i] : '\0';
 
 	s->text[21] = '\0';
@@ -1154,55 +1083,34 @@
 
 static int32_t getAIFFRate(uint8_t *in)
 {
-	int32_t exp;
-	uint32_t lo, hi;
-	double dOut;
+	int32_t exp = (int32_t)(((in[0] & 0x7F) << 8) | in[1]);
+	uint32_t lo = (in[2] << 24) | (in[3] << 16) | (in[4] << 8) | in[5];
+	uint32_t hi = (in[6] << 24) | (in[7] << 16) | (in[8] << 8) | in[9];
 
-	exp = (int32_t)(((in[0] & 0x7F) << 8) | in[1]);
-	lo  = (in[2] << 24) | (in[3] << 16) | (in[4] << 8) | in[5];
-	hi  = (in[6] << 24) | (in[7] << 16) | (in[8] << 8) | in[9];
-
 	if (exp == 0 && lo == 0 && hi == 0)
 		return 0;
 
 	exp -= 16383;
 
-	dOut = ldexp(lo, -31 + exp) + ldexp(hi, -63 + exp);
+	double dOut = ldexp(lo, -31 + exp) + ldexp(hi, -63 + exp);
 	return (int32_t)(dOut + 0.5);
 }
 
-bool loadAIFFSample(UNICHAR *fileName, char *entryName, int8_t forceDownSampling)
+static bool loadAIFFSample(UNICHAR *fileName, char *entryName)
 {
-	bool unsigned8bit;
-	char compType[4];
-	int8_t *audioDataS8;
-	uint8_t *audioDataU8, sampleRateBytes[10];
-	int16_t *audioDataS16;
+	uint8_t sampleRateBytes[10];
 	uint16_t bitDepth, numChannels;
-	int32_t i, filesize, *audioDataS32, smp32, sampleLength, nameLen;
-	uint32_t offset, sampleRate, blockName, blockSize;
-	uint32_t commPtr, commLen, ssndPtr, ssndLen;
-	FILE *f;
-	moduleSample_t *s;
+	uint32_t offset, sampleRate;
 
-	unsigned8bit = false;
-	loadedSampleType = SAMPLE_AIFF;
+	// zero out chunk pointers and lengths
+	uint32_t commPtr = 0; uint32_t commLen = 0;
+	uint32_t ssndPtr = 0; uint32_t ssndLen = 0;
 
-	if (forceDownSampling == -1)
-	{
-		// these two *must* be fully wiped, for outputting reasons
-		memset(editor.fileNameTmpU, 0, PATH_MAX);
-		memset(editor.entryNameTmp, 0, PATH_MAX);
-		UNICHAR_STRCPY(editor.fileNameTmpU, fileName);
-		strcpy(editor.entryNameTmp, entryName);
-	}
+	bool unsigned8bit = false;
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 
-	commPtr = 0; commLen = 0;
-	ssndPtr = 0; ssndLen = 0;
-
-	f = UNICHAR_FOPEN(fileName, "rb");
+	FILE *f = UNICHAR_FOPEN(fileName, "rb");
 	if (f == NULL)
 	{
 		displayErrorMsg("FILE I/O ERROR !");
@@ -1210,8 +1118,8 @@
 	}
 
 	fseek(f, 0, SEEK_END);
-	filesize = ftell(f);
-	if (filesize == 0)
+	int32_t fileSize = ftell(f);
+	if (fileSize == 0)
 	{
 		displayErrorMsg("AIFF IS CORRUPT !");
 		return false;
@@ -1218,8 +1126,10 @@
 	}
 
 	fseek(f, 12, SEEK_SET);
-	while (!feof(f) && ftell(f) < filesize-12)
+	while (!feof(f) && ftell(f) < fileSize-12)
 	{
+		uint32_t blockName, blockSize;
+
 		fread(&blockName, 4, 1, f); if (feof(f)) break;
 		fread(&blockSize, 4, 1, f); if (feof(f)) break;
 
@@ -1257,10 +1167,10 @@
 
 	// kludge for some really strange AIFFs
 	if (ssndLen == 0)
-		ssndLen = filesize - ssndPtr;
+		ssndLen = fileSize - ssndPtr;
 
-	if (ssndPtr+ssndLen > (uint32_t)filesize)
-		ssndLen = filesize - ssndPtr;
+	if (ssndPtr+ssndLen > (uint32_t)fileSize)
+		ssndLen = fileSize - ssndPtr;
 
 	fseek(f, commPtr, SEEK_SET);
 	fread(&numChannels, 2, 1, f); numChannels = SWAP16(numChannels);
@@ -1287,6 +1197,7 @@
 	// read compression type (if present)
 	if (commLen > 18)
 	{
+		char compType[4];
 		fread(&compType, 1, 4, f);
 		if (memcmp(compType, "NONE", 4))
 		{
@@ -1314,7 +1225,7 @@
 
 	ssndLen -= 8; // don't include offset and blockSize datas
 
-	sampleLength = ssndLen;
+	int32_t sampleLength = ssndLen;
 	if (sampleLength == 0)
 	{
 		fclose(f);
@@ -1322,19 +1233,12 @@
 		return false;
 	}
 
+	bool forceDownSampling = false;
 	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
 	{
-		if (forceDownSampling == -1)
-		{
-			showDownsampleAskDialog();
-			fclose(f);
-			return true;
-		}
+		if (askBox(ASKBOX_DOWNSAMPLE, "DOWNSAMPLE ?"))
+			forceDownSampling = true;
 	}
-	else
-	{
-		forceDownSampling = false;
-	}
 
 	int8_t *smpPtr = &song->sampleData[editor.currSample * config.maxSampleLength];
 
@@ -1343,7 +1247,7 @@
 		if (sampleLength > config.maxSampleLength*4)
 			sampleLength = config.maxSampleLength*4;
 
-		audioDataS8 = (int8_t *)malloc(sampleLength * sizeof (int8_t));
+		int8_t *audioDataS8 = (int8_t *)malloc(sampleLength * sizeof (int8_t));
 		if (audioDataS8 == NULL)
 		{
 			fclose(f);
@@ -1362,7 +1266,7 @@
 
 		if (unsigned8bit)
 		{
-			for (i = 0; i < sampleLength; i++)
+			for (int32_t i = 0; i < sampleLength; i++)
 				audioDataS8[i] ^= 0x80;
 		}
 
@@ -1370,7 +1274,7 @@
 		if (numChannels == 2)
 		{
 			sampleLength >>= 1;
-			for (i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
 				audioDataS8[i] = (audioDataS8[(i * 2) + 0] + audioDataS8[(i * 2) + 1]) >> 1;;
 		}
 
@@ -1385,7 +1289,7 @@
 			sampleLength = config.maxSampleLength;
 
 		turnOffVoices();
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 			smpPtr[i] = audioDataS8[i];
 
 		free(audioDataS8);
@@ -1396,7 +1300,7 @@
 		if (sampleLength > config.maxSampleLength*4)
 			sampleLength = config.maxSampleLength*4;
 
-		audioDataS16 = (int16_t *)malloc(sampleLength * sizeof (int16_t));
+		int16_t *audioDataS16 = (int16_t *)malloc(sampleLength * sizeof (int16_t));
 		if (audioDataS16 == NULL)
 		{
 			fclose(f);
@@ -1414,7 +1318,7 @@
 		}
 
 		// fix endianness
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 			audioDataS16[i] = SWAP16(audioDataS16[i]);
 
 		// convert from stereo to mono (if needed)
@@ -1421,7 +1325,7 @@
 		if (numChannels == 2)
 		{
 			sampleLength >>= 1;
-			for (i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
 				audioDataS16[i] = (audioDataS16[(i << 1) + 0] + audioDataS16[(i << 1) + 1]) >> 1;
 		}
 
@@ -1448,9 +1352,9 @@
 		}
 
 		turnOffVoices();
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 		{
-			smp32 = (int32_t)round(audioDataS16[i] * dAmp);
+			int32_t smp32 = (int32_t)round(audioDataS16[i] * dAmp);
 			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
 			smpPtr[i] = (int8_t)smp32;
 		}
@@ -1463,7 +1367,7 @@
 		if (sampleLength > config.maxSampleLength*4)
 			sampleLength = config.maxSampleLength*4;
 
-		audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
+		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
 		if (audioDataS32 == NULL)
 		{
 			fclose(f);
@@ -1481,8 +1385,8 @@
 		}
 
 		// convert to 32-bit
-		audioDataU8 = (uint8_t *)audioDataS32 + sampleLength;
-		for (i = 0; i < sampleLength; i++)
+		uint8_t *audioDataU8 = (uint8_t *)audioDataS32 + sampleLength;
+		for (int32_t i = 0; i < sampleLength; i++)
 		{
 			audioDataS32[i] = (audioDataU8[0] << 24) | (audioDataU8[1] << 16) | (audioDataU8[2] << 8);
 			audioDataU8 += 3;
@@ -1492,7 +1396,7 @@
 		if (numChannels == 2)
 		{
 			sampleLength >>= 1;
-			for (i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
 			{
 				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
 				audioDataS32[i] = (int32_t)smp;
@@ -1522,9 +1426,9 @@
 		}
 
 		turnOffVoices();
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 		{
-			smp32 = (int32_t)round(audioDataS32[i] * dAmp);
+			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
 			smpPtr[i] = (int8_t)smp32;
 		}
 
@@ -1536,7 +1440,7 @@
 		if (sampleLength > config.maxSampleLength*4)
 			sampleLength = config.maxSampleLength*4;
 
-		audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
+		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
 		if (audioDataS32 == NULL)
 		{
 			fclose(f);
@@ -1554,7 +1458,7 @@
 		}
 
 		// fix endianness
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 			audioDataS32[i] = SWAP32(audioDataS32[i]);
 
 		// convert from stereo to mono (if needed)
@@ -1561,7 +1465,7 @@
 		if (numChannels == 2)
 		{
 			sampleLength >>= 1;
-			for (i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
 			{
 				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
 				audioDataS32[i] = (int32_t)smp;
@@ -1591,9 +1495,9 @@
 		}
 
 		turnOffVoices();
-		for (i = 0; i < sampleLength; i++)
+		for (int32_t i = 0; i < sampleLength; i++)
 		{
-			smp32 = (int32_t)round(audioDataS32[i] * dAmp);
+			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
 			smpPtr[i] = (int8_t)smp32;
 		}
 
@@ -1619,8 +1523,8 @@
 	fclose(f);
 
 	// copy over sample name
-	nameLen = (int32_t)strlen(entryName);
-	for (i = 0; i < 21; i++)
+	int32_t nameLen = (int32_t)strlen(entryName);
+	for (int32_t i = 0; i < 21; i++)
 		s->text[i] = (i < nameLen) ? (char)entryName[i] : '\0';
 
 	s->text[21] = '\0';
@@ -1651,9 +1555,6 @@
 
 bool loadSample(UNICHAR *fileName, char *entryName)
 {
-	uint32_t fileSize, ID;
-	FILE *f;
-
 	if (editor.sampleZero)
 	{
 		statusNotSampleZero();
@@ -1660,7 +1561,7 @@
 		return false;
 	}
 
-	f = UNICHAR_FOPEN(fileName, "rb");
+	FILE *f = UNICHAR_FOPEN(fileName, "rb");
 	if (f == NULL)
 	{
 		displayErrorMsg("FILE I/O ERROR !");
@@ -1668,12 +1569,13 @@
 	}
 
 	fseek(f, 0, SEEK_END);
-	fileSize = ftell(f);
+	uint32_t fileSize = ftell(f);
 	fseek(f, 0, SEEK_SET);
 
 	// first, check heades before we eventually load as RAW
 	if (fileSize > 16)
 	{
+		uint32_t ID;
 		fread(&ID, 4, 1, f);
 
 		/* Reject FLAC files, since they are not supported.
@@ -1695,9 +1597,9 @@
 			if (ID == 0x45564157) // "WAVE"
 			{
 				fclose(f);
-				return loadWAVSample(fileName, entryName, -1);
+				return loadWAVSample(fileName, entryName);
 			}
-		}	
+		}
 		else if (ID == 0x4D524F46) // "FORM"
 		{
 			fseek(f, 4, SEEK_CUR);
@@ -1707,7 +1609,7 @@
 			if (ID == 0x58565338 || ID == 0x56533631) // "8SVX" (normal) and "16SV" (FT2 sample)
 			{
 				fclose(f);
-				return loadIFFSample(fileName, entryName, -1);
+				return loadIFFSample(fileName, entryName);
 			}
 
 			// check if it's an AIFF sample
@@ -1714,7 +1616,7 @@
 			else if (ID == 0x46464941) // "AIFF"
 			{
 				fclose(f);
-				return loadAIFFSample(fileName, entryName, -1);
+				return loadAIFFSample(fileName, entryName);
 			}
 
 			else if (ID == 0x43464941) // "AIFC" (compressed AIFF)
--- a/src/pt2_sample_loader.h
+++ b/src/pt2_sample_loader.h
@@ -4,5 +4,4 @@
 #include <stdbool.h>
 #include "pt2_unicode.h"
 
-void extLoadWAVOrAIFFSampleCallback(bool downsample);
 bool loadSample(UNICHAR *fileName, char *entryName);
--- a/src/pt2_sample_saver.c
+++ b/src/pt2_sample_saver.c
@@ -4,7 +4,6 @@
 #include <stdbool.h>
 #include <ctype.h> // tolower()
 #include <sys/stat.h>
-#include "pt2_header.h"
 #include "pt2_structs.h"
 #include "pt2_textout.h"
 #include "pt2_mouse.h"
@@ -11,23 +10,21 @@
 #include "pt2_visuals.h"
 #include "pt2_helpers.h"
 #include "pt2_diskop.h"
+#include "pt2_askbox.h"
 
 #define PLAYBACK_FREQ 16574 /* C-3, period 214 */
 
 static void removeSampleFileExt(char *text) // for sample saver
 {
-	uint32_t fileExtPos;
-	uint32_t filenameLength;
-
 	if (text == NULL || text[0] == '\0')
 		return;
 	
-	filenameLength = (uint32_t)strlen(text);
+	uint32_t filenameLength = (uint32_t)strlen(text);
 	if (filenameLength < 5)
 		return;
 
 	// remove .wav/.iff/from end of sample name (if present)
-	fileExtPos = filenameLength - 4;
+	uint32_t fileExtPos = filenameLength - 4;
 	if (fileExtPos > 0 && (!strncmp(&text[fileExtPos], ".wav", 4) || !strncmp(&text[fileExtPos], ".iff", 4)))
 		text[fileExtPos] = '\0';
 }
@@ -66,8 +63,6 @@
 bool saveSample(bool checkIfFileExist, bool giveNewFreeFilename)
 {
 	char fileName[128], tmpBuffer[64];
-	uint32_t i, j, chunkLen;
-	FILE *f;
 	struct stat statBuffer;
 	wavHeader_t wavHeader;
 	samplerChunk_t samplerChunk;
@@ -91,7 +86,7 @@
 	}
 	else
 	{
-		for (i = 0; i < 22; i++)
+		for (int32_t i = 0; i < 22; i++)
 		{
 			tmpBuffer[i] = (char)tolower(song->samples[editor.currSample].text[i]);
 			if (tmpBuffer[i] == '\0') break;
@@ -107,7 +102,7 @@
 	// if the user picked "no" to overwriting the file, generate a new filename
 	if (giveNewFreeFilename && stat(fileName, &statBuffer) == 0)
 	{
-		for (j = 1; j <= 999; j++)
+		for (int32_t j = 1; j <= 999; j++)
 		{
 			if (s->text[0] == '\0')
 			{
@@ -115,7 +110,7 @@
 			}
 			else
 			{
-				for (i = 0; i < 22; i++)
+				for (int32_t i = 0; i < 22; i++)
 				{
 					tmpBuffer[i] = (char)tolower(song->samples[editor.currSample].text[i]);
 					if (tmpBuffer[i] == '\0') break;
@@ -133,26 +128,13 @@
 		}
 	}
 
-	// check if we need to overwrite file...
-
 	if (checkIfFileExist && stat(fileName, &statBuffer) == 0)
 	{
-		ui.askScreenShown = true;
-		ui.askScreenType = ASK_SAVESMP_OVERWRITE;
-		pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-		setStatusMessage("OVERWRITE FILE ?", NO_CARRY);
-		renderAskDialog();
-		return -1;
+		if (!askBox(ASKBOX_YES_NO, "OVERWRITE FILE ?"))
+			return false;
 	}
 
-	if (ui.askScreenShown)
-	{
-		ui.answerNo = false;
-		ui.answerYes = false;
-		ui.askScreenShown = false;
-	}
-
-	f = fopen(fileName, "wb");
+	FILE *f = fopen(fileName, "wb");
 	if (f == NULL)
 	{
 		displayErrorMsg("FILE I/O ERROR !");
@@ -208,7 +190,7 @@
 
 			fwrite(&wavHeader, sizeof (wavHeader_t), 1, f);
 
-			for (i = 0; i < sampleLength; i++)
+			for (uint32_t i = 0; i < sampleLength; i++)
 				fputc((uint8_t)(sampleData[i] + 128), f);
 
 			if (sampleLength & 1)
@@ -248,7 +230,7 @@
 			iffWriteUint32(f, s->volume * 1024); // volume (max: 65536/0x10000)
 
 			// "NAME" chunk
-			chunkLen = (uint32_t)strlen(s->text);
+			uint32_t chunkLen = (uint32_t)strlen(s->text);
 			if (chunkLen > 0)
 			{
 				iffWriteChunkHeader(f, "NAME", chunkLen);
--- a/src/pt2_sampler.c
+++ b/src/pt2_sampler.c
@@ -7,22 +7,18 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdbool.h>
-#include "pt2_header.h"
 #include "pt2_helpers.h"
 #include "pt2_textout.h"
 #include "pt2_audio.h"
 #include "pt2_tables.h"
 #include "pt2_visuals.h"
-#include "pt2_blep.h"
-#include "pt2_mouse.h"
 #include "pt2_scopes.h"
 #include "pt2_sampler.h"
-#include "pt2_structs.h"
 #include "pt2_config.h"
 #include "pt2_bmp.h"
-#include "pt2_sync.h"
 #include "pt2_rcfilter.h"
 #include "pt2_chordmaker.h"
+#include "pt2_replayer.h"
 
 #define CENTER_LINE_COLOR 0x303030
 #define MARK_COLOR_1 0x666666 /* inverted background */
@@ -32,19 +28,47 @@
 #define SAMPLE_AREA_Y_CENTER 169
 #define SAMPLE_AREA_HEIGHT 64
 
-sampler_t sampler; // globalized
-
 static int32_t samOffsetScaled, lastDrawX, lastDrawY;
+static uint16_t TToneBit;
 static uint32_t waveInvertTable[8];
 
-static const int8_t tuneToneData[32] = // Tuning Tone (Sine Wave)
+sampler_t sampler; // globalized
+
+static const int8_t tuneToneData[32] = // Tuning Tone (sine, regenerated with 127-scale instead of 128)
 {
-	   0,  25,  49,  71,  91, 106, 118, 126,
-	 127, 126, 118, 106,  91,  71,  49,  25,
-	   0, -25, -49, -71, -91,-106,-118,-126,
-	-127,-126,-118,-106, -91, -71, -49, -25
+	   0,   25,   49,   71,   90,  106,  117,  125,
+	 127,  125,  117,  106,   90,   71,   49,   25,
+	   0,  -25,  -49,  -71,  -90, -106, -117, -125,
+	-127, -125, -117, -106,  -90,  -71,  -49,  -25
 };
 
+void killSample(void)
+{
+	if (editor.sampleZero)
+	{
+		statusNotSampleZero();
+		return;
+	}
+
+	turnOffVoices();
+	moduleSample_t *s = &song->samples[editor.currSample];
+
+	s->fineTune = 0;
+	s->volume = 0;
+	s->length = 0;
+	s->loopStart = 0;
+	s->loopLength = 2;
+
+	memset(s->text, 0, sizeof (s->text));
+	memset(&song->sampleData[(editor.currSample * config.maxSampleLength)], 0, config.maxSampleLength);
+
+	editor.samplePos = 0;
+	updateCurrSample();
+
+	ui.updateSongSize = true;
+	updateWindowTitle(MOD_IS_MODIFIED);
+}
+
 void upSample(void)
 {
 	if (editor.sampleZero)
@@ -139,7 +163,7 @@
 
 void createSampleMarkTable(void)
 {
-	// used for invertRange()  (sample data marking)
+	// used for invertRange() (sample data marking)
 
 	waveInvertTable[0] = 0x00000000 | video.palette[PAL_BACKGRD];
 	waveInvertTable[1] = 0x01000000 | video.palette[PAL_QADSCP];
@@ -198,24 +222,23 @@
 
 void sampleLine(int32_t line_x1, int32_t line_x2, int32_t line_y1, int32_t line_y2)
 {
-	int32_t d, x, y, ax, ay, sx, sy, dx, dy;
-	uint32_t color = 0x01000000 | video.palette[PAL_QADSCP];
+	const uint32_t color = 0x01000000 | video.palette[PAL_QADSCP]; // set alpha to 0x10 ( used for invertRange() as a hack )
 
 	assert(line_x1 >= 0 || line_x2 >= 0 || line_x1 < SCREEN_W || line_x2 < SCREEN_W);
 	assert(line_y1 >= 0 || line_y2 >= 0 || line_y1 < SCREEN_H || line_y2 < SCREEN_H);
 
-	dx = line_x2 - line_x1;
-	ax = ABS(dx) * 2;
-	sx = SGN(dx);
-	dy = line_y2 - line_y1;
-	ay = ABS(dy) * 2;
-	sy = SGN(dy);
-	x  = line_x1;
-	y  = line_y1;
+	int32_t dx = line_x2 - line_x1;
+	int32_t ax = ABS(dx) * 2;
+	int32_t sx = SGN(dx);
+	int32_t dy = line_y2 - line_y1;
+	int32_t ay = ABS(dy) * 2;
+	int32_t sy = SGN(dy);
+	int32_t x  = line_x1;
+	int32_t y  = line_y1;
 
 	if (ax > ay)
 	{
-		d = ay - ((uint16_t)ax >> 1);
+		int32_t d = ay - ((uint16_t)ax >> 1);
 		while (true)
 		{
 			assert(y >= 0 || x >= 0 || y < SCREEN_H || x < SCREEN_W);
@@ -237,7 +260,7 @@
 	}
 	else
 	{
-		d = ax - ((uint16_t)ay >> 1);
+		int32_t d = ax - ((uint16_t)ay >> 1);
 		while (true)
 		{
 			assert(y >= 0 || x >= 0 || y < SCREEN_H || x < SCREEN_W);
@@ -261,8 +284,6 @@
 
 static void setDragBar(void)
 {
-	int32_t pos;
-
 	// clear drag bar background
 	fillRect(4, 206, 312, 4, video.palette[PAL_BACKGRD]);
 
@@ -271,7 +292,7 @@
 		const int32_t roundingBias = sampler.samLength >> 1;
 
 		// update drag bar coordinates
-		pos = 4 + (((sampler.samOffset * 311) + roundingBias) / sampler.samLength);
+		int32_t pos = 4 + (((sampler.samOffset * 311) + roundingBias) / sampler.samLength);
 		sampler.dragStart = (uint16_t)CLAMP(pos, 4, 315);
 
 		pos = 5 + ((((sampler.samDisplay + sampler.samOffset) * 311) + roundingBias) / sampler.samLength);
@@ -290,12 +311,10 @@
 
 static int8_t getScaledSample(int32_t index)
 {
-	const int8_t *ptr8;
-
 	if (sampler.samLength <= 0 || index < 0 || index > sampler.samLength)
 		return 0;
 
-	ptr8 = sampler.samStart;
+	const int8_t *ptr8 = sampler.samStart;
 	if (ptr8 == NULL)
 		return 0;
 
@@ -334,14 +353,12 @@
 
 static void getSampleDataPeak(int8_t *smpPtr, int32_t numBytes, int16_t *outMin, int16_t *outMax)
 {
-	int8_t smp, smpMin, smpMax;
+	int8_t smpMin = 127;
+	int8_t smpMax = -128;
 
-	smpMin = 127;
-	smpMax = -128;
-
 	for (int32_t i = 0; i < numBytes; i++)
 	{
-		smp = smpPtr[i];
+		int8_t smp = smpPtr[i];
 		if (smp < smpMin) smpMin = smp;
 		if (smp > smpMax) smpMax = smp;
 	}
@@ -352,14 +369,8 @@
 
 void renderSampleData(void)
 {
-	int8_t *smpPtr;
-	int16_t y1, y2, min, max, oldMin, oldMax;
-	int32_t x, smpIdx, smpNum;
-	uint32_t *dstPtr;
-	moduleSample_t *s;
+	moduleSample_t *s = &song->samples[editor.currSample];
 
-	s = &song->samples[editor.currSample];
-
 	// clear sample data background
 	fillRect(3, 138, SAMPLE_AREA_WIDTH, SAMPLE_VIEW_HEIGHT, video.palette[PAL_BACKGRD]);
 
@@ -366,8 +377,8 @@
 	// display center line (if enabled)
 	if (config.waveformCenterLine)
 	{
-		dstPtr = &video.frameBuffer[(SAMPLE_AREA_Y_CENTER * SCREEN_W) + 3];
-		for (x = 0; x < SAMPLE_AREA_WIDTH; x++)
+		uint32_t *dstPtr = &video.frameBuffer[(SAMPLE_AREA_Y_CENTER * SCREEN_W) + 3];
+		for (int32_t x = 0; x < SAMPLE_AREA_WIDTH; x++)
 			dstPtr[x] = 0x02000000 | CENTER_LINE_COLOR;
 	}
 
@@ -374,14 +385,14 @@
 	// render sample data
 	if (sampler.samDisplay >= 0 && sampler.samDisplay <= config.maxSampleLength)
 	{
-		y1 = SAMPLE_AREA_Y_CENTER - getScaledSample(scr2SmpPos(0));
+		int16_t y1 = SAMPLE_AREA_Y_CENTER - getScaledSample(scr2SmpPos(0));
 
 		if (sampler.samDisplay <= SAMPLE_AREA_WIDTH)
 		{
 			// 1:1 or zoomed in
-			for (x = 1; x < SAMPLE_AREA_WIDTH; x++)
+			for (int32_t x = 1; x < SAMPLE_AREA_WIDTH; x++)
 			{
-				y2 = SAMPLE_AREA_Y_CENTER - getScaledSample(scr2SmpPos(x));
+				int16_t y2 = SAMPLE_AREA_Y_CENTER - getScaledSample(scr2SmpPos(x));
 				sampleLine(x + 2, x + 3, y1, y2);
 				y1 = y2;
 			}
@@ -390,14 +401,16 @@
 		{
 			// zoomed out
 
-			oldMin = y1;
-			oldMax = y1;
+			int16_t min, max;
 
-			smpPtr = &song->sampleData[s->offset];
-			for (x = 0; x < SAMPLE_AREA_WIDTH; x++)
+			int16_t oldMin = y1;
+			int16_t oldMax = y1;
+
+			int8_t *smpPtr = &song->sampleData[s->offset];
+			for (int32_t x = 0; x < SAMPLE_AREA_WIDTH; x++)
 			{
-				smpIdx = scr2SmpPos(x);
-				smpNum = scr2SmpPos(x+1) - smpIdx;
+				int32_t smpIdx = scr2SmpPos(x);
+				int32_t smpNum = scr2SmpPos(x+1) - smpIdx;
 
 				// prevent look-up overflow (yes, this can happen near the end of the sample)
 				if (smpIdx+smpNum > sampler.samLength)
@@ -448,14 +461,11 @@
 
 void invertRange(void)
 {
-	int32_t x, y, rangeLen, start, end;
-	uint32_t *dstPtr;
-
 	if (editor.markStartOfs == -1)
 		return; // no marking
 
-	start = smpPos2Scr(editor.markStartOfs);
-	end = smpPos2Scr(editor.markEndOfs);
+	int32_t start = smpPos2Scr(editor.markStartOfs);
+	int32_t end = smpPos2Scr(editor.markEndOfs);
 
 	if (sampler.samDisplay < sampler.samLength && (start >= SAMPLE_AREA_WIDTH || end < 0))
 		return; // range is outside of view
@@ -463,14 +473,14 @@
 	start = CLAMP(start, 0, SAMPLE_AREA_WIDTH-1);
 	end = CLAMP(end, 0, SAMPLE_AREA_WIDTH-1);
 
-	rangeLen = (end + 1) - start;
+	int32_t rangeLen = (end + 1) - start;
 	if (rangeLen < 1)
 		rangeLen = 1;
 
-	dstPtr = &video.frameBuffer[(138 * SCREEN_W) + (start + 3)];
-	for (y = 0; y < 64; y++)
+	uint32_t *dstPtr = &video.frameBuffer[(138 * SCREEN_W) + (start + 3)];
+	for (int32_t y = 0; y < 64; y++)
 	{
-		for (x = 0; x < rangeLen; x++)
+		for (int32_t x = 0; x < rangeLen; x++)
 			dstPtr[x] = waveInvertTable[((dstPtr[x] >> 24) & 7) ^ 4]; // ptr[x]>>24 = wave/invert color number
 
 		dstPtr += SCREEN_W;
@@ -491,8 +501,6 @@
 
 void redrawSample(void)
 {
-	moduleSample_t *s;
-
 	if (!ui.samplerScreenShown)
 		return;
 
@@ -504,7 +512,7 @@
 		sampler.samOffset = 0;
 		updateSamOffset();
 
-		s = &song->samples[editor.currSample];
+		moduleSample_t *s = &song->samples[editor.currSample];
 		if (s->length > 0)
 		{
 			sampler.samStart = &song->sampleData[s->offset];
@@ -529,9 +537,6 @@
 
 void highPassSample(int32_t cutOff)
 {
-	int32_t i, from, to;
-	double *dSampleData, dBaseFreq, dCutOff;
-	moduleSample_t *s;
 	rcFilter_t filterHi;
 
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
@@ -548,7 +553,7 @@
 		return;
 	}
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length == 0)
 	{
 		statusSampleIsEmpty();
@@ -555,8 +560,8 @@
 		return;
 	}
 
-	from = 0;
-	to = s->length;
+	int32_t from = 0;
+	int32_t to = s->length;
 
 	if (editor.markStartOfs != -1)
 	{
@@ -573,7 +578,7 @@
 		}
 	}
 
-	dSampleData = (double *)malloc(s->length * sizeof (double));
+	double *dSampleData = (double *)malloc(s->length * sizeof (double));
 	if (dSampleData == NULL)
 	{
 		statusOutOfMemory();
@@ -584,9 +589,9 @@
 
 	// setup filter coefficients
 
-	dBaseFreq = FILTERS_BASE_FREQ;
+	double dBaseFreq = FILTERS_BASE_FREQ;
 
-	dCutOff = (double)cutOff;
+	double dCutOff = (double)cutOff;
 	if (dCutOff >= dBaseFreq/2.0)
 	{
 		dCutOff = dBaseFreq/2.0;
@@ -599,7 +604,7 @@
 	if (to <= s->length)
 	{
 		const int8_t *smpPtr = &song->sampleData[s->offset];
-		for (i = from; i < to; i++)
+		for (int32_t i = from; i < to; i++)
 		{
 			double dSmp = smpPtr[i];
 			RCHighPassFilter(&filterHi, dSmp, &dSampleData[i]);
@@ -615,7 +620,7 @@
 	}
 
 	int8_t *smpPtr = &song->sampleData[s->offset];
-	for (i = from; i < to; i++)
+	for (int32_t i = from; i < to; i++)
 	{
 		int16_t smp16 = (int16_t)round(dSampleData[i] * dAmp);
 		CLAMP8(smp16);
@@ -631,9 +636,6 @@
 
 void lowPassSample(int32_t cutOff)
 {
-	int32_t i, from, to;
-	double *dSampleData, dBaseFreq, dCutOff;
-	moduleSample_t *s;
 	rcFilter_t filterLo;
 
 	if (editor.sampleZero)
@@ -650,7 +652,7 @@
 		return;
 	}
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length == 0)
 	{
 		statusSampleIsEmpty();
@@ -657,8 +659,8 @@
 		return;
 	}
 
-	from = 0;
-	to = s->length;
+	int32_t from = 0;
+	int32_t to = s->length;
 
 	if (editor.markStartOfs != -1)
 	{
@@ -675,7 +677,7 @@
 		}
 	}
 
-	dSampleData = (double *)malloc(s->length * sizeof (double));
+	double *dSampleData = (double *)malloc(s->length * sizeof (double));
 	if (dSampleData == NULL)
 	{
 		statusOutOfMemory();
@@ -686,9 +688,9 @@
 
 	// setup filter coefficients
 
-	dBaseFreq = FILTERS_BASE_FREQ;
+	double dBaseFreq = FILTERS_BASE_FREQ;
 
-	dCutOff = (double)cutOff;
+	double dCutOff = (double)cutOff;
 	if (dCutOff >= dBaseFreq/2.0)
 	{
 		dCutOff = dBaseFreq/2.0;
@@ -698,7 +700,7 @@
 	calcRCFilterCoeffs(dBaseFreq, dCutOff, &filterLo);
 
 	// copy over sample data to double buffer
-	for (i = 0; i < s->length; i++)
+	for (int32_t i = 0; i < s->length; i++)
 		dSampleData[i] = song->sampleData[s->offset+i];
 
 	clearRCFilterState(&filterLo);
@@ -705,7 +707,7 @@
 	if (to <= s->length)
 	{
 		const int8_t *smpPtr = &song->sampleData[s->offset];
-		for (i = from; i < to; i++)
+		for (int32_t i = from; i < to; i++)
 		{ 
 			double dSmp = smpPtr[i];
 			RCLowPassFilter(&filterLo, dSmp, &dSampleData[i]);
@@ -722,7 +724,7 @@
 	}
 
 	int8_t *smpPtr = &song->sampleData[s->offset];
-	for (i = from; i < to; i++)
+	for (int32_t i = from; i < to; i++)
 	{
 		int16_t smp16 = (int16_t)round(dSampleData[i] * dAmp);
 		CLAMP8(smp16);
@@ -744,12 +746,9 @@
 		return;
 	}
 
-	moduleSample_t *s;
-
 	assert(sample >= 0 && sample <= 30);
+	moduleSample_t *s = &song->samples[sample];
 
-	s = &song->samples[sample];
-
 	turnOffVoices();
 
 	if (editor.smpRedoBuffer[sample] != NULL && editor.smpRedoLengths[sample] > 0)
@@ -787,12 +786,9 @@
 
 void fillSampleRedoBuffer(int8_t sample)
 {
-	moduleSample_t *s;
-
 	assert(sample >= 0 && sample <= 30);
+	moduleSample_t *s = &song->samples[sample];
 
-	s = &song->samples[sample];
-
 	if (editor.smpRedoBuffer[sample] != NULL)
 	{
 		free(editor.smpRedoBuffer[sample]);
@@ -850,10 +846,6 @@
 
 void samplerRemoveDcOffset(void)
 {
-	int8_t *smpDat;
-	int32_t smp32, i, from, to, offset;
-	moduleSample_t *s;
-
 	if (editor.sampleZero)
 	{
 		statusNotSampleZero();
@@ -862,7 +854,7 @@
 
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length == 0)
 	{
 		statusSampleIsEmpty();
@@ -869,10 +861,10 @@
 		return;
 	}
 
-	smpDat = &song->sampleData[s->offset];
+	int8_t *smpDat = &song->sampleData[s->offset];
 
-	from = 0;
-	to = s->length;
+	int32_t from = 0;
+	int32_t to = s->length;
 
 	if (editor.markStartOfs != -1)
 	{
@@ -893,15 +885,15 @@
 		return;
 
 	// calculate offset value
-	offset = 0;
-	for (i = from; i < to; i++)
+	int32_t offset = 0;
+	for (int32_t i = from; i < to; i++)
 		offset += smpDat[i];
 	offset /= to;
 
 	// remove DC offset
-	for (i = from; i < to; i++)
+	for (int32_t i = from; i < to; i++)
 	{
-		smp32 = smpDat[i] - offset;
+		int32_t smp32 = smpDat[i] - offset;
 		CLAMP8(smp32);
 		smpDat[i] = (int8_t)smp32;
 	}
@@ -920,15 +912,9 @@
 	s1 += s2; \
 	s1 >>= 8; \
 
-
 void samplerResample(void)
 {
-	int8_t *readData, *writeData;
-	int16_t refPeriod, newPeriod;
-	int32_t samples[INTRP_LINEAR_TAPS], i, pos, readPos, writePos;
-	int32_t readLength, writeLength, loopStart, loopLength;
-	uint64_t frac64, delta64;
-	moduleSample_t *s;
+	int32_t samples[INTRP_LINEAR_TAPS];
 
 	if (editor.sampleZero)
 	{
@@ -939,7 +925,7 @@
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
 	assert(editor.tuningNote <= 35 && editor.resampleNote <= 35);
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length == 0)
 	{
 		statusSampleIsEmpty();
@@ -947,19 +933,19 @@
 	}
 
 	// setup resampling variables
-	readPos = 0;
-	writePos = 0;
-	writeData = &song->sampleData[s->offset];
-	refPeriod = periodTable[editor.tuningNote];
-	newPeriod = periodTable[(37 * (s->fineTune & 0xF)) + editor.resampleNote];
-	readLength = s->length;
-	writeLength = (readLength * newPeriod) / refPeriod;
+	int32_t readPos = 0;
+	int32_t writePos = 0;
+	int8_t *writeData = &song->sampleData[s->offset];
+	int16_t refPeriod = periodTable[editor.tuningNote];
+	int16_t newPeriod = periodTable[(37 * (s->fineTune & 0xF)) + editor.resampleNote];
+	int32_t readLength = s->length;
+	int32_t writeLength = (readLength * newPeriod) / refPeriod;
 
 	if (readLength == writeLength)
 		return; // no resampling needed
 
 	// allocate memory for our sample duplicate
-	readData = (int8_t *)malloc(s->length);
+	int8_t *readData = (int8_t *)malloc(s->length);
 	if (readData == NULL)
 	{
 		statusOutOfMemory();
@@ -973,7 +959,7 @@
 		return;
 	}
 
-	delta64 = ((uint64_t)readLength << 32) / writeLength;
+	uint64_t delta64 = ((uint64_t)readLength << 32) / writeLength;
 	assert(delta64 != 0);
 
 	writeLength = writeLength & ~1;
@@ -984,15 +970,15 @@
 
 	// resample
 
-	frac64 = 0;
-
 	turnOffVoices();
+
+	uint64_t frac64 = 0;
 	while (writePos < writeLength)
 	{
 		// collect samples for interpolation
-		for (i = 0; i < INTRP_LINEAR_TAPS; i++)
+		for (int32_t i = 0; i < INTRP_LINEAR_TAPS; i++)
 		{
-			pos = readPos + i;
+			int32_t pos = readPos + i;
 			if (pos >= readLength)
 				samples[i] = 0;
 			else
@@ -1004,7 +990,7 @@
 
 		frac64 += delta64;
 		readPos += frac64 >> 32;
-		frac64 &= 0xFFFFFFFF;
+		frac64 &= UINT32_MAX;
 	}
 	free(readData);
 
@@ -1019,8 +1005,8 @@
 	// scale loop points (and deactivate if overflowing)
 	if ((s->loopStart + s->loopLength) > 2)
 	{
-		loopStart = (int32_t)(((uint64_t)s->loopStart << 32) / delta64) & ~1;
-		loopLength = (int32_t)(((uint64_t)s->loopLength << 32) / delta64) & ~1;
+		int32_t loopStart = (int32_t)(((uint64_t)s->loopStart << 32) / delta64) & ~1;
+		int32_t loopLength = (int32_t)(((uint64_t)s->loopLength << 32) / delta64) & ~1;
 
 		if (loopStart+loopLength > s->length)
 		{
@@ -1068,15 +1054,12 @@
 
 void doMix(void)
 {
-	int8_t *fromPtr1, *fromPtr2, *mixPtr;
-	uint8_t smpFrom1, smpFrom2, smpTo;
-	int16_t tmp16;
-	int32_t i, mixLength;
-	moduleSample_t *s1, *s2, *s3;
+	int8_t *fromPtr1, *fromPtr2;
+	int32_t mixLength;
 
-	smpFrom1 = hexToInteger2(&editor.mixText[4]);
-	smpFrom2 = hexToInteger2(&editor.mixText[7]);
-	smpTo = hexToInteger2(&editor.mixText[13]);
+	uint8_t smpFrom1 = hexToInteger2(&editor.mixText[4]);
+	uint8_t smpFrom2 = hexToInteger2(&editor.mixText[7]);
+	uint8_t smpTo = hexToInteger2(&editor.mixText[13]);
 
 	if (smpFrom1 == 0 || smpFrom1 > 0x1F || smpFrom2 == 0 || smpFrom2 > 0x1F || smpTo == 0 || smpTo > 0x1F)
 	{
@@ -1088,9 +1071,9 @@
 	smpFrom2--;
 	smpTo--;
 
-	s1 = &song->samples[smpFrom1];
-	s2 = &song->samples[smpFrom2];
-	s3 = &song->samples[smpTo];
+	moduleSample_t *s1 = &song->samples[smpFrom1];
+	moduleSample_t *s2 = &song->samples[smpFrom2];
+	moduleSample_t *s3 = &song->samples[smpTo];
 
 	if (s1->length == 0 || s2->length == 0)
 	{
@@ -1111,7 +1094,7 @@
 		mixLength = s2->length;
 	}
 
-	mixPtr = (int8_t *)malloc(mixLength);
+	int8_t *mixPtr = (int8_t *)malloc(mixLength);
 	if (mixPtr == NULL)
 	{
 		statusOutOfMemory();
@@ -1120,9 +1103,9 @@
 
 	turnOffVoices();
 
-	for (i = 0; i < mixLength; i++)
+	for (int32_t i = 0; i < mixLength; i++)
 	{
-		tmp16 = (i < s2->length) ? (fromPtr1[i] + fromPtr2[i]) : fromPtr1[i];
+		int16_t tmp16 = (i < s2->length) ? (fromPtr1[i] + fromPtr2[i]) : fromPtr1[i];
 		if (editor.halfClipFlag == 0)
 			tmp16 >>= 1;
 
@@ -1153,21 +1136,16 @@
 // this is actually treble increase
 void boostSample(int32_t sample, bool ignoreMark)
 {
-	int8_t *smpDat;
-	int16_t tmp16_0, tmp16_1, tmp16_2;
-	int32_t i, from, to;
-	moduleSample_t *s;
-
 	assert(sample >= 0 && sample <= 30);
 
-	s = &song->samples[sample];
+	moduleSample_t *s = &song->samples[sample];
 	if (s->length == 0)
 		return; // don't display warning/show warning pointer, it is done elsewhere
 
-	smpDat = &song->sampleData[s->offset];
+	int8_t *smpDat = &song->sampleData[s->offset];
 
-	from = 0;
-	to = s->length;
+	int32_t from = 0;
+	int32_t to = s->length;
 
 	if (!ignoreMark)
 	{
@@ -1187,11 +1165,11 @@
 		}
 	}
 
-	tmp16_0 = 0;
-	for (i = from; i < to; i++)
+	int16_t tmp16_0 = 0;
+	for (int32_t i = from; i < to; i++)
 	{
-		tmp16_1 = smpDat[i];
-		tmp16_2 = tmp16_1;
+		int16_t tmp16_1 = smpDat[i];
+		int16_t tmp16_2 = tmp16_1;
 		tmp16_1 -= tmp16_0;
 		tmp16_0 = tmp16_2;
 		tmp16_1 >>= 2;
@@ -1209,21 +1187,16 @@
 // this is actually treble decrease
 void filterSample(int32_t sample, bool ignoreMark)
 {
-	int8_t *smpDat;
-	int16_t tmp16;
-	int32_t i, from, to;
-	moduleSample_t *s;
-
 	assert(sample >= 0 && sample <= 30);
 
-	s = &song->samples[sample];
+	moduleSample_t *s = &song->samples[sample];
 	if (s->length == 0)
 		return; // don't display warning/show warning pointer, it is done elsewhere
 
-	smpDat = &song->sampleData[s->offset];
+	int8_t *smpDat = &song->sampleData[s->offset];
 
-	from = 1;
-	to = s->length;
+	int32_t from = 1;
+	int32_t to = s->length;
 
 	if (!ignoreMark)
 	{
@@ -1247,9 +1220,9 @@
 		return;
 	to--;
 
-	for (i = from; i < to; i++)
+	for (int32_t i = from; i < to; i++)
 	{
-		tmp16 = (smpDat[i+0] + smpDat[i+1]) >> 1;
+		int16_t tmp16 = (smpDat[i+0] + smpDat[i+1]) >> 1;
 		CLAMP8(tmp16);
 		smpDat[i] = (int8_t)tmp16;
 	}
@@ -1260,45 +1233,46 @@
 
 void toggleTuningTone(void)
 {
+	// bugfix: don't allow tuning tone during play (it was very bugged anyway)
 	if (editor.currMode == MODE_PLAY || editor.currMode == MODE_RECORD)
 		return;
 
-	editor.tuningFlag ^= 1;
-	if (editor.tuningFlag)
+	editor.tuningToneFlag ^= 1;
+	if (editor.tuningToneFlag)
 	{
 		// turn tuning tone on
 
-		const int8_t ch = editor.tuningChan = (cursor.channel + 1) & 3;
+		const int32_t chNum = (cursor.channel + 1) & 3;
+		TToneBit = 1 << chNum;
 
-		if (editor.tuningNote > 35)
-			editor.tuningNote = 35;
-
 		lockAudio();
 
-		song->channels[ch].n_volume = 64; // we need this for the scopes
+		paulaSetDMACON(TToneBit); // voice DMA off
 
-		paulaSetPeriod(ch, periodTable[editor.tuningNote]);
-		paulaSetVolume(ch, 64);
-		paulaSetData(ch, tuneToneData);
-		paulaSetLength(ch, sizeof (tuneToneData) / 2);
-		paulaStartDMA(ch);
+		paulaSetPeriod(chNum, periodTable[editor.tuningNote]);
+		paulaSetVolume(chNum, 64);
+		paulaSetData(chNum, tuneToneData);
+		paulaSetLength(chNum, sizeof (tuneToneData) / 2);
 
+		paulaSetDMACON(0x8000 | TToneBit); // voice DMA on
+
 		unlockAudio();
 	}
 	else
 	{
 		// turn tuning tone off
-		mixerKillVoice(editor.tuningChan);
+
+		lockAudio();
+		paulaSetDMACON(TToneBit); // voice DMA off
+		unlockAudio();
 	}
 }
 
 void sampleMarkerToBeg(void)
 {
-	moduleSample_t *s;
-
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length == 0)
 	{
 		invertRange();
@@ -1327,12 +1301,9 @@
 
 void sampleMarkerToCenter(void)
 {
-	int32_t middlePos;
-	moduleSample_t *s;
-
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length == 0)
 	{
 		invertRange();
@@ -1341,7 +1312,7 @@
 	}
 	else
 	{
-		middlePos = sampler.samOffset + ((sampler.samDisplay + 1) / 2);
+		int32_t middlePos = sampler.samOffset + ((sampler.samDisplay + 1) / 2);
 
 		invertRange();
 		if (keyb.shiftPressed && editor.markStartOfs != -1)
@@ -1366,11 +1337,9 @@
 
 void sampleMarkerToEnd(void)
 {
-	moduleSample_t *s;
-
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length == 0)
 	{
 		invertRange();
@@ -1399,8 +1368,6 @@
 
 void samplerSamCopy(void)
 {
-	moduleSample_t *s;
-
 	if (editor.sampleZero)
 	{
 		statusNotSampleZero();
@@ -1407,8 +1374,6 @@
 		return;
 	}
 
-	assert(editor.currSample >= 0 && editor.currSample <= 30);
-
 	if (editor.markStartOfs == -1)
 	{
 		displayErrorMsg("NO RANGE SELECTED");
@@ -1421,7 +1386,9 @@
 		return;
 	}
 
-	s = &song->samples[editor.currSample];
+	assert(editor.currSample >= 0 && editor.currSample <= 30);
+
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length == 0)
 	{
 		statusSampleIsEmpty();
@@ -1441,10 +1408,6 @@
 
 void samplerSamDelete(uint8_t cut)
 {
-	int8_t *tmpBuf;
-	int32_t val32, sampleLength, copyLength, markEnd, markStart;
-	moduleSample_t *s;
-
 	if (editor.sampleZero)
 	{
 		statusNotSampleZero();
@@ -1451,8 +1414,6 @@
 		return;
 	}
 
-	assert(editor.currSample >= 0 && editor.currSample <= 30);
-
 	if (editor.markStartOfs == -1)
 	{
 		displayErrorMsg("NO RANGE SELECTED");
@@ -1468,9 +1429,10 @@
 	if (cut)
 		samplerSamCopy();
 
-	s = &song->samples[editor.currSample];
+	assert(editor.currSample >= 0 && editor.currSample <= 30);
+	moduleSample_t *s = &song->samples[editor.currSample];
 
-	sampleLength = s->length;
+	int32_t sampleLength = s->length;
 	if (sampleLength == 0)
 	{
 		statusSampleIsEmpty();
@@ -1504,10 +1466,10 @@
 		return;
 	}
 
-	markEnd = (editor.markEndOfs > sampleLength) ? sampleLength : editor.markEndOfs;
-	markStart = editor.markStartOfs;
+	int32_t markEnd = (editor.markEndOfs > sampleLength) ? sampleLength : editor.markEndOfs;
+	int32_t markStart = editor.markStartOfs;
 
-	copyLength = (editor.markStartOfs + sampleLength) - markEnd;
+	int32_t copyLength = (editor.markStartOfs + sampleLength) - markEnd;
 	if (copyLength < 2 || copyLength > config.maxSampleLength)
 	{
 		displayErrorMsg("SAMPLE CUT FAIL !");
@@ -1514,7 +1476,7 @@
 		return;
 	}
 
-	tmpBuf = (int8_t *)malloc(copyLength);
+	int8_t *tmpBuf = (int8_t *)malloc(copyLength);
 	if (tmpBuf == NULL)
 	{
 		statusOutOfMemory();
@@ -1528,7 +1490,7 @@
 	if (sampleLength-markEnd > 0)
 		memcpy(&tmpBuf[editor.markStartOfs], &song->sampleData[s->offset+markEnd], sampleLength - markEnd);
 
-	// nuke sample data and copy over the result
+	// wipe sample data and copy over the result
 	memcpy(&song->sampleData[s->offset], tmpBuf, copyLength);
 
 	if (copyLength < config.maxSampleLength)
@@ -1567,7 +1529,7 @@
 			if (markStart < s->loopStart+s->loopLength)
 			{
 				// we cut data inside the loop, increase loop length
-				val32 = (s->loopLength - (markEnd - markStart)) & ~1;
+				int32_t val32 = (s->loopLength - (markEnd - markStart)) & ~1;
 				if (val32 < 2)
 					val32 = 2;
 
@@ -1579,7 +1541,7 @@
 		else
 		{
 			// we cut data before the loop, adjust loop start point
-			val32 = (s->loopStart - (markEnd - markStart)) & ~1;
+			int32_t val32 = (s->loopStart - (markEnd - markStart)) & ~1;
 			if (val32 < 0)
 			{
 				s->loopStart = 0;
@@ -1638,12 +1600,6 @@
 
 void samplerSamPaste(void)
 {
-	bool wasZooming;
-	int8_t *tmpBuf;
-	int32_t markStart;
-	uint32_t readPos;
-	moduleSample_t *s;
-
 	if (editor.sampleZero)
 	{
 		statusNotSampleZero();
@@ -1650,8 +1606,6 @@
 		return;
 	}
 
-	assert(editor.currSample >= 0 && editor.currSample <= 30);
-
 	if (sampler.copyBuf == NULL || sampler.copyBufSize == 0)
 	{
 		displayErrorMsg("BUFFER IS EMPTY");
@@ -1658,7 +1612,9 @@
 		return;
 	}
 
-	s = &song->samples[editor.currSample];
+	assert(editor.currSample >= 0 && editor.currSample <= 30);
+
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length > 0 && editor.markStartOfs == -1)
 	{
 		displayErrorMsg("SET CURSOR POS");
@@ -1665,7 +1621,7 @@
 		return;
 	}
 
-	markStart = editor.markStartOfs;
+	int32_t markStart = editor.markStartOfs;
 	if (s->length == 0)
 		markStart = 0;
 
@@ -1675,7 +1631,7 @@
 		return;
 	}
 
-	tmpBuf = (int8_t *)malloc(config.maxSampleLength);
+	int8_t *tmpBuf = (int8_t *)malloc(config.maxSampleLength);
 	if (tmpBuf == NULL)
 	{
 		statusOutOfMemory();
@@ -1682,9 +1638,9 @@
 		return;
 	}
 
-	readPos = 0;
+	uint32_t readPos = 0;
 	turnOffVoices();
-	wasZooming = (sampler.samDisplay != sampler.samLength);
+	bool wasZooming = (sampler.samDisplay != sampler.samLength);
 
 	// copy start part
 	if (markStart > 0)
@@ -1785,18 +1741,15 @@
 
 static void playCurrSample(uint8_t chn, int32_t startOffset, int32_t endOffset, bool playWaveformFlag)
 {
-	moduleChannel_t *ch;
-	moduleSample_t *s;
-
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
-	assert(chn < AMIGA_VOICES);
+	assert(chn < PAULA_VOICES);
 	assert(editor.currPlayNote <= 35);
 
+	moduleSample_t *s = &song->samples[editor.currSample];
+	moduleChannel_t *ch = &song->channels[chn];
+
 	lockAudio();
 
-	s = &song->samples[editor.currSample];
-	ch = &song->channels[chn];
-
 	ch->n_samplenum = editor.currSample;
 	ch->n_volume = s->volume;
 	ch->n_period = periodTable[(37 * (s->fineTune & 0xF)) + editor.currPlayNote];
@@ -1825,9 +1778,9 @@
 	paulaSetLength(chn, ch->n_length);
 
 	if (!editor.muted[chn])
-		paulaStartDMA(chn);
+		paulaSetDMACON(0x8000 | ch->n_dmabit); // voice DMA on
 	else
-		paulaStopDMA(chn);
+		paulaSetDMACON(ch->n_dmabit); // voice DMA off
 
 	// these take effect after the current DMA cycle is done
 	if (playWaveformFlag)
@@ -1841,9 +1794,9 @@
 		paulaSetLength(chn, 1);
 	}
 
-	updateSpectrumAnalyzer(ch->n_volume, ch->n_period);
-
 	unlockAudio();
+
+	updateSpectrumAnalyzer(ch->n_volume, ch->n_period);
 }
 
 void samplerPlayWaveform(void)
@@ -1878,8 +1831,6 @@
 
 void setLoopSprites(void)
 {
-	moduleSample_t *s;
-
 	if (!ui.samplerScreenShown)
 	{
 		hideSprite(SPRITE_LOOP_PIN_LEFT);
@@ -1889,7 +1840,7 @@
 
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->loopStart+s->loopLength > 2)
 	{
 		if (sampler.samDisplay > 0)
@@ -1902,7 +1853,7 @@
 
 			sampler.loopEndPos = (int16_t)smpPos2Scr(s->loopStart + s->loopLength);
 
-			/* nasty kludge for where the right loop pin would sometimes disappear
+			/* Nasty kludge for where the right loop pin would sometimes disappear
 			** when zoomed in and scrolled all the way to the right.
 			*/
 			if (sampler.loopEndPos == SAMPLE_AREA_WIDTH+1)
@@ -1940,8 +1891,6 @@
 
 static void samplerZoomIn(int32_t step, int32_t x)
 {
-	int32_t tmpDisplay, tmpOffset;
-
 	if (song->samples[editor.currSample].length == 0 || sampler.samDisplay <= 2)
 		return;
 
@@ -1948,7 +1897,7 @@
 	if (step < 1)
 		step = 1;
 
-	tmpDisplay = sampler.samDisplay - (step << 1);
+	int32_t tmpDisplay = sampler.samDisplay - (step << 1);
 	if (tmpDisplay < 2)
 		tmpDisplay = 2;
 
@@ -1956,7 +1905,7 @@
 
 	step += (((x - (SCREEN_W / 2)) * step) + roundingBias) / (SCREEN_W / 2);
 
-	tmpOffset = sampler.samOffset + step;
+	int32_t tmpOffset = sampler.samOffset + step;
 	if (tmpOffset < 0)
 		tmpOffset = 0;
 
@@ -1972,7 +1921,7 @@
 
 static void samplerZoomOut(int32_t step, int32_t x)
 {
-	int32_t tmpDisplay, tmpOffset;
+	int32_t tmpOffset;
 
 	if (song->samples[editor.currSample].length == 0 || sampler.samDisplay == sampler.samLength)
 		return;
@@ -1980,7 +1929,7 @@
 	if (step < 1)
 		step = 1;
 
-	tmpDisplay = sampler.samDisplay + (step << 1);
+	int32_t tmpDisplay = sampler.samDisplay + (step << 1);
 	if (tmpDisplay > sampler.samLength)
 	{
 		tmpOffset  = 0;
@@ -2024,11 +1973,9 @@
 
 void samplerRangeAll(void)
 {
-	moduleSample_t *s;
-
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length == 0)
 	{
 		invertRange();
@@ -2045,11 +1992,9 @@
 
 void samplerShowRange(void)
 {
-	moduleSample_t *s;
-
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length == 0)
 	{
 		statusSampleIsEmpty();
@@ -2084,8 +2029,6 @@
 
 void volBoxBarPressed(bool mouseButtonHeld)
 {
-	int32_t mouseX;
-
 	if (!mouseButtonHeld)
 	{
 		if (mouse.x >= 72 && mouse.x <= 173)
@@ -2099,7 +2042,7 @@
 		if (sampler.lastMouseX != mouse.x)
 		{
 			sampler.lastMouseX = mouse.x;
-			mouseX = CLAMP(sampler.lastMouseX - 107, 0, 60);
+			int32_t mouseX = CLAMP(sampler.lastMouseX - 107, 0, 60);
 
 			if (ui.forceVolDrag == 1)
 			{
@@ -2119,8 +2062,6 @@
 
 void samplerBarPressed(bool mouseButtonHeld)
 {
-	int32_t tmp32;
-
 	if (!mouseButtonHeld)
 	{
 		if (mouse.x >= 4 && mouse.x <= 315)
@@ -2127,7 +2068,7 @@
 		{
 			if (mouse.x < sampler.dragStart)
 			{
-				tmp32 = sampler.samOffset - sampler.samDisplay;
+				int32_t tmp32 = sampler.samOffset - sampler.samDisplay;
 				if (tmp32 < 0)
 					tmp32 = 0;
 
@@ -2143,7 +2084,7 @@
 
 			if (mouse.x > sampler.dragEnd)
 			{
-				tmp32 = sampler.samOffset + sampler.samDisplay;
+				int32_t tmp32 = sampler.samOffset + sampler.samDisplay;
 				if (tmp32+sampler.samDisplay <= sampler.samLength)
 				{
 					if (tmp32 == sampler.samOffset)
@@ -2176,7 +2117,7 @@
 	{
 		sampler.lastSamPos = mouse.x;
 
-		tmp32 = sampler.lastSamPos - sampler.saveMouseX - 4;
+		int32_t tmp32 = sampler.lastSamPos - sampler.saveMouseX - 4;
 		tmp32 = CLAMP(tmp32, 0, SAMPLE_AREA_WIDTH);
 
 		tmp32 = ((tmp32 * sampler.samLength) + (311/2)) / 311; // rounded
@@ -2203,8 +2144,6 @@
 
 static int32_t mouseYToSampleY(int32_t my)
 {
-	int32_t tmp32;
-
 	if (my == SAMPLE_AREA_Y_CENTER) // center
 	{
 		return 128;
@@ -2211,20 +2150,18 @@
 	}
 	else
 	{
-		tmp32 = my - 138;
+		int32_t tmp32 = my - 138;
 		tmp32 = ((tmp32 << 8) + (SAMPLE_AREA_HEIGHT/2)) / SAMPLE_AREA_HEIGHT;
 		tmp32 = CLAMP(tmp32, 0, 255);
 		tmp32 ^= 0xFF;
-	}
 
-	return tmp32;
+		return tmp32;
+	}
 }
 
 void samplerEditSample(bool mouseButtonHeld)
 {
-	int8_t *ptr8;
-	int32_t mx, my, tmp32, p, vl, tvl, r, rl, rvl, start, end;
-	moduleSample_t *s;
+	int32_t p, vl;
 
 	if (editor.sampleZero)
 	{
@@ -2233,7 +2170,7 @@
 	}
 
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 
 	if (s->length == 0)
 	{
@@ -2241,11 +2178,11 @@
 		return;
 	}
 
-	mx = mouse.x;
+	int32_t mx = mouse.x;
 	if (mx > 4+SAMPLE_AREA_WIDTH)
 		mx = 4+SAMPLE_AREA_WIDTH;
 
-	my = mouse.y;
+	int32_t my = mouse.y;
 
 	if (!mouseButtonHeld)
 	{
@@ -2273,14 +2210,14 @@
 	sampler.lastMouseX = mx;
 	sampler.lastMouseY = my;
 
-	r = p;
-	rvl = vl;
+	int32_t r = p;
+	int32_t rvl = vl;
 
 	// swap x/y if needed
 	if (p > lastDrawX)
 	{
 		// swap x
-		tmp32 = p;
+		int32_t tmp32 = p;
 		p = lastDrawX;
 		lastDrawX = tmp32;
 
@@ -2290,13 +2227,13 @@
 		vl = tmp32;
 	}
 
-	ptr8 = &song->sampleData[s->offset];
+	int8_t *ptr8 = &song->sampleData[s->offset];
 
-	start = p;
+	int32_t start = p;
 	if (start < 0)
 		start = 0;
 
-	end = lastDrawX+1;
+	int32_t end = lastDrawX+1;
 	if (end > s->length)
 		end = s->length;
 
@@ -2303,8 +2240,8 @@
 	if (p == lastDrawX)
 	{
 		const int8_t smpVal = (int8_t)(vl ^ 0x80);
-		for (rl = start; rl < end; rl++)
-			ptr8[rl] = smpVal;
+		for (int32_t i = start; i < end; i++)
+			ptr8[i] = smpVal;
 	}
 	else
 	{
@@ -2316,9 +2253,9 @@
 			double dMul = 1.0 / x;
 			int32_t i = 0;
 
-			for (rl = start; rl < end; rl++)
+			for (int32_t rl = start; rl < end; rl++)
 			{
-				tvl = y * i;
+				int32_t tvl = y * i;
 				tvl = (int32_t)(tvl * dMul); // tvl /= x
 				tvl += vl;
 				tvl ^= 0x80;
@@ -2337,11 +2274,6 @@
 
 void samplerSamplePressed(bool mouseButtonHeld)
 {
-	int32_t mouseX, tmpPos;
-	moduleSample_t *s;
-
-	assert(editor.currSample >= 0 && editor.currSample <= 30);
-
 	if (!mouseButtonHeld)
 	{
 		if (!editor.sampleZero && mouse.y < 142)
@@ -2365,9 +2297,10 @@
 		}
 	}
 
-	mouseX = CLAMP(mouse.x, 0, SCREEN_W+8); // allow some extra pixels outside of the screen
+	int32_t mouseX = CLAMP(mouse.x, 0, SCREEN_W+8); // allow some extra pixels outside of the screen
 
-	s = &song->samples[editor.currSample];
+	assert(editor.currSample >= 0 && editor.currSample <= 30);
+	moduleSample_t *s = &song->samples[editor.currSample];
 
 	if (ui.leftLoopPinMoving)
 	{
@@ -2375,7 +2308,7 @@
 		{
 			sampler.lastMouseX = mouseX;
 
-			tmpPos = (scr2SmpPos(mouseX - 1) - s->loopStart) & ~1;
+			int32_t tmpPos = (scr2SmpPos(mouseX - 1) - s->loopStart) & ~1;
 			if (tmpPos > config.maxSampleLength)
 				tmpPos = config.maxSampleLength;
 
@@ -2398,7 +2331,7 @@
 			ui.updateCurrSampleReplen = true;
 
 			setLoopSprites();
-			mixerUpdateLoops();
+			updatePaulaLoops();
 			updateWindowTitle(MOD_IS_MODIFIED);
 		}
 
@@ -2413,7 +2346,7 @@
 
 			s = &song->samples[editor.currSample];
 
-			tmpPos = (scr2SmpPos(mouseX - 4) - s->loopStart) & ~1;
+			int32_t tmpPos = (scr2SmpPos(mouseX - 4) - s->loopStart) & ~1;
 			tmpPos = CLAMP(tmpPos, 2, config.maxSampleLength);
 
 			s->loopLength = tmpPos;
@@ -2422,7 +2355,7 @@
 			ui.updateCurrSampleReplen = true;
 
 			setLoopSprites();
-			mixerUpdateLoops();
+			updatePaulaLoops();
 			updateWindowTitle(MOD_IS_MODIFIED);
 		}
 
@@ -2459,7 +2392,7 @@
 		}
 		else
 		{
-			tmpPos = scr2SmpPos(mouseX - 3);
+			int32_t tmpPos = scr2SmpPos(mouseX - 3);
 			if (tmpPos > s->length)
 				tmpPos = s->length;
 
@@ -2508,7 +2441,7 @@
 	}
 	else
 	{
-		tmpPos = scr2SmpPos(mouseX - 3);
+		int32_t tmpPos = scr2SmpPos(mouseX - 3);
 		if (tmpPos > s->length)
 			tmpPos = s->length;
 
@@ -2520,8 +2453,6 @@
 
 void samplerLoopToggle(void)
 {
-	moduleSample_t *s;
-
 	if (editor.sampleZero)
 	{
 		statusNotSampleZero();
@@ -2530,7 +2461,7 @@
 
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
 
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 	if (s->length < 2)
 		return;
 
@@ -2572,7 +2503,7 @@
 	ui.updateCurrSampleReplen = true;
 
 	displaySample();
-	mixerUpdateLoops();
+	updatePaulaLoops();
 	recalcChordLength();
 	updateWindowTitle(MOD_IS_MODIFIED);
 }
@@ -2622,7 +2553,7 @@
 	if (!ui.samplerScreenShown || ui.samplerVolBoxShown || ui.samplerFiltersBoxShown)
 		return;
 
-	for (int32_t ch = 0; ch < AMIGA_VOICES; ch++)
+	for (int32_t ch = 0; ch < PAULA_VOICES; ch++)
 	{
 		int32_t pos = getSampleReadPos(ch);
 		if (pos >= 0)
--- a/src/pt2_sampler.h
+++ b/src/pt2_sampler.h
@@ -18,6 +18,7 @@
 
 void sampleLine(int32_t line_x1, int32_t line_x2, int32_t line_y1, int32_t line_y2);
 
+void killSample(void);
 void downSample(void);
 void upSample(void);
 void createSampleMarkTable(void);
@@ -27,7 +28,6 @@
 void highPassSample(int32_t cutOff);
 void lowPassSample(int32_t cutOff);
 void samplerRemoveDcOffset(void);
-void mixChordSample(void);
 void samplerResample(void);
 void doMix(void);
 void boostSample(int32_t sample, bool ignoreMark);
--- a/src/pt2_sampling.c
+++ b/src/pt2_sampling.c
@@ -15,21 +15,17 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <stdbool.h>
-#include "pt2_header.h"
 #include "pt2_textout.h"
-#include "pt2_mouse.h"
-#include "pt2_structs.h"
-#include "pt2_sampler.h" // fixSampleBeep() / sampleLine()
+#include "pt2_sampler.h"
 #include "pt2_visuals.h"
 #include "pt2_helpers.h"
 #include "pt2_bmp.h"
-#include "pt2_unicode.h"
 #include "pt2_audio.h"
 #include "pt2_tables.h"
 #include "pt2_config.h"
 #include "pt2_sampling.h"
 #include "pt2_math.h" // PT2_PI
-#include "pt2_hpc.h"
+#include "pt2_replayer.h"
 
 enum
 {
@@ -542,7 +538,7 @@
 
 void writeSampleMonitorWaveform(void) // called every frame
 {
-	if (!ui.samplingBoxShown || ui.askScreenShown)
+	if (!ui.samplingBoxShown || ui.askBoxShown)
 		return;
 
 	if (samplingEnded)
--- a/src/pt2_scopes.c
+++ b/src/pt2_scopes.c
@@ -4,14 +4,10 @@
 #ifndef _WIN32
 #include <unistd.h> // usleep()
 #endif
-#include "pt2_header.h"
 #include "pt2_helpers.h"
 #include "pt2_visuals.h"
 #include "pt2_scopes.h"
-#include "pt2_tables.h"
-#include "pt2_structs.h"
 #include "pt2_config.h"
-#include "pt2_hpc.h"
 
 // this uses code that is not entirely thread safe, but I have never had any issues so far...
 
@@ -19,18 +15,8 @@
 static hpc_t scopeHpc;
 static SDL_Thread *scopeThread;
 
-scope_t scope[AMIGA_VOICES]; // global
+scope_t scope[PAULA_VOICES]; // global
 
-void resetCachedScopePeriod(void)
-{
-	scope_t *s = scope;
-	for (int32_t i = 0; i < AMIGA_VOICES; i++, s++)
-	{
-		s->oldPeriod = -1;
-		s->dOldScopeDelta = 0.0;
-	}
-}
-
 // this is quite hackish, but fixes sample swapping issues
 static int32_t getSampleSlotFromReadAddress(const int8_t *sampleReadAddress)
 {
@@ -97,18 +83,7 @@
 
 void scopeSetPeriod(int32_t ch, int32_t period)
 {
-	volatile scope_t *s = &scope[ch];
-
-	// if the new period was the same as the previous period, use cached delta
-	if (period != s->oldPeriod)
-	{
-		s->oldPeriod = period;
-
-		const double dPeriodToScopeDeltaDiv = PAULA_PAL_CLK / (double)SCOPE_HZ;
-		s->dOldScopeDelta = dPeriodToScopeDeltaDiv / period;
-	}
-
-	s->dDelta = s->dOldScopeDelta;
+	scope[ch].dDelta = (PAULA_PAL_CLK / (double)SCOPE_HZ) / period;
 }
 
 void scopeTrigger(int32_t ch)
@@ -143,13 +118,13 @@
 {
 	scope_t tempState;
 
-	if (editor.isWAVRendering)
+	if (editor.mod2WavOngoing)
 		return;
 
 	volatile scope_t *sc = scope;
 
 	scopesUpdatingFlag = true;
-	for (int32_t i = 0; i < AMIGA_VOICES; i++, sc++)
+	for (int32_t i = 0; i < PAULA_VOICES; i++, sc++)
 	{
 		tempState = *sc; // cache it
 		if (!tempState.active)
@@ -191,7 +166,7 @@
 	scope_t tmpScope, *sc;
 
 	// sink VU-meters first
-	for (int32_t i = 0; i < AMIGA_VOICES; i++)
+	for (int32_t i = 0; i < PAULA_VOICES; i++)
 	{
 		editor.realVuMeterVolumes[i] -= 4;
 		if (editor.realVuMeterVolumes[i] < 0)
@@ -200,7 +175,7 @@
 
 	// get peak sample data from running scope voices
 	sc = scope;
-	for (int32_t i = 0; i < AMIGA_VOICES; i++, sc++)
+	for (int32_t i = 0; i < PAULA_VOICES; i++, sc++)
 	{
 		tmpScope = *sc; // cache it
 
@@ -259,7 +234,7 @@
 	const uint32_t fgColor = video.palette[PAL_QADSCP];
 
 	scopesDisplayingFlag = true;
-	for (int32_t i = 0; i < AMIGA_VOICES; i++, sc++)
+	for (int32_t i = 0; i < PAULA_VOICES; i++, sc++)
 	{
 		scope_t tmpScope = *sc; // cache it
 
@@ -287,7 +262,8 @@
 
 				scopeDrawPtr[(scopeData * SCREEN_W) + x] = fgColor;
 
-				if (++pos >= length)
+				pos++;
+				if (pos >= length)
 				{
 					pos = 0;
 
@@ -339,8 +315,6 @@
 
 bool initScopes(void)
 {
-	resetCachedScopePeriod();
-
 	scopeThread = SDL_CreateThread(scopeThreadFunc, NULL, NULL);
 	if (scopeThread == NULL)
 	{
@@ -368,7 +342,7 @@
 	// wait for scopes to finish updating
 	while (scopesUpdatingFlag);
 
-	for (int32_t i = 0; i < AMIGA_VOICES; i++)
+	for (int32_t i = 0; i < PAULA_VOICES; i++)
 		scope[i].active = false;
 
 	// wait for scope displaying to be done (safety)
--- a/src/pt2_scopes.h
+++ b/src/pt2_scopes.h
@@ -12,17 +12,11 @@
 	uint8_t volume;
 	int32_t length, pos;
 
-	// cache
-	int32_t oldPeriod;
-	double dOldScopeDelta;
-
 	double dDelta, dPhase;
 	const int8_t *newData;
 	int32_t newLength;
 } scope_t;
 
-void resetCachedScopePeriod(void);
-
 void scopeSetPeriod(int32_t ch, int32_t period);
 void scopeTrigger(int32_t ch);
 
@@ -33,4 +27,4 @@
 void stopScope(int32_t ch);
 void stopAllScopes(void);
 
-extern scope_t scope[AMIGA_VOICES]; // pt2_scopes.c
+extern scope_t scope[PAULA_VOICES]; // pt2_scopes.c
--- a/src/pt2_structs.h
+++ b/src/pt2_structs.h
@@ -9,6 +9,7 @@
 #include <stdbool.h>
 #include "pt2_header.h"
 #include "pt2_hpc.h"
+#include "pt2_paula.h"
 
 // for .WAV sample loading/saving
 typedef struct wavHeader_t
@@ -67,7 +68,7 @@
 
 typedef struct moduleChannel_t
 {
-	int8_t *n_start, *n_wavestart, *n_loopstart, n_chanindex, n_volume;
+	int8_t *n_start, *n_wavestart, *n_loopstart, n_chanindex, n_volume, n_dmabit;
 	int8_t n_toneportdirec, n_pattpos, n_loopcount;
 	uint8_t n_wavecontrol, n_glissfunk, n_sampleoffset, n_toneportspeed;
 	uint8_t n_vibratocmd, n_tremolocmd, n_finetune, n_funkoffset, n_samplenum;
@@ -93,7 +94,7 @@
 
 	moduleHeader_t header;
 	moduleSample_t samples[MOD_SAMPLES];
-	moduleChannel_t channels[AMIGA_VOICES];
+	moduleChannel_t channels[PAULA_VOICES];
 	note_t *patterns[MAX_PATTERNS];
 
 	// for pattern viewer
@@ -133,7 +134,7 @@
 	float fMouseXMul, fMouseYMul;
 	hpc_t vblankHpc;
 	SDL_PixelFormat *pixelFormat;
-	uint32_t *frameBuffer, *frameBufferUnaligned;
+	uint32_t *frameBuffer;
 
 	SDL_Window *window;
 	SDL_Renderer *renderer;
@@ -148,9 +149,9 @@
 
 typedef struct editor_t
 {
-	volatile int8_t vuMeterVolumes[AMIGA_VOICES], spectrumVolumes[SPECTRUM_BAR_NUM];
-	volatile int8_t *sampleFromDisp, *sampleToDisp, *currSampleDisp, realVuMeterVolumes[AMIGA_VOICES];
-	volatile bool songPlaying, programRunning, isWAVRendering, isSMPRendering, smpRenderingDone;
+	volatile int8_t vuMeterVolumes[PAULA_VOICES], spectrumVolumes[SPECTRUM_BAR_NUM];
+	volatile int8_t *sampleFromDisp, *sampleToDisp, *currSampleDisp, realVuMeterVolumes[PAULA_VOICES], mod2WavNumLoops, mod2WavFadeOutSeconds;
+	volatile bool songPlaying, programRunning, mod2WavOngoing, pat2SmpOngoing, mainLoopOngoing, abortMod2Wav, mod2WavFadeOut;
 	volatile uint16_t *quantizeValueDisp, *metroSpeedDisp, *metroChannelDisp, *sampleVolDisp;
 	volatile uint16_t *vol1Disp, *vol2Disp, *currEditPatternDisp, *currPosDisp, *currPatternDisp;
 	volatile uint16_t *currPosEdPattDisp, *currLengthDisp, *lpCutOffDisp, *hpCutOffDisp;
@@ -162,10 +163,10 @@
 
 	bool errorMsgActive, errorMsgBlock, multiFlag, metroFlag, keypadToggle8CFlag, normalizeFiltersFlag;
 	bool sampleAllFlag, halfClipFlag, newOldFlag, pat2SmpHQ, mixFlag, useLEDFilter;
-	bool modLoaded, autoInsFlag, repeatKeyFlag, sampleZero, tuningFlag;
+	bool modLoaded, autoInsFlag, repeatKeyFlag, sampleZero, tuningToneFlag;
 	bool stepPlayEnabled, stepPlayBackwards, blockBufferFlag, blockMarkFlag, didQuantize;
-	bool swapChannelFlag, configFound, abortMod2Wav, chordLengthMin, rowVisitTable[MOD_ORDERS * MOD_ROWS];
-	bool muted[AMIGA_VOICES];
+	bool swapChannelFlag, configFound, chordLengthMin, rowVisitTable[MOD_ORDERS * MOD_ROWS];
+	bool muted[PAULA_VOICES];
 
 	int8_t smpRedoFinetunes[MOD_SAMPLES], smpRedoVolumes[MOD_SAMPLES], multiModeNext[4], trackPattFlag;
 	int8_t *smpRedoBuffer[MOD_SAMPLES], *tempSample, currSample, recordMode, sampleFrom, sampleTo, autoInsSlot;
@@ -178,11 +179,10 @@
 	uint16_t metroSpeed, metroChannel, sampleVol;
 	uint16_t effectMacros[10], currPlayNote, vol1, vol2, lpCutOff, hpCutOff;
 	int32_t smpRedoLoopStarts[MOD_SAMPLES], smpRedoLoopLengths[MOD_SAMPLES], smpRedoLengths[MOD_SAMPLES];
-	int32_t oldTempo, modulatePos, modulateOffset, markStartOfs, markEndOfs, pat2SmpPos, samplePos, chordLength;
+	int32_t oldTempo, modulatePos, modulateOffset, markStartOfs, markEndOfs, samplePos, chordLength;
 	uint64_t musicTime64;
-	double *dPat2SmpBuf;
 	note_t trackBuffer[MOD_ROWS], cmdsBuffer[MOD_ROWS], blockBuffer[MOD_ROWS];
-	note_t patternBuffer[MOD_ROWS * AMIGA_VOICES], undoBuffer[MOD_ROWS * AMIGA_VOICES];
+	note_t patternBuffer[MOD_ROWS * PAULA_VOICES], undoBuffer[MOD_ROWS * PAULA_VOICES];
 	SDL_Thread *mod2WavThread, *pat2SmpThread;
 } editor_t;
 
@@ -206,16 +206,16 @@
 	char statusMessage[18], prevStatusMessage[18];
 	char *dstPtr, *editPos, *textEndPtr, *showTextPtr;
 
-	bool answerNo, answerYes, throwExit, editTextFlag, askScreenShown, samplerScreenShown;
+	volatile bool askBoxShown, throwExit;
+
+	bool editTextFlag, samplerScreenShown;
 	bool leftLoopPinMoving, rightLoopPinMoving, changingSmpResample, changingDrumPadNote;
-	bool forceSampleDrag, forceSampleEdit, introScreenShown;
-	bool aboutScreenShown, clearScreenShown, posEdScreenShown, diskOpScreenShown;
+	bool forceSampleDrag, forceSampleEdit, introTextShown;
+	bool aboutScreenShown, posEdScreenShown, diskOpScreenShown;
 	bool samplerVolBoxShown, samplerFiltersBoxShown, samplingBoxShown, editOpScreenShown;
+	bool changingSamplingNote, force32BitNumPtr;
 
-	bool changingSamplingNote;
-
-	bool force32BitNumPtr;
-	int8_t *numPtr8, tmpDisp8, pointerMode, editOpScreen, editTextType, askScreenType;
+	int8_t *numPtr8, tmpDisp8, pointerMode, editOpScreen, editTextType;
 	int8_t visualizerMode, previousPointerMode, forceVolDrag, changingChordNote;
 	uint8_t numLen, numBits;
 
@@ -243,7 +243,7 @@
 	bool updateCurrSampleNum, updateCurrSampleVolume, updateCurrSampleLength;
 	bool updateCurrSampleRepeat, updateCurrSampleReplen, updateCurrSampleName;
 	bool updateSongSize, updateSongTiming, updateSongBPM;
-	bool updateCurrPattText, updateTrackerFlags, pat2SmpDialogShown;
+	bool updateCurrPattText, updateTrackerFlags;
 
 	// disk op.
 	bool updateLoadMode, updatePackText, updateSaveFormatText, updateDiskOpPathText;
@@ -251,13 +251,12 @@
 	// pos ed.
 	bool updatePosEd, updateDiskOpFileList;
 
-	// these are used when things are drawn on top, for example clear/ask dialogs
-	bool disablePosEd, disableVisualizer;
+	bool disableVisualizer; // ask boxes (f.ex. MOD2WAV)
 
 	int16_t lineCurX, lineCurY, editObject, sampleMarkingPos;
 	uint16_t *numPtr16, tmpDisp16, *dstOffset, dstPos, textLength, editTextPos;
 	uint16_t dstOffsetEnd, lastSampleOffset, diskOpPathTextOffset;
-	int32_t askTempData, *numPtr32, tmpDisp32;
+	int32_t *numPtr32, tmpDisp32;
 } ui_t;
 
 extern keyb_t keyb;
--- a/src/pt2_sync.c
+++ b/src/pt2_sync.c
@@ -1,9 +1,7 @@
 #include <stdint.h>
 #include <stdbool.h>
-#include "pt2_header.h"
 #include "pt2_sync.h"
 #include "pt2_scopes.h"
-#include "pt2_audio.h"
 #include "pt2_visuals.h"
 #include "pt2_tables.h"
 
@@ -109,7 +107,7 @@
 
 void updateChannelSyncBuffer(void)
 {
-	uint8_t updateFlags[AMIGA_VOICES];
+	uint8_t updateFlags[PAULA_VOICES];
 
 	chSyncEntry = NULL;
 
@@ -129,7 +127,7 @@
 		if (chSyncEntry == NULL)
 			break;
 
-		for (int32_t i = 0; i < AMIGA_VOICES; i++)
+		for (int32_t i = 0; i < PAULA_VOICES; i++)
 			updateFlags[i] |= chSyncEntry->channels[i].flags; // yes, OR the status
 
 		if (!chQueuePop())
@@ -147,7 +145,7 @@
 	{
 		scope_t *s = scope;
 		syncedChannel_t *c = chSyncEntry->channels;
-		for (int32_t ch = 0; ch < AMIGA_VOICES; ch++, s++, c++)
+		for (int32_t ch = 0; ch < PAULA_VOICES; ch++, s++, c++)
 		{
 			const uint8_t flags = updateFlags[ch];
 			if (flags == 0)
@@ -159,13 +157,6 @@
 			if (flags & SET_SCOPE_PERIOD)
 				scopeSetPeriod(ch, c->period);
 
-			if (flags & TRIGGER_SCOPE)
-			{
-				s->newData = c->triggerData;
-				s->newLength = c->triggerLength;
-				scopeTrigger(ch);
-			}
-
 			if (flags & SET_SCOPE_DATA)
 				scope[ch].newData = c->newData;
 
@@ -172,8 +163,15 @@
 			if (flags & SET_SCOPE_LENGTH)
 				scope[ch].newLength = c->newLength;
 
-			if (flags & STOP_SCOPE)
+			if (flags & STOP_SCOPE) // this must be handled *before* TRIGGER_SCOPE
 				scope[ch].active = false;
+
+			if (flags & TRIGGER_SCOPE)
+			{
+				s->newData = c->triggerData;
+				s->newLength = c->triggerLength;
+				scopeTrigger(ch);
+			}
 
 			if (flags & UPDATE_ANALYZER)
 				updateSpectrumAnalyzer(c->analyzerVolume, c ->analyzerPeriod);
--- a/src/pt2_sync.h
+++ b/src/pt2_sync.h
@@ -2,7 +2,7 @@
 
 #include <stdint.h>
 #include <stdbool.h>
-#include "pt2_header.h" // AMIGA_VOICES
+#include "pt2_paula.h"
 
 enum // flags
 {
@@ -32,7 +32,7 @@
 
 typedef struct chSyncData_t
 {
-	syncedChannel_t channels[AMIGA_VOICES];
+	syncedChannel_t channels[PAULA_VOICES];
 	uint64_t timestamp;
 } chSyncData_t;
 
--- a/src/pt2_tables.c
+++ b/src/pt2_tables.c
@@ -1,5 +1,4 @@
 #include <stdint.h>
-#include <stdbool.h>
 #include "pt2_mouse.h"
 
 const char *ftuneStrTab[16] =
@@ -180,10 +179,18 @@
 };
 
 /*
-** const double dBpmMs1024 = 1024.0 / (bpm / 2.5); // milliseconds (scaled from 1000 to 1024)
-** x = (uint64_t)floor((UINT32_MAX + 1.0) * dBpmMs1024);
+** Formula:
+** for (int32_t i = 32; i <= 255; i++)
+** {
+**     double dBpmMs1024 = 1024.0 / (i / 2.5); // binary ms (1000->1024)
+**     musicTimeTab64[i-32] = (uint64_t)floor((UINT32_MAX + 1.0) * dBpmMs1024);
+** }
+**
+** // vblank mode (~49.92Hz)
+** double dBpmMs1024 = 1024.0 / 49.920409283472; // binary ms (1000->1024)
+** musicTimeTab64[256] =  (uint64_t)floor((UINT32_MAX + 1.0) * dBpmMs1024);
 */
-const uint64_t musicTimeTab64[256-32] =
+const uint64_t musicTimeTab64[(256-32) + 1] =
 {
 	0x5000000000,0x4D9364D936,0x4B4B4B4B4B,0x4924924924,0x471C71C71C,0x45306EB3E4,
 	0x435E50D794,0x41A41A41A4,0x4000000000,0x3E7063E706,0x3CF3CF3CF3,0x3B88EE23B8,
@@ -222,33 +229,13 @@
 	0x0AD8F2FBA9,0x0ACD3B68C6,0x0AC19D0AC1,0x0AB617909A,0x0AAAAAAAAA,0x0A9F560A9F,
 	0x0A94196370,0x0A88F46959,0x0A7DE6D1D6,0x0A72F05397,0x0A6810A681,0x0A5D4783A0,
 	0x0A5294A529,0x0A47F7C66C,0x0A3D70A3D7,0x0A32FEFAE6,0x0A28A28A28,0x0A1E5B1133,
-	0x0A142850A1,0x0A0A0A0A0A
+	0x0A142850A1,0x0A0A0A0A0A,
+
+	0x14833D2EF0 // ~49.92Hz (vblank tempo mode)
 };
 
 // button tables taken from the ptplay project + modified
 
-const guiButton_t bAsk[] =
-{
-	{171, 71,196, 81, PTB_SUREY},
-	{234, 71,252, 81, PTB_SUREN}
-};
-
-const guiButton_t bPat2SmpAsk[] =
-{
-	{168, 71,185, 81, PTB_PAT2SMP_HI},
-	{192, 71,210, 81, PTB_PAT2SMP_LO},
-	{217, 71,256, 81, PTB_PAT2SMP_ABORT}
-};
-
-const guiButton_t bClear[] =
-{
-	{166, 57,198, 67, PTB_CLEARSONG},
-	{204, 57,257, 67, PTB_CLEARSAMPLES},
-
-	{166, 73,198, 83, PTB_CLEARALL},
-	{204, 73,257, 83, PTB_CLEARCANCEL}
-};
-
 const guiButton_t bTopScreen[] =
 {
 	{  0,  0, 39, 10, PTB_POSED},
@@ -351,21 +338,21 @@
 
 const guiButton_t bPosEd[] =
 {
-	{ 120,  0,171, 10, PTB_POSINS},
-	{ 172,  0,267, 21, PTB_STOP},
-	{ 268,  0,319, 10, PTB_PLAY},
+	{120,  0,171, 10, PTB_POSINS},
+	{172,  0,267, 21, PTB_STOP},
+	{268,  0,319, 10, PTB_PLAY},
 
-	{ 120, 11,171, 21, PTB_POSDEL},
-	{ 178, 22,307, 98, PTB_DUMMY},
-	{ 268, 11,319, 21, PTB_PATTERN},
+	{120, 11,171, 21, PTB_POSDEL},
+	{178, 22,307, 98, PTB_DUMMY},
+	{268, 11,319, 21, PTB_PATTERN},
 
-	{ 120, 22,177, 98, PTB_PE_PATT},
-	{ 308, 22,319, 32, PTB_PE_SCROLLTOP},
+	{120, 22,177, 98, PTB_PE_PATT},
+	{308, 22,319, 32, PTB_PE_SCROLLTOP},
 
-	{ 308, 33,319, 43, PTB_PE_SCROLLUP},
-	{ 308, 44,319, 76, PTB_PE_EXIT},
-	{ 308, 77,319, 87, PTB_PE_SCROLLDOWN},
-	{ 308, 88,319, 98, PTB_PE_SCROLLBOT}
+	{308, 33,319, 43, PTB_PE_SCROLLUP},
+	{308, 44,319, 76, PTB_PE_EXIT},
+	{308, 77,319, 87, PTB_PE_SCROLLDOWN},
+	{308, 88,319, 98, PTB_PE_SCROLLBOT}
 };
 
 const guiButton_t bEditOp1[] =
--- a/src/pt2_tables.h
+++ b/src/pt2_tables.h
@@ -16,18 +16,13 @@
 extern const uint8_t vibratoTable[32];
 extern const int16_t periodTable[(37*16)+15];
 extern int8_t pNoteTable[32];
-extern const uint64_t musicTimeTab64[256-32];
+extern const uint64_t musicTimeTab64[(256-32)+1];
 
 // changable by config file
 extern uint16_t analyzerColors[36];
 extern uint16_t vuMeterColors[48];
 
-// button tables taken from the ptplay project + modified
-
 // MODIFY THESE EVERY TIME YOU REMOVE/ADD A BUTTON!
-#define ASK_BUTTONS 2
-#define PAT2SMP_ASK_BUTTONS 3
-#define CLEAR_BUTTONS 4
 #define TOPSCREEN_BUTTONS 47
 #define MIDSCREEN_BUTTONS 3
 #define BOTSCREEN_BUTTONS 4
@@ -40,9 +35,6 @@
 #define SAMPLER_BUTTONS 25
 // -----------------------------------------------
 
-extern const guiButton_t bAsk[];
-extern const guiButton_t bPat2SmpAsk[];
-extern const guiButton_t bClear[];
 extern const guiButton_t bTopScreen[];
 extern const guiButton_t bMidScreen[];
 extern const guiButton_t bBotScreen[];
--- a/src/pt2_textout.c
+++ b/src/pt2_textout.c
@@ -1,18 +1,12 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <string.h>
-#include "pt2_header.h"
-#include "pt2_helpers.h"
 #include "pt2_tables.h"
-#include "pt2_visuals.h"
 #include "pt2_structs.h"
 #include "pt2_bmp.h"
 
 void charOut(uint32_t xPos, uint32_t yPos, char ch, uint32_t color)
 {
-	const uint8_t *srcPtr;
-	uint32_t *dstPtr;
-
 	if (ch == '\0' || ch == ' ')
 		return;
 
@@ -20,8 +14,8 @@
 	if (ch == 5 || ch == 6) // arrow up/down has 1 more scanline
 		h++;
 	
-	srcPtr = &fontBMP[(ch & 0x7F) << 3];
-	dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
+	const uint8_t *srcPtr = &fontBMP[(ch & 0x7F) << 3];
+	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
 
 	for (int32_t y = 0; y < h; y++)
 	{
@@ -38,9 +32,6 @@
 
 void charOut2(uint32_t xPos, uint32_t yPos, char ch) // for static GUI text
 {
-	const uint8_t *srcPtr;
-	uint32_t *dstPtr;
-
 	if (ch == '\0' || ch == ' ')
 		return;
 
@@ -48,8 +39,8 @@
 	if (ch == 5 || ch == 6) // arrow up/down has 1 more scanline
 		h++;
 	
-	srcPtr = &fontBMP[(ch & 0x7F) << 3];
-	dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
+	const uint8_t *srcPtr = &fontBMP[(ch & 0x7F) << 3];
+	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
 
 	const uint32_t fgColor = video.palette[PAL_BORDER];
 	const uint32_t bgColor = video.palette[PAL_GENBKG2];
@@ -72,8 +63,7 @@
 
 void charOutBg(uint32_t xPos, uint32_t yPos, char ch, uint32_t fgColor, uint32_t bgColor)
 {
-	const uint8_t *srcPtr;
-	uint32_t *dstPtr, colors[2];
+	uint32_t colors[2];
 
 	if (ch == '\0')
 		return;
@@ -82,8 +72,8 @@
 	if (ch == 5 || ch == 6) // arrow up/down has 1 more scanline
 		h++;
 
-	srcPtr = &fontBMP[(ch & 0x7F) << 3];
-	dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
+	const uint8_t *srcPtr = &fontBMP[(ch & 0x7F) << 3];
+	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
 
 	colors[0] = bgColor;
 	colors[1] = fgColor;
@@ -100,9 +90,6 @@
 
 void charOutBig(uint32_t xPos, uint32_t yPos, char ch, uint32_t color)
 {
-	const uint8_t *srcPtr;
-	uint32_t *dstPtr1, *dstPtr2;
-
 	if (ch == '\0' || ch == ' ')
 		return;
 
@@ -110,9 +97,9 @@
 	if (ch == 5 || ch == 6) // arrow up/down has 1 more scanline
 		h++;
 
-	srcPtr = &fontBMP[(ch & 0x7F) << 3];
-	dstPtr1 = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
-	dstPtr2 = dstPtr1 + SCREEN_W;
+	const uint8_t *srcPtr = &fontBMP[(ch & 0x7F) << 3];
+	uint32_t *dstPtr1 = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
+	uint32_t *dstPtr2 = dstPtr1 + SCREEN_W;
 
 	for (int32_t y = 0; y < h; y++)
 	{
@@ -133,15 +120,14 @@
 
 void charOutBigBg(uint32_t xPos, uint32_t yPos, char ch, uint32_t fgColor, uint32_t bgColor)
 {
-	const uint8_t *srcPtr;
-	uint32_t *dstPtr1, *dstPtr2, colors[2];
+	uint32_t colors[2];
 
 	if (ch == '\0')
 		return;
 
-	srcPtr = &fontBMP[(ch & 0x7F) << 3];
-	dstPtr1 = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
-	dstPtr2 = dstPtr1 + SCREEN_W;
+	const uint8_t *srcPtr = &fontBMP[(ch & 0x7F) << 3];
+	uint32_t *dstPtr1 = &video.frameBuffer[(yPos * SCREEN_W) + xPos];
+	uint32_t *dstPtr2 = dstPtr1 + SCREEN_W;
 
 	colors[0] = bgColor;
 	colors[1] = fgColor;
@@ -351,7 +337,6 @@
 void printSixDecimals(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor)
 {
 	char numberText[7];
-	uint8_t i;
 
 	if (value == 0)
 	{
@@ -370,7 +355,7 @@
 		numberText[1] = '0' + (value % 10); value /= 10;
 		numberText[0] = '0' + (value % 10);
 
-		i = 0;
+		int32_t i = 0;
 		while (numberText[i] == '0')
 			numberText[i++] = ' ';
 
@@ -461,7 +446,7 @@
 	{
 		value &= 0xFFFFF;
 
-		charOut(x + (FONT_CHAR_W * 0), y, hexTable[value  >> 16], fontColor);
+		charOut(x + (FONT_CHAR_W * 0), y, hexTable[value >> 16], fontColor);
 		charOut(x + (FONT_CHAR_W * 1), y, hexTable[(value & (15 << 12)) >> 12], fontColor);
 		charOut(x + (FONT_CHAR_W * 2), y, hexTable[(value & (15 << 8)) >> 8], fontColor);
 		charOut(x + (FONT_CHAR_W * 3), y, hexTable[(value & (15 << 4)) >> 4], fontColor);
@@ -540,7 +525,6 @@
 void printFiveDecimalsBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor)
 {
 	char numberText[6];
-	uint8_t i;
 
 	if (value == 0)
 	{
@@ -558,7 +542,7 @@
 		numberText[1] = '0' + (value % 10); value /= 10;
 		numberText[0] = '0' + (value % 10);
 
-		i = 0;
+		int32_t i = 0;
 		while (numberText[i] == '0')
 			numberText[i++] = ' ';
 
@@ -570,7 +554,6 @@
 void printSixDecimalsBg(uint32_t x, uint32_t y, uint32_t value, uint32_t fontColor, uint32_t backColor)
 {
 	char numberText[7];
-	uint8_t i;
 
 	if (value == 0)
 	{
@@ -589,7 +572,7 @@
 		numberText[1] = '0' + (value % 10); value /= 10;
 		numberText[0] = '0' + (value % 10);
 
-		i = 0;
+		int32_t i = 0;
 		while (numberText[i] == '0')
 			numberText[i++] = ' ';
 
--- a/src/pt2_unicode.c
+++ b/src/pt2_unicode.c
@@ -4,16 +4,13 @@
 // this is probably broken, but it "works" for now
 uint32_t unicharToAnsi(char *dstBuffer, const UNICHAR *inputString, uint32_t maxDstLen)
 {
-	uint32_t i;
-	UNICHAR ch;
-
 	if (inputString == NULL || dstBuffer == NULL)
 		return 0;
 
-	i = 0;
+	uint32_t i = 0;
 	while (i < maxDstLen && inputString[i] != '\0')
 	{
-		ch = inputString[i];
+		UNICHAR ch = inputString[i];
 #ifdef _WIN32
 		if (ch >= 256)
 #else
--- a/src/pt2_visuals.c
+++ b/src/pt2_visuals.c
@@ -19,17 +19,9 @@
 #include <unistd.h> // usleep()
 #endif
 #include <ctype.h> // tolower()
-#include "pt2_header.h"
-#include "pt2_keyboard.h"
-#include "pt2_mouse.h"
-#include "pt2_audio.h"
 #include "pt2_helpers.h"
 #include "pt2_textout.h"
 #include "pt2_tables.h"
-#include "pt2_module_loader.h"
-#include "pt2_module_saver.h"
-#include "pt2_sample_loader.h"
-#include "pt2_sample_saver.h"
 #include "pt2_pattern_viewer.h"
 #include "pt2_sampler.h"
 #include "pt2_diskop.h"
@@ -36,13 +28,11 @@
 #include "pt2_visuals.h"
 #include "pt2_scopes.h"
 #include "pt2_edit.h"
-#include "pt2_pat2smp.h"
-#include "pt2_mod2wav.h"
 #include "pt2_config.h"
 #include "pt2_bmp.h"
 #include "pt2_sampling.h"
 #include "pt2_chordmaker.h"
-#include "pt2_hpc.h"
+#include "pt2_mod2wav.h"
 
 typedef struct sprite_t
 {
@@ -53,6 +43,7 @@
 	const void *data;
 } sprite_t;
 
+static int32_t oldCurrMode = -1;
 static uint32_t vuMetersBg[4 * (10 * 48)];
 
 sprite_t sprites[SPRITE_NUM]; // globalized
@@ -69,7 +60,6 @@
 void updateSongInfo2(void);
 void updateSampler(void);
 void updatePatternData(void);
-void updateMOD2WAVDialog(void);
 
 void blit32(int32_t x, int32_t y, int32_t w, int32_t h, const uint32_t *src)
 {
@@ -130,9 +120,23 @@
 	putPixel(x, y+h-1, video.palette[PAL_GENBKG]);
 	putPixel(x+w-1, y, video.palette[PAL_GENBKG]);
 
-	fillRect(x+1, y+1, w-2, h-2, video.palette[PAL_BACKGRD]);
+	fillRect(x+1, y+1, w-2, h-2, video.palette[PAL_GENBKG]);
 }
 
+void drawFramework3(int32_t x, int32_t y, int32_t w, int32_t h)
+{
+	fillRect(x, y, w, h, video.palette[PAL_GENBKG]);
+
+	vLine(x,     y,     h-1, video.palette[PAL_BORDER]);
+	vLine(x+1,   y,     h-2, video.palette[PAL_BORDER]);
+	hLine(x+2,   y,     w-3, video.palette[PAL_BORDER]);
+	hLine(x+2,   y+1,   w-4, video.palette[PAL_BORDER]);
+	hLine(x+1,   y+h-1, w-1, video.palette[PAL_GENBKG2]);
+	hLine(x+2,   y+h-2, w-2, video.palette[PAL_GENBKG2]);
+	vLine(x+w-2, y+2,   h-4, video.palette[PAL_GENBKG2]);
+	vLine(x+w-1, y+1,   h-3, video.palette[PAL_GENBKG2]);
+}
+
 void fillRect(int32_t x, int32_t y, int32_t w, int32_t h, const uint32_t pixelColor)
 {
 	uint32_t *dstPtr = &video.frameBuffer[(y * SCREEN_W) + x];
@@ -146,18 +150,44 @@
 	}
 }
 
-void drawButton(int32_t x, int32_t y, int32_t w, const char *text)
+void drawButton1(int32_t x, int32_t y, int32_t w, int32_t h, const char *text)
 {
-	if (w < 2)
-		return;
+	const int32_t textW = (int32_t)strlen(text) * (FONT_CHAR_W - 1);
 
-	const int32_t textW = (int32_t)strlen(text) * (FONT_CHAR_W-1);
-	const int32_t textX = x + (((w - 2) - textW) >> 1);
+	drawFramework1(x, y, w, h);
 
-	drawFramework1(x, y, w, 11);
-	textOut2(textX, y+3, text);
+	int32_t textX = x + ((w - textW) / 2);
+	int32_t textY = y + ((h - FONT_CHAR_H) / 2);
+
+	// kludge
+	if (!strcmp(text, ARROW_UP_STR) || !strcmp(text, ARROW_DOWN_STR))
+	{
+		textX--;
+		textY--;
+	}
+
+	textOut2(textX, textY, text);
 }
 
+void drawButton2(int32_t x, int32_t y, int32_t w, int32_t h, const char *text)
+{
+	const int32_t textW = (int32_t)strlen(text) * (FONT_CHAR_W - 1);
+
+	drawFramework2(x, y, w, h);
+
+	int32_t textX = x + ((w - textW) / 2);
+	int32_t textY = y + ((h - FONT_CHAR_H) / 2);
+
+	// kludge
+	if (!strcmp(text, ARROW_UP_STR) || !strcmp(text, ARROW_DOWN_STR))
+	{
+		textX--;
+		textY--;
+	}
+
+	textOut2(textX, textY, text);
+}
+
 void drawUpButton(int32_t x, int32_t y)
 {
 	drawFramework1(x, y, 11, 11);
@@ -200,21 +230,35 @@
 	displayErrorMsg("NOT SAMPLE 0 !");
 }
 
-void renderFrame(void)
+void renderFrame2(void) // use this in askBox()
 {
-	updateMOD2WAVDialog(); // must be first to avoid flickering issues
+	updateMod2WavDialog(); // must be first to avoid flickering issues
 
 	updateSongInfo1(); // top left side of screen, when "disk op"/"pos ed" is hidden
 	updateSongInfo2(); // two middle rows of screen, always visible
-	updateEditOp();
 	updatePatternData();
-	updateDiskOp();
 	updateSampler();
+	handleLastGUIObjectDown(); // XXX
+	drawSamplerLine();
+	writeSampleMonitorWaveform(); // XXX
+}
+
+void renderFrame(void)
+{
+	renderFrame2();
+
+	updateEditOp();
+	updateDiskOp();
 	updatePosEd();
 	updateVisualizer();
-	handleLastGUIObjectDown();
-	drawSamplerLine();
-	writeSampleMonitorWaveform();
+
+	// show [EDITING] in window title if in edit mode
+	if (oldCurrMode != editor.currMode)
+	{
+		oldCurrMode = editor.currMode;
+		if (song != NULL)
+			updateWindowTitle(song->modified);
+	}
 }
 
 void resetAllScreens(void) // prepare GUI for "really quit?" dialog
@@ -221,7 +265,6 @@
 {
 	editor.mixFlag = false;
 	editor.swapChannelFlag = false;
-	ui.clearScreenShown = false;
 
 	ui.changingChordNote = false;
 	ui.changingSmpResample = false;
@@ -228,8 +271,6 @@
 	ui.changingSamplingNote = false;
 	ui.changingDrumPadNote = false;
 
-	ui.pat2SmpDialogShown = false;
-	ui.disablePosEd = false;
 	ui.disableVisualizer = false;
 	
 	if (ui.samplerScreenShown)
@@ -249,58 +290,15 @@
 		exitGetTextLine(EDIT_TEXT_NO_UPDATE);
 }
 
-void removeAskDialog(void)
-{
-	if (!ui.askScreenShown && !editor.isWAVRendering)
-		displayMainScreen();
-
-	ui.disablePosEd = false;
-	ui.disableVisualizer = false;
-}
-
-void renderAskDialog(void)
-{
-	ui.disablePosEd = true;
-	ui.disableVisualizer = true;
-
-	const uint32_t *srcPtr = ui.pat2SmpDialogShown ? pat2SmpDialogBMP : yesNoDialogBMP;
-	blit32(160, 51, 104, 39, srcPtr);
-}
-
-void renderBigAskDialog(void)
-{
-	ui.disablePosEd = true;
-	ui.disableVisualizer = true;
-
-	blit32(120, 44, 200, 55, bigYesNoDialogBMP);
-}
-
-void showDownsampleAskDialog(void)
-{
-	ui.askScreenShown = true;
-	ui.askScreenType = ASK_LOAD_DOWNSAMPLE;
-	pointerSetMode(POINTER_MODE_MSG1, NO_CARRY);
-	setStatusMessage("PLEASE SELECT", NO_CARRY);
-	renderBigAskDialog();
-
-	textOutTight(133, 49, "THE SAMPLE'S FREQUENCY IS", video.palette[PAL_BACKGRD]);
-	textOutTight(154, 57, "HIGH (ABOVE 22KHZ).", video.palette[PAL_BACKGRD]);
-	textOutTight(133, 65, "DO YOU WANT TO DOWNSAMPLE", video.palette[PAL_BACKGRD]);
-	textOutTight(156, 73, "BEFORE LOADING IT?", video.palette[PAL_BACKGRD]);
-}
-
 static void fillFromVuMetersBgBuffer(void)
 {
-	const uint32_t *srcPtr;
-	uint32_t *dstPtr;
-
-	if (ui.samplerScreenShown || editor.isWAVRendering || editor.isSMPRendering)
+	if (ui.samplerScreenShown || editor.mod2WavOngoing || editor.pat2SmpOngoing)
 		return;
 
-	srcPtr = vuMetersBg;
-	dstPtr = &video.frameBuffer[(187 * SCREEN_W) + 55];
+	const uint32_t *srcPtr = vuMetersBg;
+	uint32_t *dstPtr = &video.frameBuffer[(187 * SCREEN_W) + 55];
 
-	for (uint32_t i = 0; i < AMIGA_VOICES; i++)
+	for (uint32_t i = 0; i < PAULA_VOICES; i++)
 	{
 		for (uint32_t y = 0; y < 48; y++)
 		{
@@ -317,16 +315,13 @@
 
 void fillToVuMetersBgBuffer(void)
 {
-	const uint32_t *srcPtr;
-	uint32_t *dstPtr;
-
-	if (ui.samplerScreenShown || editor.isWAVRendering || editor.isSMPRendering)
+	if (ui.samplerScreenShown || editor.mod2WavOngoing || editor.pat2SmpOngoing)
 		return;
 
-	srcPtr = &video.frameBuffer[(187 * SCREEN_W) + 55];
-	dstPtr = vuMetersBg;
+	const uint32_t *srcPtr = &video.frameBuffer[(187 * SCREEN_W) + 55];
+	uint32_t *dstPtr = vuMetersBg;
 
-	for (uint32_t i = 0; i < AMIGA_VOICES; i++)
+	for (uint32_t i = 0; i < PAULA_VOICES; i++)
 	{
 		for (uint32_t y = 0; y < 48; y++)
 		{
@@ -343,17 +338,15 @@
 
 void renderVuMeters(void)
 {
-	const uint32_t *srcPtr;
-	uint32_t h, *dstPtr;
-
-	if (ui.samplerScreenShown || editor.isWAVRendering || editor.isSMPRendering)
+	if (ui.samplerScreenShown || editor.mod2WavOngoing || editor.pat2SmpOngoing)
 		return;
 
 	fillToVuMetersBgBuffer();
 	
-	dstPtr = &video.frameBuffer[(187 * SCREEN_W) + 55];
-	for (uint32_t i = 0; i < AMIGA_VOICES; i++)
+	uint32_t *dstPtr = &video.frameBuffer[(187 * SCREEN_W) + 55];
+	for (uint32_t i = 0; i < PAULA_VOICES; i++)
 	{
+		uint32_t h;
 		if (config.realVuMeters)
 			h = editor.realVuMeterVolumes[i];
 		else
@@ -362,7 +355,7 @@
 		if (h > 48)
 			h = 48;
 
-		srcPtr = vuMeterBMP;
+		const uint32_t *srcPtr = vuMeterBMP;
 		for (uint32_t y = 0; y < h; y++)
 		{
 			for (uint32_t x = 0; x < 10; x++)
@@ -378,12 +371,10 @@
 
 void updateSongInfo1(void) // left side of screen, when Disk Op. is hidden
 {
-	moduleSample_t *currSample;
-
 	if (ui.diskOpScreenShown)
 		return;
 
-	currSample = &song->samples[editor.currSample];
+	moduleSample_t *currSample = &song->samples[editor.currSample];
 
 	if (ui.updateSongPos)
 	{
@@ -400,7 +391,7 @@
 	if (ui.updateSongLength)
 	{
 		ui.updateSongLength = false;
-		if (!editor.isWAVRendering)
+		if (!editor.mod2WavOngoing)
 			printThreeDecimalsBg(72, 25, *editor.currLengthDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 	}
 
@@ -408,7 +399,7 @@
 	{
 		ui.updateCurrSampleFineTune = false;
 
-		if (!editor.isWAVRendering)
+		if (!editor.mod2WavOngoing)
 			textOutBg(80, 36, ftuneStrTab[currSample->fineTune & 0xF], video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 	}
 
@@ -415,7 +406,7 @@
 	if (ui.updateCurrSampleNum)
 	{
 		ui.updateCurrSampleNum = false;
-		if (!editor.isWAVRendering)
+		if (!editor.mod2WavOngoing)
 		{
 			printTwoHexBg(80, 47,
 				editor.sampleZero ? 0 : ((*editor.currSampleDisp) + 1), video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
@@ -425,7 +416,7 @@
 	if (ui.updateCurrSampleVolume)
 	{
 		ui.updateCurrSampleVolume = false;
-		if (!editor.isWAVRendering)
+		if (!editor.mod2WavOngoing)
 			printTwoHexBg(80, 58, *currSample->volumeDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 	}
 
@@ -432,7 +423,7 @@
 	if (ui.updateCurrSampleLength)
 	{
 		ui.updateCurrSampleLength = false;
-		if (!editor.isWAVRendering)
+		if (!editor.mod2WavOngoing)
 		{
 			if (config.maxSampleLength == 0xFFFE)
 				printFourHexBg(64, 69, *currSample->lengthDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
@@ -462,10 +453,6 @@
 
 void updateSongInfo2(void) // two middle rows of screen, always present
 {
-	char tempChar;
-	int32_t x, i;
-	moduleSample_t *currSample;
-
 	if (ui.updateStatusText)
 	{
 		ui.updateStatusText = false;
@@ -474,8 +461,7 @@
 		fillRect(88, 127, 17*FONT_CHAR_W, FONT_CHAR_H, video.palette[PAL_GENBKG]);
 
 		// render status text
-		if (!editor.errorMsgActive && editor.blockMarkFlag && !ui.askScreenShown
-			&& !ui.clearScreenShown && !editor.swapChannelFlag)
+		if (!editor.errorMsgActive && editor.blockMarkFlag && !ui.askBoxShown && !editor.swapChannelFlag)
 		{
 			textOut(88, 127, "MARK BLOCK", video.palette[PAL_GENTXT]);
 			charOut(192, 127, '-', video.palette[PAL_GENTXT]);
@@ -579,9 +565,9 @@
 	if (ui.updateSongName)
 	{
 		ui.updateSongName = false;
-		for (x = 0; x < 20; x++)
+		for (int32_t x = 0; x < 20; x++)
 		{
-			tempChar = song->header.name[x];
+			char tempChar = song->header.name[x];
 			if (tempChar == '\0')
 				tempChar = '_';
 
@@ -592,11 +578,11 @@
 	if (ui.updateCurrSampleName)
 	{
 		ui.updateCurrSampleName = false;
-		currSample = &song->samples[editor.currSample];
+		moduleSample_t *currSample = &song->samples[editor.currSample];
 
-		for (x = 0; x < 22; x++)
+		for (int32_t x = 0; x < 22; x++)
 		{
-			tempChar = currSample->text[x];
+			char tempChar = currSample->text[x];
 			if (tempChar == '\0')
 				tempChar = '_';
 
@@ -614,11 +600,11 @@
 		// calculate module length
 
 		uint32_t totalSampleDataSize = 0;
-		for (i = 0; i < MOD_SAMPLES; i++)
+		for (int32_t i = 0; i < MOD_SAMPLES; i++)
 			totalSampleDataSize += song->samples[i].length;
 
 		uint32_t totalPatterns = 0;
-		for (i = 0; i < MOD_ORDERS; i++)
+		for (int32_t i = 0; i < MOD_ORDERS; i++)
 		{
 			if (song->header.order[i] > totalPatterns)
 				totalPatterns = song->header.order[i];
@@ -651,14 +637,11 @@
 
 void updateSampler(void)
 {
-	int32_t tmpSampleOffset;
-	moduleSample_t *s;
-
 	if (!ui.samplerScreenShown || ui.samplingBoxShown)
 		return;
 
 	assert(editor.currSample >= 0 && editor.currSample <= 30);
-	s = &song->samples[editor.currSample];
+	moduleSample_t *s = &song->samples[editor.currSample];
 
 	// update 9xx offset
 	if (mouse.y >= 138 && mouse.y <= 201 && mouse.x >= 3 && mouse.x <= 316)
@@ -665,7 +648,7 @@
 	{
 		if (!ui.samplerVolBoxShown && !ui.samplerFiltersBoxShown && s->length > 0)
 		{
-			tmpSampleOffset = 0x900 + (scr2SmpPos(mouse.x-3) >> 8);
+			int32_t tmpSampleOffset = 0x900 + (scr2SmpPos(mouse.x-3) >> 8);
 			if (tmpSampleOffset != ui.lastSampleOffset)
 			{
 				ui.lastSampleOffset = (uint16_t)tmpSampleOffset;
@@ -744,14 +727,12 @@
 
 void showVolFromSlider(void)
 {
-	uint32_t *dstPtr, pixel, bgPixel, sliderStart, sliderEnd;
+	uint32_t sliderStart = ((editor.vol1 * 3) + 5) / 10;
+	uint32_t sliderEnd  = sliderStart + 4;
+	uint32_t pixel = video.palette[PAL_QADSCP];
+	uint32_t bgPixel = video.palette[PAL_BACKGRD];
+	uint32_t *dstPtr = &video.frameBuffer[(158 * SCREEN_W) + 105];
 
-	sliderStart = ((editor.vol1 * 3) + 5) / 10;
-	sliderEnd  = sliderStart + 4;
-	pixel = video.palette[PAL_QADSCP];
-	bgPixel = video.palette[PAL_BACKGRD];
-	dstPtr = &video.frameBuffer[(158 * SCREEN_W) + 105];
-
 	for (uint32_t y = 0; y < 3; y++)
 	{
 		for (uint32_t x = 0; x < 65; x++)
@@ -768,14 +749,12 @@
 
 void showVolToSlider(void)
 {
-	uint32_t *dstPtr, pixel, bgPixel, sliderStart, sliderEnd;
+	uint32_t sliderStart = ((editor.vol2 * 3) + 5) / 10;
+	uint32_t sliderEnd = sliderStart + 4;
+	uint32_t pixel = video.palette[PAL_QADSCP];
+	uint32_t bgPixel = video.palette[PAL_BACKGRD];
+	uint32_t *dstPtr = &video.frameBuffer[(169 * SCREEN_W) + 105];
 
-	sliderStart = ((editor.vol2 * 3) + 5) / 10;
-	sliderEnd = sliderStart + 4;
-	pixel = video.palette[PAL_QADSCP];
-	bgPixel = video.palette[PAL_BACKGRD];
-	dstPtr = &video.frameBuffer[(169 * SCREEN_W) + 105];
-
 	for (uint32_t y = 0; y < 3; y++)
 	{
 		for (uint32_t x = 0; x < 65; x++)
@@ -832,53 +811,50 @@
 
 void updatePosEd(void)
 {
-	if (!ui.posEdScreenShown || !ui.updatePosEd)
+	if (!ui.posEdScreenShown || ui.askBoxShown || !ui.updatePosEd)
 		return;
 
 	ui.updatePosEd = false;
 
-	if (!ui.disablePosEd)
-	{
-		int32_t posEdPosition = song->currOrder;
-		if (posEdPosition > song->header.numOrders-1)
-			posEdPosition = song->header.numOrders-1;
+	int32_t posEdPosition = song->currOrder;
+	if (posEdPosition > song->header.numOrders-1)
+		posEdPosition = song->header.numOrders-1;
 
-		// top five
-		for (int32_t y = 0; y < 5; y++)
+	// top five
+	for (int32_t y = 0; y < 5; y++)
+	{
+		if (posEdPosition-(5-y) >= 0)
 		{
-			if (posEdPosition-(5-y) >= 0)
-			{
-				printThreeDecimalsBg(128, 23+(y*6), posEdPosition-(5-y), video.palette[PAL_QADSCP], video.palette[PAL_BACKGRD]);
-				printTwoDecimalsBg(160, 23+(y*6), song->header.order[posEdPosition-(5-y)], video.palette[PAL_QADSCP], video.palette[PAL_BACKGRD]);
-			}
-			else
-			{
-				fillRect(128, 23+(y*6), 22*FONT_CHAR_W, FONT_CHAR_H, video.palette[PAL_BACKGRD]);
-			}
+			printThreeDecimalsBg(128, 23+(y*6), posEdPosition-(5-y), video.palette[PAL_QADSCP], video.palette[PAL_BACKGRD]);
+			printTwoDecimalsBg(160, 23+(y*6), song->header.order[posEdPosition-(5-y)], video.palette[PAL_QADSCP], video.palette[PAL_BACKGRD]);
 		}
+		else
+		{
+			fillRect(128, 23+(y*6), 22*FONT_CHAR_W, FONT_CHAR_H, video.palette[PAL_BACKGRD]);
+		}
+	}
 
-		// middle
-		printThreeDecimalsBg(128, 53, posEdPosition, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
-		printTwoDecimalsBg(160, 53, *editor.currPosEdPattDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+	// middle
+	printThreeDecimalsBg(128, 53, posEdPosition, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
+	printTwoDecimalsBg(160, 53, *editor.currPosEdPattDisp, video.palette[PAL_GENTXT], video.palette[PAL_GENBKG]);
 
-		// bottom six
-		for (int32_t y = 0; y < 6; y++)
+	// bottom six
+	for (int32_t y = 0; y < 6; y++)
+	{
+		if (posEdPosition+y < song->header.numOrders-1)
 		{
-			if (posEdPosition+y < song->header.numOrders-1)
-			{
-				printThreeDecimalsBg(128, 59+(y*6), posEdPosition+(y+1), video.palette[PAL_QADSCP], video.palette[PAL_BACKGRD]);
-				printTwoDecimalsBg(160, 59+(y*6), song->header.order[posEdPosition+(y+1)], video.palette[PAL_QADSCP], video.palette[PAL_BACKGRD]);
-			}
-			else
-			{
-				fillRect(128, 59+(y*6), 22*FONT_CHAR_W, FONT_CHAR_H, video.palette[PAL_BACKGRD]);
-			}
+			printThreeDecimalsBg(128, 59+(y*6), posEdPosition+(y+1), video.palette[PAL_QADSCP], video.palette[PAL_BACKGRD]);
+			printTwoDecimalsBg(160, 59+(y*6), song->header.order[posEdPosition+(y+1)], video.palette[PAL_QADSCP], video.palette[PAL_BACKGRD]);
 		}
-
-		// kludge to fix bottom part of text edit marker in pos ed
-		if (ui.editTextFlag && ui.editObject == PTB_PE_PATT)
-			renderTextEditMarker();
+		else
+		{
+			fillRect(128, 59+(y*6), 22*FONT_CHAR_W, FONT_CHAR_H, video.palette[PAL_BACKGRD]);
+		}
 	}
+
+	// kludge to fix bottom part of text edit marker in pos ed
+	if (ui.editTextFlag && ui.editObject == PTB_PE_PATT)
+		renderTextEditMarker();
 }
 
 void renderPosEdScreen(void)
@@ -888,15 +864,15 @@
 
 void renderMuteButtons(void)
 {
-	const uint32_t *srcPtr;
-	uint32_t *dstPtr, srcPitch;
-
 	if (ui.diskOpScreenShown || ui.posEdScreenShown)
 		return;
 
-	dstPtr = &video.frameBuffer[(3 * SCREEN_W) + 310];
-	for (uint32_t i = 0; i < AMIGA_VOICES; i++)
+	uint32_t *dstPtr = &video.frameBuffer[(3 * SCREEN_W) + 310];
+	for (uint32_t i = 0; i < PAULA_VOICES; i++)
 	{
+		const uint32_t *srcPtr;
+		uint32_t srcPitch;
+
 		if (editor.muted[i])
 		{
 			srcPtr = &muteButtonsBMP[i * (6 * 7)];
@@ -921,22 +897,6 @@
 	}
 }
 
-void renderClearScreen(void)
-{
-	ui.disablePosEd = true;
-	ui.disableVisualizer = true;
-
-	blit32(160, 51, 104, 39, clearDialogBMP);
-}
-
-void removeClearScreen(void)
-{
-	displayMainScreen();
-
-	ui.disablePosEd = false;
-	ui.disableVisualizer = false;
-}
-
 void updateCurrSample(void)
 {
 	ui.updateCurrSampleName = true;
@@ -1060,9 +1020,9 @@
 void updateVisualizer(void)
 {
 	if (ui.disableVisualizer || ui.diskOpScreenShown ||
-		ui.posEdScreenShown  || ui.editOpScreenShown ||
-		ui.aboutScreenShown  || ui.askScreenShown    ||
-		editor.isWAVRendering || ui.samplingBoxShown)
+		ui.posEdScreenShown || ui.editOpScreenShown ||
+		ui.aboutScreenShown || ui.askBoxShown ||
+		editor.mod2WavOngoing || ui.samplingBoxShown)
 	{
 		return;
 	}
@@ -1103,12 +1063,9 @@
 
 void renderQuadrascopeBg(void)
 {
-	const uint32_t *srcPtr;
-	uint32_t *dstPtr;
+	const uint32_t *srcPtr = &trackerFrameBMP[(44 * SCREEN_W) + 120];
+	uint32_t *dstPtr = &video.frameBuffer[(44 * SCREEN_W) + 120];
 
-	srcPtr = &trackerFrameBMP[(44 * SCREEN_W) + 120];
-	dstPtr = &video.frameBuffer[(44 * SCREEN_W) + 120];
-
 	for (uint32_t y = 0; y < 55; y++)
 	{
 		memcpy(dstPtr, srcPtr, 200 * sizeof (int32_t));
@@ -1117,7 +1074,7 @@
 		dstPtr += SCREEN_W;
 	}
 
-	for (int32_t i = 0; i < AMIGA_VOICES; i++)
+	for (int32_t i = 0; i < PAULA_VOICES; i++)
 		scope[i].emptyScopeDrawn = false;
 }
 
@@ -1129,7 +1086,6 @@
 void renderAboutScreen(void)
 {
 	char verString[16];
-	uint32_t verStringX;
 
 	if (!ui.aboutScreenShown || ui.diskOpScreenShown || ui.posEdScreenShown || ui.editOpScreenShown)
 		return;
@@ -1139,7 +1095,7 @@
 	// draw version string
 
 	sprintf(verString, "v%s", PROG_VER_STR);
-	verStringX = 260 + (((63 - ((uint32_t)strlen(verString) * (FONT_CHAR_W - 1))) + 1) / 2);
+	uint32_t verStringX = 260 + (((63 - ((uint32_t)strlen(verString) * (FONT_CHAR_W - 1))) + 1) / 2);
 	textOutTight(verStringX, 67, verString, video.palette[PAL_GENBKG2]);
 }
 
@@ -1148,7 +1104,6 @@
 	const uint32_t *srcPtr;
 
 	// select what character box to render
-
 	switch (ui.editOpScreen)
 	{
 		default:
@@ -1158,9 +1113,12 @@
 
 		case 1:
 		{
-			     if (editor.trackPattFlag == 0) srcPtr = &editOpModeCharsBMP[EDOP_MODE_BMP_T_OFS];
-			else if (editor.trackPattFlag == 1) srcPtr = &editOpModeCharsBMP[EDOP_MODE_BMP_P_OFS];
-			else srcPtr = &editOpModeCharsBMP[EDOP_MODE_BMP_S_OFS];
+			if (editor.trackPattFlag == 0)
+				srcPtr = &editOpModeCharsBMP[EDOP_MODE_BMP_T_OFS];
+			else if (editor.trackPattFlag == 1)
+				srcPtr = &editOpModeCharsBMP[EDOP_MODE_BMP_P_OFS];
+			else
+				srcPtr = &editOpModeCharsBMP[EDOP_MODE_BMP_S_OFS];
 		}
 		break;
 
@@ -1173,7 +1131,6 @@
 		break;
 	}
 
-	// render it...
 	blit32(310, 47, 7, 6, srcPtr);
 }
 
@@ -1242,73 +1199,6 @@
 	}
 }
 
-void renderMOD2WAVDialog(void)
-{
-	blit32(64, 27, 192, 48, mod2wavBMP);
-}
-
-void updateMOD2WAVDialog(void)
-{
-	if (!ui.updateMod2WavDialog)
-		return;
-
-	ui.updateMod2WavDialog = false;
-
-	if (editor.isWAVRendering)
-	{
-		if (ui.mod2WavFinished)
-		{
-			ui.mod2WavFinished = false;
-
-			resetSong();
-			pointerSetMode(POINTER_MODE_IDLE, DO_CARRY);
-
-			if (editor.abortMod2Wav)
-			{
-				displayErrorMsg("MOD2WAV ABORTED !");
-			}
-			else
-			{
-				displayMsg("MOD RENDERED !");
-				setMsgPointer();
-			}
-
-			editor.isWAVRendering = false;
-			modSetTempo(song->currBPM, true); // update BPM with normal audio output rate
-			displayMainScreen();
-		}
-		else
-		{
-			if (song->rowsInTotal == 0)
-				return;
-
-			// render progress bar
-
-			int32_t percent = (song->rowsCounter * 100) / song->rowsInTotal;
-			if (percent > 100)
-				percent = 100;
-
-			// foreground (progress)
-			const int32_t progressBarWidth = ((percent * 180) + 50) / 100;
-			if (progressBarWidth > 0)
-				fillRect(70, 42, progressBarWidth, 11, video.palette[PAL_GENBKG2]); // foreground (progress)
-
-			// background
-			int32_t bgWidth = 180 - progressBarWidth;
-			if (bgWidth > 0)
-				fillRect(70+progressBarWidth, 42, bgWidth, 11, video.palette[PAL_BORDER]);
-
-			// draw percentage text
-			if (percent > 99)
-				printThreeDecimals(144, 45, percent, video.palette[PAL_GENTXT]);
-			else
-				printTwoDecimals(152, 45, percent, video.palette[PAL_GENTXT]);
-
-			charOut(168, 45, '%', video.palette[PAL_GENTXT]);
-		}
-	}
-}
-
 void updateEditOp(void)
 {
 	if (!ui.editOpScreenShown || ui.posEdScreenShown || ui.diskOpScreenShown)
@@ -1539,7 +1429,7 @@
 		charOut(64,  3, '0', video.palette[PAL_GENTXT]);
 		textOut(64, 14, "00", video.palette[PAL_GENTXT]);
 
-		if (!editor.isWAVRendering)
+		if (!editor.mod2WavOngoing)
 		{
 			charOut(64, 25, '0', video.palette[PAL_GENTXT]);
 			textOut(64, 47, "00", video.palette[PAL_GENTXT]);
@@ -1575,296 +1465,12 @@
 	}
 }
 
-static void restoreStatusAndMousePointer(void)
-{
-	editor.errorMsgActive = false;
-	editor.errorMsgBlock = false;
-	editor.errorMsgCounter = 0;
-	pointerSetPreviousMode();
-	setPrevStatusMessage();
-}
-
-void handleAskNo(void)
-{
-	ui.pat2SmpDialogShown = false;
-
-	switch (ui.askScreenType)
-	{
-		case ASK_SAVEMOD_OVERWRITE:
-		{
-			restoreStatusAndMousePointer();
-			saveModule(DONT_CHECK_IF_FILE_EXIST, GIVE_NEW_FILENAME);
-		}
-		break;
-
-		case ASK_SAVESMP_OVERWRITE:
-		{
-			restoreStatusAndMousePointer();
-			saveSample(DONT_CHECK_IF_FILE_EXIST, GIVE_NEW_FILENAME);
-		}
-		break;
-
-		case ASK_LOAD_DOWNSAMPLE:
-		{
-			restoreStatusAndMousePointer();
-			extLoadWAVOrAIFFSampleCallback(DONT_DOWNSAMPLE);
-		}
-		break;
-
-		default:
-			restoreStatusAndMousePointer();
-		break;
-	}
-
-	removeAskDialog();
-}
-
-void handleAskYes(void)
-{
-	char fileName[20 + 4 + 1];
-	int8_t oldSample;
-	uint32_t i;
-	moduleSample_t *s;
-
-	switch (ui.askScreenType)
-	{
-		case ASK_DISCARD_SONG:
-		{
-			restoreStatusAndMousePointer();
-			diskOpLoadFile2();
-		}
-		break;
-
-		case ASK_DISCARD_SONG_DRAGNDROP:
-		{
-			restoreStatusAndMousePointer();
-			loadDroppedFile2();
-		}
-		break;
-
-		case ASK_RESTORE_SAMPLE:
-		{
-			restoreStatusAndMousePointer();
-			redoSampleData(editor.currSample);
-		}
-		break;
-
-		case ASK_PAT2SMP:
-		{
-			restoreStatusAndMousePointer();
-			doPat2Smp();
-		}
-		break;
-
-		case ASK_SAVE_ALL_SAMPLES:
-		{
-			editor.errorMsgActive = false;
-			editor.errorMsgBlock = false;
-			editor.errorMsgCounter = 0;
-
-			oldSample = editor.currSample;
-			for (i = 0; i < MOD_SAMPLES; i++)
-			{
-				editor.currSample = (int8_t)i;
-				if (song->samples[i].length > 2)
-					saveSample(DONT_CHECK_IF_FILE_EXIST, GIVE_NEW_FILENAME);
-			}
-			editor.currSample = oldSample;
-
-			displayMsg("SAMPLES SAVED !");
-			setMsgPointer();
-		}
-		break;
-
-		case ASK_MAKE_CHORD:
-		{
-			restoreStatusAndMousePointer();
-			mixChordSample();
-		}
-		break;
-
-		case ASK_BOOST_ALL_SAMPLES:
-		{
-			restoreStatusAndMousePointer();
-
-			for (i = 0; i < MOD_SAMPLES; i++)
-				boostSample(i, true);
-
-			if (ui.samplerScreenShown)
-				redrawSample();
-
-			updateWindowTitle(MOD_IS_MODIFIED);
-		}
-		break;
-
-		case ASK_FILTER_ALL_SAMPLES:
-		{
-			restoreStatusAndMousePointer();
-
-			for (i = 0; i < MOD_SAMPLES; i++)
-				filterSample(i, true);
-
-			if (ui.samplerScreenShown)
-				redrawSample();
-
-			updateWindowTitle(MOD_IS_MODIFIED);
-		}
-		break;
-
-		case ASK_UPSAMPLE:
-		{
-			restoreStatusAndMousePointer();
-			upSample();
-		}
-		break;
-
-		case ASK_DOWNSAMPLE:
-		{
-			restoreStatusAndMousePointer();
-			downSample();
-		}
-		break;
-
-		case ASK_KILL_SAMPLE:
-		{
-			restoreStatusAndMousePointer();
-
-			if (editor.sampleZero)
-			{
-				statusNotSampleZero();
-				break;
-			}
-
-			turnOffVoices();
-			s = &song->samples[editor.currSample];
-
-			s->fineTune = 0;
-			s->volume = 0;
-			s->length = 0;
-			s->loopStart = 0;
-			s->loopLength = 2;
-
-			memset(s->text, 0, sizeof (s->text));
-			memset(&song->sampleData[(editor.currSample * config.maxSampleLength)], 0, config.maxSampleLength);
-
-			editor.samplePos = 0;
-			updateCurrSample();
-
-			ui.updateSongSize = true;
-			updateWindowTitle(MOD_IS_MODIFIED);
-		}
-		break;
-
-		case ASK_RESAMPLE:
-		{
-			restoreStatusAndMousePointer();
-			samplerResample();
-		}
-		break;
-
-		case ASK_LOAD_DOWNSAMPLE:
-		{
-			// for WAV and AIFF sample loader
-			restoreStatusAndMousePointer();
-			extLoadWAVOrAIFFSampleCallback(DO_DOWNSAMPLE);
-		}
-		break;
-
-		case ASK_MOD2WAV_OVERWRITE:
-		{
-			memset(fileName, 0, sizeof (fileName));
-
-			if (song->header.name[0] != '\0')
-			{
-				for (i = 0; i < 20; i++)
-				{
-					fileName[i] = (char)tolower(song->header.name[i]);
-					if (fileName[i] == '\0') break;
-					sanitizeFilenameChar(&fileName[i]);
-				}
-
-				strcat(fileName, ".wav");
-			}
-			else
-			{
-				strcpy(fileName, "untitled.wav");
-			}
-
-			renderToWav(fileName, DONT_CHECK_IF_FILE_EXIST);
-		}
-		break;
-
-		case ASK_MOD2WAV:
-		{
-			memset(fileName, 0, sizeof (fileName));
-
-			if (song->header.name[0] != '\0')
-			{
-				for (i = 0; i < 20; i++)
-				{
-					fileName[i] = (char)tolower(song->header.name[i]);
-					if (fileName[i] == '\0') break;
-					sanitizeFilenameChar(&fileName[i]);
-				}
-
-				strcat(fileName, ".wav");
-			}
-			else
-			{
-				strcpy(fileName, "untitled.wav");
-			}
-
-			renderToWav(fileName, CHECK_IF_FILE_EXIST);
-		}
-		break;
-
-		case ASK_QUIT:
-		{
-			restoreStatusAndMousePointer();
-			ui.throwExit = true;
-		}
-		break;
-
-		case ASK_SAVE_SAMPLE:
-		{
-			restoreStatusAndMousePointer();
-			saveSample(CHECK_IF_FILE_EXIST, DONT_GIVE_NEW_FILENAME);
-		}
-		break;
-
-		case ASK_SAVESMP_OVERWRITE:
-		{
-			restoreStatusAndMousePointer();
-			saveSample(DONT_CHECK_IF_FILE_EXIST, DONT_GIVE_NEW_FILENAME);
-		}
-		break;
-
-		case ASK_SAVE_MODULE:
-		{
-			restoreStatusAndMousePointer();
-			saveModule(CHECK_IF_FILE_EXIST, DONT_GIVE_NEW_FILENAME);
-		}
-		break;
-
-		case ASK_SAVEMOD_OVERWRITE:
-		{
-			restoreStatusAndMousePointer();
-			saveModule(DONT_CHECK_IF_FILE_EXIST, DONT_GIVE_NEW_FILENAME);
-		}
-		break;
-
-		default: break;
-	}
-
-	removeAskDialog();
-}
-
 void videoClose(void)
 {
-	SDL_DestroyTexture(video.texture);
-	SDL_DestroyRenderer(video.renderer);
-	SDL_DestroyWindow(video.window);
-	free(video.frameBufferUnaligned);
+	if (video.texture     != NULL) SDL_DestroyTexture(video.texture);
+	if (video.renderer    != NULL) SDL_DestroyRenderer(video.renderer);
+	if (video.window      != NULL) SDL_DestroyWindow(video.window);
+	if (video.frameBuffer != NULL) free(video.frameBuffer);
 }
 
 void setupSprites(void)
@@ -1930,23 +1536,18 @@
 
 void eraseSprites(void)
 {
-	int32_t sx, sy, x, y, sw, sh, srcPitch, dstPitch;
-	const uint32_t *src32;
-	uint32_t *dst32;
-	sprite_t *s;
-
 	for (int32_t i = SPRITE_NUM-1; i >= 0; i--) // erasing must be done in reverse order
 	{
-		s = &sprites[i];
+		sprite_t *s = &sprites[i];
 		if (s->x >= SCREEN_W || s->y >= SCREEN_H) // sprite is hidden, don't draw nor fill clear buffer
 			continue;
 
 		assert(s->refreshBuffer != NULL);
 
-		sw = s->w;
-		sh = s->h;
-		sx = s->x;
-		sy = s->y;
+		int32_t sw = s->w;
+		int32_t sh = s->h;
+		int32_t sx = s->x;
+		int32_t sy = s->y;
 
 		// if x is negative, adjust variables
 		if (sx < 0)
@@ -1962,19 +1563,19 @@
 			sy = 0;
 		}
 
-		dst32 = &video.frameBuffer[(sy * SCREEN_W) + sx];
-		src32 = s->refreshBuffer;
+		uint32_t *dst32 = &video.frameBuffer[(sy * SCREEN_W) + sx];
+		const uint32_t *src32 = s->refreshBuffer;
 
 		// handle x/y clipping
 		if (sx+sw >= SCREEN_W) sw = SCREEN_W - sx;
 		if (sy+sh >= SCREEN_H) sh = SCREEN_H - sy;
 
-		srcPitch = s->w - sw;
-		dstPitch = SCREEN_W - sw;
+		int32_t srcPitch = s->w - sw;
+		int32_t dstPitch = SCREEN_W - sw;
 
-		for (y = 0; y < sh; y++)
+		for (int32_t y = 0; y < sh; y++)
 		{
-			for (x = 0; x < sw; x++)
+			for (int32_t x = 0; x < sw; x++)
 				*dst32++ = *src32++;
 
 			src32 += srcPitch;
@@ -1987,17 +1588,11 @@
 
 void renderSprites(void)
 {
-	const uint8_t *src8;
-	int32_t sx, sy, x, y, srcPtrBias, sw, sh, srcPitch, dstPitch;
-	const uint32_t *src32;
-	uint32_t *dst32, *clr32, colorKey;
-	sprite_t *s;
-
 	renderVuMeters(); // let's put it here even though it's not sprite-based
 
 	for (int32_t i = 0; i < SPRITE_NUM; i++)
 	{
-		s = &sprites[i];
+		sprite_t *s = &sprites[i];
 
 		// set new sprite position
 		s->x = s->newX;
@@ -2008,11 +1603,11 @@
 
 		assert(s->data != NULL && s->refreshBuffer != NULL);
 
-		sw = s->w;
-		sh = s->h;
-		sx = s->x;
-		sy = s->y;
-		srcPtrBias = 0;
+		int32_t sw = s->w;
+		int32_t sh = s->h;
+		int32_t sx = s->x;
+		int32_t sy = s->y;
+		int32_t srcPtrBias = 0;
 
 		// if x is negative, adjust variables
 		if (sx < 0)
@@ -2030,24 +1625,24 @@
 			sy = 0;
 		}
 
-		dst32 = &video.frameBuffer[(sy * SCREEN_W) + sx];
-		clr32 = s->refreshBuffer;
+		uint32_t *dst32 = &video.frameBuffer[(sy * SCREEN_W) + sx];
+		uint32_t *clr32 = s->refreshBuffer;
 
 		// handle x/y clipping
 		if (sx+sw >= SCREEN_W) sw = SCREEN_W - sx;
 		if (sy+sh >= SCREEN_H) sh = SCREEN_H - sy;
 
-		srcPitch = s->w - sw;
-		dstPitch = SCREEN_W - sw;
+		int32_t srcPitch = s->w - sw;
+		int32_t dstPitch = SCREEN_W - sw;
 
-		colorKey = sprites[i].colorKey;
+		uint32_t colorKey = sprites[i].colorKey;
 		if (sprites[i].pixelType == SPRITE_TYPE_RGB)
 		{
 			// 24-bit RGB sprite
-			src32 = ((uint32_t *)sprites[i].data) + srcPtrBias;
-			for (y = 0; y < sh; y++)
+			const uint32_t *src32 = ((uint32_t *)sprites[i].data) + srcPtrBias;
+			for (int32_t y = 0; y < sh; y++)
 			{
-				for (x = 0; x < sw; x++)
+				for (int32_t x = 0; x < sw; x++)
 				{
 					*clr32++ = *dst32; // fill clear buffer
 					if (*src32 != colorKey)
@@ -2065,10 +1660,10 @@
 		else
 		{
 			// 8-bit paletted sprite
-			src8 = ((uint8_t *)sprites[i].data) + srcPtrBias;
-			for (y = 0; y < sh; y++)
+			const uint8_t *src8 = ((uint8_t *)sprites[i].data) + srcPtrBias;
+			for (int32_t y = 0; y < sh; y++)
 			{
-				for (x = 0; x < sw; x++)
+				for (int32_t x = 0; x < sw; x++)
 				{
 					*clr32++ = *dst32; // fill clear buffer
 					if (*src8 != colorKey)
@@ -2133,18 +1728,16 @@
 void updateSpectrumAnalyzer(int8_t vol, int16_t period)
 {
 	const uint8_t maxHeight = SPECTRUM_BAR_HEIGHT + 1; // +1 because of audio latency - allows full height to be seen
-	uint16_t scaledVol;
-	uint32_t scaledNote;
 
 	if (ui.visualizerMode != VISUAL_SPECTRUM || vol <= 0)
 		return;
 
-	scaledVol = ((uint16_t)vol * 24576) >> 16; // scaledVol = vol / 2.66667 (0..64 -> 0..24)
+	uint16_t scaledVol = ((uint16_t)vol * 24576) >> 16; // scaledVol = vol / 2.66667 (0..64 -> 0..24)
 
 	period = CLAMP(period, 113, 856);
 	period -= 113;
 
-	scaledNote = 743 - period;
+	uint32_t scaledNote = 743 - period;
 	scaledNote *= scaledNote;
 	scaledNote /= 25093; // scaledNote now ranges 0..22, no need to clamp
 
@@ -2172,20 +1765,18 @@
 
 void sinkVisualizerBars(void)
 {
-	int32_t i;
+	// sink visualizer bars @ 49.92Hz (Amiga PAL) rate
 
-	// sink stuff @ 49.92Hz (Amiga PAL) rate
-
 	static uint64_t counter50Hz;
 	const uint64_t counter50HzDelta = (uint64_t)(((UINT32_MAX+1.0) * (AMIGA_PAL_VBLANK_HZ / (double)VBLANK_HZ)) + 0.5);
 
 	counter50Hz += counter50HzDelta; // 32.32 fixed-point counter
-	if (counter50Hz > 0xFFFFFFFF)
+	if (counter50Hz > UINT32_MAX)
 	{
-		counter50Hz &= 0xFFFFFFFF;
+		counter50Hz &= UINT32_MAX;
 
 		// sink VU-meters
-		for (i = 0; i < AMIGA_VOICES; i++)
+		for (int32_t i = 0; i < PAULA_VOICES; i++)
 		{
 			if (editor.vuMeterVolumes[i] > 0)
 				editor.vuMeterVolumes[i]--;
@@ -2192,7 +1783,7 @@
 		}
 
 		// sink "spectrum analyzer" bars
-		for (i = 0; i < SPECTRUM_BAR_NUM; i++)
+		for (int32_t i = 0; i < SPECTRUM_BAR_NUM; i++)
 		{
 			if (editor.spectrumVolumes[i] > 0)
 				editor.spectrumVolumes[i]--;
@@ -2202,8 +1793,6 @@
 
 void updateRenderSizeVars(void)
 {
-	float fXScale, fYScale;
-
 	if (video.useDesktopMouseCoords)
 	{
 		SDL_DisplayMode dm;
@@ -2232,6 +1821,7 @@
 		}
 		else
 		{
+			float fXScale, fYScale;
 			SDL_RenderGetScale(video.renderer, &fXScale, &fYScale);
 
 			video.renderW = (int32_t)(SCREEN_W * fXScale);
@@ -2390,7 +1980,7 @@
 
 	SDL_RenderSetLogicalSize(video.renderer, SCREEN_W, SCREEN_H);
 
-#if SDL_PATCHLEVEL >= 5
+#if SDL_MINOR_VERSION >= 24 || (SDL_MINOR_VERSION == 0 && SDL_PATCHLEVEL >= 5)
 	SDL_RenderSetIntegerScale(video.renderer, config.integerScaling ? SDL_TRUE : SDL_FALSE);
 #endif
 
@@ -2414,15 +2004,12 @@
 	SDL_SetTextureBlendMode(video.texture, SDL_BLENDMODE_NONE);
 
 	// frame buffer used by SDL (for texture)
-	video.frameBufferUnaligned = (uint32_t *)MALLOC_PAD(SCREEN_W * SCREEN_H * sizeof (int32_t), 256);
-	if (video.frameBufferUnaligned == NULL)
+	video.frameBuffer = (uint32_t *)malloc(SCREEN_W * SCREEN_H * sizeof (int32_t));
+	if (video.frameBuffer == NULL)
 	{
 		showErrorMsgBox("Out of memory!");
 		return false;
 	}
-
-	// we want an aligned pointer
-	video.frameBuffer = (uint32_t *)ALIGN_PTR(video.frameBufferUnaligned, 256);
 
 	// Workaround: SDL_GetGlobalMouseState() doesn't work with KMSDRM/Wayland
 	video.useDesktopMouseCoords = true;
--- a/src/pt2_visuals.h
+++ b/src/pt2_visuals.h
@@ -25,8 +25,10 @@
 void vLine(int32_t x, int32_t y, int32_t h, const uint32_t pixelColor);
 void drawFramework1(int32_t x, int32_t y, int32_t w, int32_t h);
 void drawFramework2(int32_t x, int32_t y, int32_t w, int32_t h);
+void drawFramework3(int32_t x, int32_t y, int32_t w, int32_t h);
 void fillRect(int32_t x, int32_t y, int32_t w, int32_t h, const uint32_t pixelColor);
-void drawButton(int32_t x, int32_t y, int32_t w, const char *text);
+void drawButton1(int32_t x, int32_t y, int32_t w, int32_t h, const char *text);
+void drawButton2(int32_t x, int32_t y, int32_t w, int32_t h, const char *text);
 void drawUpButton(int32_t x, int32_t y);
 void drawDownButton(int32_t x, int32_t y);
 
@@ -35,11 +37,10 @@
 void statusSampleIsEmpty(void);
 void statusNotSampleZero(void);
 void changeStatusText(const char *text);
-
 void resetAllScreens(void);
-void handleAskNo(void);
-void handleAskYes(void);
+
 bool setupVideo(void);
+void renderFrame2(void);
 void renderFrame(void);
 void flipFrame(void);
 void updateSpectrumAnalyzer(int8_t vol, int16_t period);
@@ -49,18 +50,12 @@
 void updateEditOp(void);
 void toggleFullscreen(void);
 void videoClose(void);
-
 void displayMainScreen(void);
-void renderAskDialog(void);
-void renderBigAskDialog(void);
-void showDownsampleAskDialog(void);
 void renderPosEdScreen(void);
 void renderMuteButtons(void);
-void renderClearScreen(void);
 void renderAboutScreen(void);
 void renderQuadrascopeBg(void);
 void renderSpectrumAnalyzerBg(void);
-void renderMOD2WAVDialog(void);
 void renderEditOpMode(void);
 void renderTextEditMarker(void);
 void renderEditOpScreen(void);
@@ -67,10 +62,8 @@
 void renderSamplerVolBox(void);
 void renderSamplerFiltersBox(void);
 void removeTextEditMarker(void);
-void removeClearScreen(void);
 void removeSamplerVolBox(void);
 void removeSamplerFiltersBox(void);
-void removeAskDialog(void);
 void fillToVuMetersBgBuffer(void);
 void showVolFromSlider(void);
 void showVolToSlider(void);
--- a/src/pt2_xpk.c
+++ b/src/pt2_xpk.c
@@ -10,6 +10,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include "pt2_helpers.h"
 
 typedef struct XPKFILEHEADER
@@ -46,10 +47,9 @@
 
 static inline int32_t bfextu(size_t p, int32_t bo, int32_t bc, XPK_BufferBounds *bufs)
 {
-	uint32_t r;
-
 	p += (uint32_t)bo >> 3;
-	r = SrcRead(p, bufs); p++;
+
+	uint32_t r = SrcRead(p, bufs); p++;
 	r <<= 8;
 	r |= SrcRead(p, bufs); p++;
 	r <<= 8;
@@ -63,10 +63,9 @@
 
 static inline int32_t bfexts(size_t p, int32_t bo, int32_t bc, XPK_BufferBounds *bufs)
 {
-	uint32_t r;
-
 	p += (uint32_t)bo >> 3;
-	r = SrcRead(p, bufs); p++;
+
+	uint32_t r = SrcRead(p, bufs); p++;
 	r <<= 8;
 	r |= SrcRead(p, bufs); p++;
 	r <<= 8;
@@ -91,9 +90,8 @@
 	if (len <= 0)
 		return false;
 
-	int32_t d0,d1,d2,d3,d4,d5,d6,a2,a5;
-	int32_t cp, cup1, type;
-	size_t c, src, phist = 0;
+	int32_t d0, d1, d2, d3, d4, d5, d6, a2, a5, cup1;
+	size_t phist = 0;
 
 	const uint32_t unpackedLen = MIN((uint32_t)len, MIN(srcLen, UINT32_MAX / 20) * 20);
 
@@ -108,12 +106,12 @@
 	bufs.pSrcBeg = src_;
 	bufs.SrcSize = srcLen;
 
-	src = 0;
-	c = src;
+	size_t src = 0;
+	size_t c = src;
 	while (len > 0)
 	{
-		type = SrcRead(c+0, &bufs);
-		cp = (SrcRead(c+4, &bufs)<<8) | (SrcRead(c+5, &bufs)); // packed
+		int32_t type = SrcRead(c+0, &bufs);
+		int32_t cp = (SrcRead(c+4, &bufs)<<8) | (SrcRead(c+5, &bufs)); // packed
 		cup1 = (SrcRead(c+6, &bufs)<<8) | (SrcRead(c+7, &bufs)); // unpacked
 
 		c += 8;
binary files a/vs2019_project/pt2-clone/SDL2.dll b/vs2019_project/pt2-clone/SDL2.dll differ
--- a/vs2019_project/pt2-clone/protracker.ini
+++ b/vs2019_project/pt2-clone/protracker.ini
@@ -30,7 +30,7 @@
 ;         that since this feature is off by default, most people will not be
 ;         able to listen to 128kB modules in the PT2 clone out of the box.
 ;
-64K_LIMIT=TRUE
+64K_LIMIT=FALSE
 
 [VIDEO SETTINGS]
 ; Video scaling factor
@@ -252,7 +252,7 @@
 ; Audio output frequency
 ;        Syntax: Number, in hertz
 ; Default value: 48000
-;       Comment: Ranges from 44100 to 192000. Also applies to MOD2WAV.
+;       Comment: Ranges from 44100 to 192000. Does not apply to MOD2WAV.
 ;
 FREQUENCY=48000
 
@@ -263,6 +263,13 @@
 ;         the frequency used for your audio input device (for sampling).
 ;
 SAMPLINGFREQ=44100
+
+; MOD2WAV output frequency
+;        Syntax: Number, in hertz
+; Default value: 44100
+;       Comment: Ranges from 44100 to 192000.
+;
+MOD2WAVFREQUENCY=44100
 
 ; Filter model (Amiga model)
 ;        Syntax: A500 or A1200
--- a/vs2019_project/pt2-clone/pt2-clone.vcxproj
+++ b/vs2019_project/pt2-clone/pt2-clone.vcxproj
@@ -237,6 +237,8 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\src\pt2_amigafilters.h" />
+    <ClInclude Include="..\..\src\pt2_askbox.h" />
     <ClInclude Include="..\..\src\pt2_audio.h" />
     <ClInclude Include="..\..\src\pt2_blep.h" />
     <ClInclude Include="..\..\src\pt2_bmp.h" />
@@ -248,7 +250,6 @@
     <ClInclude Include="..\..\src\pt2_helpers.h" />
     <ClInclude Include="..\..\src\pt2_hpc.h" />
     <ClInclude Include="..\..\src\pt2_keyboard.h" />
-    <ClInclude Include="..\..\src\pt2_ledfilter.h" />
     <ClInclude Include="..\..\src\pt2_math.h" />
     <ClInclude Include="..\..\src\pt2_mod2wav.h" />
     <ClInclude Include="..\..\src\pt2_module_loader.h" />
@@ -257,8 +258,10 @@
     <ClInclude Include="..\..\src\pt2_palette.h" />
     <ClInclude Include="..\..\src\pt2_pat2smp.h" />
     <ClInclude Include="..\..\src\pt2_pattern_viewer.h" />
+    <ClInclude Include="..\..\src\pt2_paula.h" />
     <ClInclude Include="..\..\src\pt2_rcfilter.h" />
     <ClInclude Include="..\..\src\pt2_downsample2x.h" />
+    <ClInclude Include="..\..\src\pt2_replayer.h" />
     <ClInclude Include="..\..\src\pt2_sample_loader.h" />
     <ClInclude Include="..\..\src\pt2_sampler.h" />
     <ClInclude Include="..\..\src\pt2_sample_saver.h" />
@@ -274,15 +277,12 @@
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\gfx\pt2_gfx_aboutscreen.c" />
-    <ClCompile Include="..\..\src\gfx\pt2_gfx_clear.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_diskop.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_editop.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_font.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_icon.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_loop_pins.c" />
-    <ClCompile Include="..\..\src\gfx\pt2_gfx_mod2wav.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_mute_buttons.c" />
-    <ClCompile Include="..\..\src\gfx\pt2_gfx_pat2smp_dialog.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_patcursor.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_pointer.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_posed.c" />
@@ -290,7 +290,8 @@
     <ClCompile Include="..\..\src\gfx\pt2_gfx_spectrum.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_tracker.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_vumeter.c" />
-    <ClCompile Include="..\..\src\gfx\pt2_gfx_yes_no_dialog.c" />
+    <ClCompile Include="..\..\src\pt2_amigafilters.c" />
+    <ClCompile Include="..\..\src\pt2_askbox.c" />
     <ClCompile Include="..\..\src\pt2_audio.c" />
     <ClCompile Include="..\..\src\pt2_blep.c" />
     <ClCompile Include="..\..\src\pt2_bmp.c" />
@@ -301,11 +302,11 @@
     <ClCompile Include="..\..\src\pt2_helpers.c" />
     <ClCompile Include="..\..\src\pt2_hpc.c" />
     <ClCompile Include="..\..\src\pt2_keyboard.c" />
-    <ClCompile Include="..\..\src\pt2_ledfilter.c" />
     <ClCompile Include="..\..\src\pt2_main.c" />
     <ClCompile Include="..\..\src\pt2_math.c" />
     <ClCompile Include="..\..\src\pt2_mod2wav.c" />
     <ClCompile Include="..\..\src\pt2_module_loader.c" />
+    <ClCompile Include="..\..\src\pt2_paula.c" />
     <ClCompile Include="..\..\src\pt2_rcfilter.c" />
     <ClCompile Include="..\..\src\pt2_replayer.c" />
     <ClCompile Include="..\..\src\pt2_module_saver.c" />
--- a/vs2019_project/pt2-clone/pt2-clone.vcxproj.filters
+++ b/vs2019_project/pt2-clone/pt2-clone.vcxproj.filters
@@ -93,9 +93,6 @@
     <ClInclude Include="..\..\src\pt2_rcfilter.h">
       <Filter>headers</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\pt2_ledfilter.h">
-      <Filter>headers</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\src\pt2_chordmaker.h">
       <Filter>headers</Filter>
     </ClInclude>
@@ -111,6 +108,18 @@
     <ClInclude Include="..\..\src\pt2_xpk.h">
       <Filter>headers</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\pt2_askbox.h">
+      <Filter>headers</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\pt2_replayer.h">
+      <Filter>headers</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\pt2_paula.h">
+      <Filter>headers</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\pt2_amigafilters.h">
+      <Filter>headers</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\pt2_audio.c" />
@@ -132,9 +141,6 @@
     <ClCompile Include="..\..\src\gfx\pt2_gfx_aboutscreen.c">
       <Filter>gfx</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\gfx\pt2_gfx_clear.c">
-      <Filter>gfx</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\gfx\pt2_gfx_diskop.c">
       <Filter>gfx</Filter>
     </ClCompile>
@@ -150,15 +156,9 @@
     <ClCompile Include="..\..\src\gfx\pt2_gfx_loop_pins.c">
       <Filter>gfx</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\gfx\pt2_gfx_mod2wav.c">
-      <Filter>gfx</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\gfx\pt2_gfx_mute_buttons.c">
       <Filter>gfx</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\gfx\pt2_gfx_pat2smp_dialog.c">
-      <Filter>gfx</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\gfx\pt2_gfx_patcursor.c">
       <Filter>gfx</Filter>
     </ClCompile>
@@ -180,9 +180,6 @@
     <ClCompile Include="..\..\src\gfx\pt2_gfx_vumeter.c">
       <Filter>gfx</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\gfx\pt2_gfx_yes_no_dialog.c">
-      <Filter>gfx</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\pt2_mod2wav.c" />
     <ClCompile Include="..\..\src\pt2_pat2smp.c" />
     <ClCompile Include="..\..\src\pt2_structs.c" />
@@ -196,12 +193,14 @@
     <ClCompile Include="..\..\src\pt2_sampling.c" />
     <ClCompile Include="..\..\src\pt2_sync.c" />
     <ClCompile Include="..\..\src\pt2_rcfilter.c" />
-    <ClCompile Include="..\..\src\pt2_ledfilter.c" />
     <ClCompile Include="..\..\src\pt2_chordmaker.c" />
     <ClCompile Include="..\..\src\pt2_downsample2x.c" />
     <ClCompile Include="..\..\src\pt2_math.c" />
     <ClCompile Include="..\..\src\pt2_hpc.c" />
     <ClCompile Include="..\..\src\pt2_xpk.c" />
+    <ClCompile Include="..\..\src\pt2_askbox.c" />
+    <ClCompile Include="..\..\src\pt2_paula.c" />
+    <ClCompile Include="..\..\src\pt2_amigafilters.c" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\..\src\pt2-clone.rc" />
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL.h
@@ -41,6 +41,7 @@
 #include "SDL_events.h"
 #include "SDL_filesystem.h"
 #include "SDL_gamecontroller.h"
+#include "SDL_guid.h"
 #include "SDL_haptic.h"
 #include "SDL_hidapi.h"
 #include "SDL_hints.h"
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_assert.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_assert.h
@@ -22,7 +22,7 @@
 #ifndef SDL_assert_h_
 #define SDL_assert_h_
 
-#include "SDL_config.h"
+#include "SDL_stdinc.h"
 
 #include "begin_code.h"
 /* Set up for C function definitions, even when using C++ */
@@ -51,6 +51,8 @@
 /* Don't include intrin.h here because it contains C++ code */
     extern void __cdecl __debugbreak(void);
     #define SDL_TriggerBreakpoint() __debugbreak()
+#elif _SDL_HAS_BUILTIN(__builtin_debugtrap)
+    #define SDL_TriggerBreakpoint() __builtin_debugtrap()
 #elif ( (!defined(__NACL__)) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))) )
     #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
 #elif ( defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) )  /* this might work on other ARM targets, but this is a known quantity... */
@@ -69,7 +71,7 @@
 
 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */
 #   define SDL_FUNCTION __func__
-#elif ((__GNUC__ >= 2) || defined(_MSC_VER) || defined (__WATCOMC__))
+#elif ((defined(__GNUC__) && (__GNUC__ >= 2)) || defined(_MSC_VER) || defined (__WATCOMC__))
 #   define SDL_FUNCTION __FUNCTION__
 #else
 #   define SDL_FUNCTION "???"
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_atomic.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_atomic.h
@@ -237,6 +237,26 @@
 #endif
 #endif
 
+/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
+#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
+    #define SDL_CPUPauseInstruction() __asm__ __volatile__("pause\n")  /* Some assemblers can't do REP NOP, so go with PAUSE. */
+#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
+    #define SDL_CPUPauseInstruction() __asm__ __volatile__("yield" ::: "memory")
+#elif (defined(__powerpc__) || defined(__powerpc64__))
+    #define SDL_CPUPauseInstruction() __asm__ __volatile__("or 27,27,27");
+#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
+    #define SDL_CPUPauseInstruction() _mm_pause()  /* this is actually "rep nop" and not a SIMD instruction. No inline asm in MSVC x86-64! */
+#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
+    #define SDL_CPUPauseInstruction() __yield()
+#elif defined(__WATCOMC__) && defined(__386__)
+    /* watcom assembler rejects PAUSE if CPU < i686, and it refuses REP NOP as an invalid combination. Hardcode the bytes.  */
+    extern __inline void SDL_CPUPauseInstruction(void);
+    #pragma aux SDL_CPUPauseInstruction = "db 0f3h,90h"
+#else
+    #define SDL_CPUPauseInstruction()
+#endif
+
+
 /**
  * \brief A type representing an atomic integer value.  It is a struct
  *        so people don't accidentally use numeric operations on it.
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_audio.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_audio.h
@@ -172,7 +172,7 @@
  *  2:  FL FR                       (stereo)
  *  3:  FL FR LFE                   (2.1 surround)
  *  4:  FL FR BL BR                 (quad)
- *  5:  FL FR FC BL BR              (quad + center)
+ *  5:  FL FR LFE BL BR             (4.1 surround)
  *  6:  FL FR FC LFE SL SR          (5.1 surround - last two can also be BL BR)
  *  7:  FL FR FC LFE BC SL SR       (6.1 surround)
  *  8:  FL FR FC LFE BL BR SL SR    (7.1 surround)
@@ -487,6 +487,7 @@
  * \since This function is available since SDL 2.0.0.
  *
  * \sa SDL_GetNumAudioDevices
+ * \sa SDL_GetDefaultAudioInfo
  */
 extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index,
                                                            int iscapture);
@@ -512,6 +513,7 @@
  * \since This function is available since SDL 2.0.16.
  *
  * \sa SDL_GetNumAudioDevices
+ * \sa SDL_GetDefaultAudioInfo
  */
 extern DECLSPEC int SDLCALL SDL_GetAudioDeviceSpec(int index,
                                                    int iscapture,
@@ -519,6 +521,41 @@
 
 
 /**
+ * Get the name and preferred format of the default audio device.
+ *
+ * Some (but not all!) platforms have an isolated mechanism to get information
+ * about the "default" device. This can actually be a completely different
+ * device that's not in the list you get from SDL_GetAudioDeviceSpec(). It can
+ * even be a network address! (This is discussed in SDL_OpenAudioDevice().)
+ *
+ * As a result, this call is not guaranteed to be performant, as it can query
+ * the sound server directly every time, unlike the other query functions. You
+ * should call this function sparingly!
+ *
+ * `spec` will be filled with the sample rate, sample format, and channel
+ * count, if a default device exists on the system. If `name` is provided,
+ * will be filled with either a dynamically-allocated UTF-8 string or NULL.
+ *
+ * \param name A pointer to be filled with the name of the default device (can
+ *             be NULL). Please call SDL_free() when you are done with this
+ *             pointer!
+ * \param spec The SDL_AudioSpec to be initialized by this function.
+ * \param iscapture non-zero to query the default recording device, zero to
+ *                  query the default output device.
+ * \returns 0 on success, nonzero on error
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GetAudioDeviceName
+ * \sa SDL_GetAudioDeviceSpec
+ * \sa SDL_OpenAudioDevice
+ */
+extern DECLSPEC int SDLCALL SDL_GetDefaultAudioInfo(char **name,
+                                                    SDL_AudioSpec *spec,
+                                                    int iscapture);
+
+
+/**
  * Open a specific audio device.
  *
  * SDL_OpenAudio(), unlike this function, always acts on device ID 1. As such,
@@ -584,6 +621,7 @@
  * - `SDL_AUDIO_ALLOW_FREQUENCY_CHANGE`
  * - `SDL_AUDIO_ALLOW_FORMAT_CHANGE`
  * - `SDL_AUDIO_ALLOW_CHANNELS_CHANGE`
+ * - `SDL_AUDIO_ALLOW_SAMPLES_CHANGE`
  * - `SDL_AUDIO_ALLOW_ANY_CHANGE`
  *
  * These flags specify how SDL should behave when a device cannot offer a
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config.h
@@ -38,6 +38,18 @@
 #include <winsdkver.h>
 #endif
 
+/* sdkddkver.h defines more specific SDK version numbers. This is needed because older versions of the
+ * Windows 10 SDK have broken declarations for the C API for DirectX 12. */
+#if !defined(HAVE_SDKDDKVER_H) && defined(__has_include)
+#if __has_include(<sdkddkver.h>)
+#define HAVE_SDKDDKVER_H 1
+#endif
+#endif
+
+#ifdef HAVE_SDKDDKVER_H
+#include <sdkddkver.h>
+#endif
+
 /* This is a set of defines to configure the SDL features */
 
 #if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
@@ -97,6 +109,7 @@
 #define HAVE_DDRAW_H 1
 #define HAVE_DINPUT_H 1
 #define HAVE_DSOUND_H 1
+#ifndef __WATCOMC__
 #define HAVE_DXGI_H 1
 #define HAVE_XINPUT_H 1
 #if defined(_WIN32_MAXVER) && _WIN32_MAXVER >= 0x0A00  /* Windows 10 SDK */
@@ -106,10 +119,17 @@
 #define HAVE_D3D11_H 1
 #define HAVE_ROAPI_H 1
 #endif
+#if defined(WDK_NTDDI_VERSION) && WDK_NTDDI_VERSION > 0x0A000008 /* 10.0.19041.0 */
+#define HAVE_D3D12_H 1
+#endif
+#if defined(_WIN32_MAXVER) && _WIN32_MAXVER >= 0x0603  /* Windows 8.1 SDK */
+#define HAVE_SHELLSCALINGAPI_H 1
+#endif
 #define HAVE_MMDEVICEAPI_H 1
 #define HAVE_AUDIOCLIENT_H 1
 #define HAVE_TPCSHRD_H 1
 #define HAVE_SENSORSAPI_H 1
+#endif
 #if (defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64)) && (defined(_MSC_VER) && _MSC_VER >= 1600)
 #define HAVE_IMMINTRIN_H 1
 #elif defined(__has_include) && (defined(__i386__) || defined(__x86_64))
@@ -136,7 +156,11 @@
 #define HAVE_REALLOC 1
 #define HAVE_FREE 1
 #define HAVE_ALLOCA 1
+/* OpenWatcom requires specific calling conventions for qsort and bsearch */
+#ifndef __WATCOMC__
 #define HAVE_QSORT 1
+#define HAVE_BSEARCH 1
+#endif
 #define HAVE_ABS 1
 #define HAVE_MEMSET 1
 #define HAVE_MEMCPY 1
@@ -167,37 +191,40 @@
 #define HAVE__WCSNICMP 1
 #define HAVE__WCSDUP 1
 #define HAVE_ACOS   1
-#define HAVE_ACOSF  1
 #define HAVE_ASIN   1
-#define HAVE_ASINF  1
 #define HAVE_ATAN   1
-#define HAVE_ATANF  1
 #define HAVE_ATAN2  1
+#define HAVE_CEIL   1
+#define HAVE_COS    1
+#define HAVE_EXP    1
+#define HAVE_FABS   1
+#define HAVE_FLOOR  1
+#define HAVE_FMOD   1
+#define HAVE_LOG    1
+#define HAVE_LOG10  1
+#define HAVE_POW    1
+#define HAVE_SIN    1
+#define HAVE_SQRT   1
+#define HAVE_TAN    1
+#ifndef __WATCOMC__
+#define HAVE_ACOSF  1
+#define HAVE_ASINF  1
+#define HAVE_ATANF  1
 #define HAVE_ATAN2F 1
 #define HAVE_CEILF  1
 #define HAVE__COPYSIGN 1
-#define HAVE_COS    1
 #define HAVE_COSF   1
-#define HAVE_EXP    1
 #define HAVE_EXPF   1
-#define HAVE_FABS   1
 #define HAVE_FABSF  1
-#define HAVE_FLOOR  1
 #define HAVE_FLOORF 1
-#define HAVE_FMOD   1
 #define HAVE_FMODF  1
-#define HAVE_LOG    1
 #define HAVE_LOGF   1
-#define HAVE_LOG10  1
 #define HAVE_LOG10F 1
-#define HAVE_POW    1
 #define HAVE_POWF   1
-#define HAVE_SIN    1
 #define HAVE_SINF   1
-#define HAVE_SQRT   1
 #define HAVE_SQRTF  1
-#define HAVE_TAN    1
 #define HAVE_TANF   1
+#endif
 #if defined(_MSC_VER)
 /* These functions were added with the VC++ 2013 C runtime library */
 #if _MSC_VER >= 1800
@@ -217,8 +244,18 @@
 #if _MSC_VER >= 1400
 #define HAVE__FSEEKI64 1
 #endif
+#ifdef _USE_MATH_DEFINES
+#define HAVE_M_PI 1
 #endif
-#if !defined(_MSC_VER) || defined(_USE_MATH_DEFINES)
+#elif defined(__WATCOMC__)
+#define HAVE__FSEEKI64 1
+#define HAVE_STRTOLL 1
+#define HAVE_STRTOULL 1
+#define HAVE_VSSCANF 1
+#define HAVE_ROUND 1
+#define HAVE_SCALBN 1
+#define HAVE_TRUNC  1
+#else
 #define HAVE_M_PI 1
 #endif
 #else
@@ -227,7 +264,9 @@
 #endif
 
 /* Enable various audio drivers */
+#if defined(HAVE_MMDEVICEAPI_H) && defined(HAVE_AUDIOCLIENT_H)
 #define SDL_AUDIO_DRIVER_WASAPI 1
+#endif
 #define SDL_AUDIO_DRIVER_DSOUND 1
 #define SDL_AUDIO_DRIVER_WINMM  1
 #define SDL_AUDIO_DRIVER_DISK   1
@@ -248,7 +287,11 @@
 #define SDL_HAPTIC_XINPUT   1
 
 /* Enable the sensor driver */
+#ifdef HAVE_SENSORSAPI_H
 #define SDL_SENSOR_WINDOWS  1
+#else
+#define SDL_SENSOR_DUMMY    1
+#endif
 
 /* Enable various shared object loading systems */
 #define SDL_LOADSO_WINDOWS  1
@@ -270,6 +313,9 @@
 #if !defined(SDL_VIDEO_RENDER_D3D11) && defined(HAVE_D3D11_H)
 #define SDL_VIDEO_RENDER_D3D11  1
 #endif
+#if !defined(SDL_VIDEO_RENDER_D3D12) && defined(HAVE_D3D12_H)
+#define SDL_VIDEO_RENDER_D3D12  1
+#endif
 
 /* Enable OpenGL support */
 #ifndef SDL_VIDEO_OPENGL
@@ -299,11 +345,6 @@
 
 /* Enable filesystem support */
 #define SDL_FILESYSTEM_WINDOWS  1
-
-/* Enable assembly routines (Win64 doesn't have inline asm) */
-#ifndef _WIN64
-#define SDL_ASSEMBLY_ROUTINES   1
-#endif
 
 #endif /* SDL_config_windows_h_ */
 
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_cpuinfo.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_cpuinfo.h
@@ -79,7 +79,7 @@
 #if !defined(SDL_DISABLE_ARM_NEON_H)
 #  if defined(__ARM_NEON)
 #    include <arm_neon.h>
-#  elif defined(__WINDOWS__) || defined(__WINRT__)
+#  elif defined(__WINDOWS__) || defined(__WINRT__) || defined(__GDK__)
 /* Visual Studio doesn't define __ARM_ARCH, but _M_ARM (if set, always 7), and _M_ARM64 (if set, always 1). */
 #    if defined(_M_ARM)
 #      include <armintr.h>
@@ -98,6 +98,14 @@
 #if defined(__3dNOW__) && !defined(SDL_DISABLE_MM3DNOW_H)
 #include <mm3dnow.h>
 #endif
+#if defined(__loongarch_sx) && !defined(SDL_DISABLE_LSX_H)
+#include <lsxintrin.h>
+#define __LSX__
+#endif
+#if defined(__loongarch_asx) && !defined(SDL_DISABLE_LASX_H)
+#include <lasxintrin.h>
+#define __LASX__
+#endif
 #if defined(HAVE_IMMINTRIN_H) && !defined(SDL_DISABLE_IMMINTRIN_H)
 #include <immintrin.h>
 #else
@@ -434,9 +442,35 @@
 extern DECLSPEC SDL_bool SDLCALL SDL_HasNEON(void);
 
 /**
+ * Determine whether the CPU has LSX (LOONGARCH SIMD) features.
+ *
+ * This always returns false on CPUs that aren't using LOONGARCH instruction
+ * sets.
+ *
+ * \returns SDL_TRUE if the CPU has LOONGARCH LSX features or SDL_FALSE if
+ *          not.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasLSX(void);
+
+/**
+ * Determine whether the CPU has LASX (LOONGARCH SIMD) features.
+ *
+ * This always returns false on CPUs that aren't using LOONGARCH instruction
+ * sets.
+ *
+ * \returns SDL_TRUE if the CPU has LOONGARCH LASX features or SDL_FALSE if
+ *          not.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasLASX(void);
+
+/**
  * Get the amount of RAM configured in the system.
  *
- * \returns the amount of RAM configured in the system in MB.
+ * \returns the amount of RAM configured in the system in MiB.
  *
  * \since This function is available since SDL 2.0.1.
  */
@@ -494,7 +528,7 @@
  *
  * \since This function is available since SDL 2.0.10.
  *
- * \sa SDL_SIMDAlignment
+ * \sa SDL_SIMDGetAlignment
  * \sa SDL_SIMDRealloc
  * \sa SDL_SIMDFree
  */
@@ -518,7 +552,7 @@
  *
  * \since This function is available since SDL 2.0.14.
  *
- * \sa SDL_SIMDAlignment
+ * \sa SDL_SIMDGetAlignment
  * \sa SDL_SIMDAlloc
  * \sa SDL_SIMDFree
  */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_endian.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_endian.h
@@ -39,7 +39,7 @@
 static __inline__ void __attribute__((__always_inline__, __nodebug__))
 _m_prefetch(void *__P)
 {
-  __builtin_prefetch (__P, 0, 3 /* _MM_HINT_T0 */);
+  __builtin_prefetch(__P, 0, 3 /* _MM_HINT_T0 */);
 }
 #endif /* __PRFCHWINTRIN_H */
 #endif /* __clang__ */
@@ -59,7 +59,7 @@
 #ifdef __linux__
 #include <endian.h>
 #define SDL_BYTEORDER  __BYTE_ORDER
-#elif defined(__OpenBSD__)
+#elif defined(__OpenBSD__) || defined(__DragonFly__)
 #include <endian.h>
 #define SDL_BYTEORDER  BYTE_ORDER
 #elif defined(__FreeBSD__) || defined(__NetBSD__)
@@ -78,7 +78,7 @@
 #if defined(__hppa__) || \
     defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
     (defined(__MIPS__) && defined(__MIPSEB__)) || \
-    defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \
+    defined(__ppc__) || defined(__POWERPC__) || defined(__powerpc__) || defined(__PPC__) || \
     defined(__sparc__)
 #define SDL_BYTEORDER   SDL_BIG_ENDIAN
 #else
@@ -86,6 +86,28 @@
 #endif
 #endif /* __linux__ */
 #endif /* !SDL_BYTEORDER */
+
+#ifndef SDL_FLOATWORDORDER           /* Not defined in SDL_config.h? */
+/* predefs from newer gcc versions: */
+#if defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__FLOAT_WORD_ORDER__)
+#if (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define SDL_FLOATWORDORDER   SDL_LIL_ENDIAN
+#elif (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define SDL_FLOATWORDORDER   SDL_BIG_ENDIAN
+#else
+#error Unsupported endianness
+#endif /**/
+#elif defined(__MAVERICK__)
+/* For Maverick, float words are always little-endian. */
+#define SDL_FLOATWORDORDER   SDL_LIL_ENDIAN
+#elif (defined(__arm__) || defined(__thumb__)) && !defined(__VFP_FP__) && !defined(__ARM_EABI__)
+/* For FPA, float words are always big-endian. */
+#define SDL_FLOATWORDORDER   SDL_BIG_ENDIAN
+#else
+/* By default, assume that floats words follow the memory system mode. */
+#define SDL_FLOATWORDORDER   SDL_BYTEORDER
+#endif /* __FLOAT_WORD_ORDER__ */
+#endif /* !SDL_FLOATWORDORDER */
 
 
 #include "begin_code.h"
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_events.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_events.h
@@ -118,6 +118,7 @@
     SDL_JOYBUTTONUP,            /**< Joystick button released */
     SDL_JOYDEVICEADDED,         /**< A new joystick has been inserted into the system */
     SDL_JOYDEVICEREMOVED,       /**< An opened joystick has been removed */
+    SDL_JOYBATTERYUPDATED,      /**< Joystick battery level change */
 
     /* Game controller events */
     SDL_CONTROLLERAXISMOTION  = 0x650, /**< Game controller axis motion */
@@ -395,6 +396,16 @@
     Sint32 which;       /**< The joystick device index for the ADDED event, instance id for the REMOVED event */
 } SDL_JoyDeviceEvent;
 
+/**
+ *  \brief Joysick battery level change event structure (event.jbattery.*)
+ */
+typedef struct SDL_JoyBatteryEvent
+{
+    Uint32 type;        /**< ::SDL_JOYBATTERYUPDATED */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    SDL_JoystickID which; /**< The joystick instance id */
+    SDL_JoystickPowerLevel level; /**< The joystick battery level */
+} SDL_JoyBatteryEvent;
 
 /**
  *  \brief Game controller axis motion event structure (event.caxis.*)
@@ -625,6 +636,7 @@
     SDL_JoyHatEvent jhat;                   /**< Joystick hat event data */
     SDL_JoyButtonEvent jbutton;             /**< Joystick button event data */
     SDL_JoyDeviceEvent jdevice;             /**< Joystick device change event data */
+    SDL_JoyBatteryEvent jbattery;           /**< Joystick battery event data */
     SDL_ControllerAxisEvent caxis;          /**< Game Controller axis event data */
     SDL_ControllerButtonEvent cbutton;      /**< Game Controller button event data */
     SDL_ControllerDeviceEvent cdevice;      /**< Game Controller device event data */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_filesystem.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_filesystem.h
@@ -92,7 +92,7 @@
  *
  * `C:\\Users\\bob\\AppData\\Roaming\\My Company\\My Program Name\\`
  *
- * On Linux, the string might look like"
+ * On Linux, the string might look like:
  *
  * `/home/bob/.local/share/My Program Name/`
  *
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_gamecontroller.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_gamecontroller.h
@@ -69,7 +69,11 @@
     SDL_CONTROLLER_TYPE_VIRTUAL,
     SDL_CONTROLLER_TYPE_PS5,
     SDL_CONTROLLER_TYPE_AMAZON_LUNA,
-    SDL_CONTROLLER_TYPE_GOOGLE_STADIA
+    SDL_CONTROLLER_TYPE_GOOGLE_STADIA,
+    SDL_CONTROLLER_TYPE_NVIDIA_SHIELD,
+    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT,
+    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT,
+    SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
 } SDL_GameControllerType;
 
 typedef enum
@@ -290,6 +294,25 @@
 extern DECLSPEC const char *SDLCALL SDL_GameControllerNameForIndex(int joystick_index);
 
 /**
+ * Get the implementation dependent path for the game controller.
+ *
+ * This function can be called before any controllers are opened.
+ *
+ * `joystick_index` is the same as the `device_index` passed to
+ * SDL_JoystickOpen().
+ *
+ * \param joystick_index the device_index of a device, from zero to
+ *                       SDL_NumJoysticks()-1
+ * \returns the implementation-dependent path for the game controller, or NULL
+ *          if there is no path or the index is invalid.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GameControllerPath
+ */
+extern DECLSPEC const char *SDLCALL SDL_GameControllerPathForIndex(int joystick_index);
+
+/**
  * Get the type of a game controller.
  *
  * This can be called before any controllers are opened.
@@ -387,6 +410,23 @@
 extern DECLSPEC const char *SDLCALL SDL_GameControllerName(SDL_GameController *gamecontroller);
 
 /**
+ * Get the implementation-dependent path for an opened game controller.
+ *
+ * This is the same path as returned by SDL_GameControllerNameForIndex(), but
+ * it takes a controller identifier instead of the (unstable) device index.
+ *
+ * \param gamecontroller a game controller identifier previously returned by
+ *                       SDL_GameControllerOpen()
+ * \returns the implementation dependent path for the game controller, or NULL
+ *          if there is no path or the identifier passed is invalid.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GameControllerPathForIndex
+ */
+extern DECLSPEC const char *SDLCALL SDL_GameControllerPath(SDL_GameController *gamecontroller);
+
+/**
  * Get the type of this currently opened controller
  *
  * This is the same name as returned by SDL_GameControllerTypeForIndex(), but
@@ -415,7 +455,8 @@
  * Set the player index of an opened game controller.
  *
  * \param gamecontroller the game controller object to adjust.
- * \param player_index Player index to assign to this controller.
+ * \param player_index Player index to assign to this controller, or -1 to
+ *                     clear the player index and turn off player LEDs.
  *
  * \since This function is available since SDL 2.0.12.
  */
@@ -456,6 +497,18 @@
  * \since This function is available since SDL 2.0.6.
  */
 extern DECLSPEC Uint16 SDLCALL SDL_GameControllerGetProductVersion(SDL_GameController *gamecontroller);
+
+/**
+ * Get the firmware version of an opened controller, if available.
+ *
+ * If the firmware version isn't available this function returns 0.
+ *
+ * \param gamecontroller the game controller object to query.
+ * \return the controller firmware version, or zero if unavailable.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC Uint16 SDLCALL SDL_GameControllerGetFirmwareVersion(SDL_GameController *gamecontroller);
 
 /**
  * Get the serial number of an opened controller, if available.
--- /dev/null
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_guid.h
@@ -1,0 +1,100 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/**
+ *  \file SDL_guid.h
+ *
+ *  Include file for handling ::SDL_GUID values.
+ */
+
+#ifndef SDL_guid_h_
+#define SDL_guid_h_
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * An SDL_GUID is a 128-bit identifier for an input device that
+ *   identifies that device across runs of SDL programs on the same
+ *   platform.  If the device is detached and then re-attached to a
+ *   different port, or if the base system is rebooted, the device
+ *   should still report the same GUID.
+ *
+ * GUIDs are as precise as possible but are not guaranteed to
+ *   distinguish physically distinct but equivalent devices.  For
+ *   example, two game controllers from the same vendor with the same
+ *   product ID and revision may have the same GUID.
+ *
+ * GUIDs may be platform-dependent (i.e., the same device may report
+ *   different GUIDs on different operating systems).
+ */
+typedef struct {
+    Uint8 data[16];
+} SDL_GUID;
+
+/* Function prototypes */
+
+/**
+ * Get an ASCII string representation for a given ::SDL_GUID.
+ *
+ * You should supply at least 33 bytes for pszGUID.
+ *
+ * \param guid the ::SDL_GUID you wish to convert to string
+ * \param pszGUID buffer in which to write the ASCII string
+ * \param cbGUID the size of pszGUID
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GUIDFromString
+ */
+extern DECLSPEC void SDLCALL SDL_GUIDToString(SDL_GUID guid, char *pszGUID, int cbGUID);
+
+/**
+ * Convert a GUID string into a ::SDL_GUID structure.
+ *
+ * Performs no error checking. If this function is given a string containing
+ * an invalid GUID, the function will silently succeed, but the GUID generated
+ * will not be useful.
+ *
+ * \param pchGUID string containing an ASCII representation of a GUID
+ * \returns a ::SDL_GUID structure.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GUIDToString
+ */
+extern DECLSPEC SDL_GUID SDLCALL SDL_GUIDFromString(const char *pchGUID);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* SDL_guid_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_hints.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_hints.h
@@ -392,13 +392,14 @@
 #define SDL_HINT_ENABLE_STEAM_CONTROLLERS "SDL_ENABLE_STEAM_CONTROLLERS"
 
 /**
- *  \brief  A variable controlling whether SDL logs all events pushed onto its internal queue.
+ *  \brief  A variable controlling verbosity of the logging of SDL events pushed onto the internal queue.
  *
- *  This variable can be set to the following values:
+ *  This variable can be set to the following values, from least to most verbose:
  *
  *    "0"     - Don't log any events (default)
- *    "1"     - Log all events except mouse and finger motion, which are pretty spammy.
- *    "2"     - Log all events.
+ *    "1"     - Log most events (other than the really spammy ones).
+ *    "2"     - Include mouse and finger motion events.
+ *    "3"     - Include SDL_SysWMEvent events.
  *
  *  This is generally meant to be used to debug SDL itself, but can be useful
  *  for application developers that need better visibility into what is going
@@ -651,18 +652,27 @@
  */
 #define SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE "SDL_JOYSTICK_GAMECUBE_RUMBLE_BRAKE"
 
- /**
-  *  \brief  A variable controlling whether Switch Joy-Cons should be treated the same as Switch Pro Controllers when using the HIDAPI driver.
+/**
+  *  \brief  A variable controlling whether the HIDAPI driver for Nintendo Switch Joy-Cons should be used.
   *
   *  This variable can be set to the following values:
-  *    "0"       - basic Joy-Con support with no analog input (the default)
-  *    "1"       - Joy-Cons treated as half full Pro Controllers with analog inputs and sensors
+  *    "0"       - HIDAPI driver is not used
+  *    "1"       - HIDAPI driver is used
   *
-  *  This does not combine Joy-Cons into a single controller. That's up to the user.
+  *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
   */
 #define SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS "SDL_JOYSTICK_HIDAPI_JOY_CONS"
 
- /**
+/**
+  *  \brief  A variable controlling whether Nintendo Switch Joy-Con controllers will be combined into a single Pro-like controller when using the HIDAPI driver
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - Left and right Joy-Con controllers will not be combined and each will be a mini-gamepad
+  *    "1"       - Left and right Joy-Con controllers will be combined into a single controller (the default)
+  */
+#define SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS "SDL_JOYSTICK_HIDAPI_COMBINE_JOY_CONS"
+
+/**
   *  \brief  A variable controlling whether the HIDAPI driver for Amazon Luna controllers connected via Bluetooth should be used.
   *
   *  This variable can be set to the following values:
@@ -674,6 +684,28 @@
 #define SDL_HINT_JOYSTICK_HIDAPI_LUNA "SDL_JOYSTICK_HIDAPI_LUNA"
 
 /**
+  *  \brief  A variable controlling whether the HIDAPI driver for Nintendo Online classic controllers should be used.
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - HIDAPI driver is not used
+  *    "1"       - HIDAPI driver is used
+  *
+  *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+  */
+#define SDL_HINT_JOYSTICK_HIDAPI_NINTENDO_CLASSIC "SDL_JOYSTICK_HIDAPI_NINTENDO_CLASSIC"
+
+/**
+  *  \brief  A variable controlling whether the HIDAPI driver for NVIDIA SHIELD controllers should be used.
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - HIDAPI driver is not used
+  *    "1"       - HIDAPI driver is used
+  *
+  *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+  */
+#define SDL_HINT_JOYSTICK_HIDAPI_SHIELD "SDL_JOYSTICK_HIDAPI_SHIELD"
+
+/**
  *  \brief  A variable controlling whether the HIDAPI driver for PS4 controllers should be used.
  *
  *  This variable can be set to the following values:
@@ -778,17 +810,37 @@
 #define SDL_HINT_JOYSTICK_HIDAPI_SWITCH "SDL_JOYSTICK_HIDAPI_SWITCH"
 
 /**
- *  \brief  A variable controlling whether the Home button LED should be turned on when a Nintendo Switch controller is opened
+ *  \brief  A variable controlling whether the Home button LED should be turned on when a Nintendo Switch Pro controller is opened
  *
  *  This variable can be set to the following values:
  *    "0"       - home button LED is turned off
  *    "1"       - home button LED is turned on
  *
- *  By default the Home button LED state is not changed.
+ *  By default the Home button LED state is not changed. This hint can also be set to a floating point value between 0.0 and 1.0 which controls the brightness of the Home button LED.
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED "SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED"
 
 /**
+ *  \brief  A variable controlling whether the Home button LED should be turned on when a Nintendo Switch Joy-Con controller is opened
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - home button LED is turned off
+ *    "1"       - home button LED is turned on
+ *
+ *  By default the Home button LED state is not changed. This hint can also be set to a floating point value between 0.0 and 1.0 which controls the brightness of the Home button LED.
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED "SDL_JOYSTICK_HIDAPI_JOYCON_HOME_LED"
+
+/**
+ *  \brief  A variable controlling whether the player LEDs should be lit to indicate which player is associated with a Nintendo Switch controller.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - player LEDs are not enabled
+ *    "1"       - player LEDs are enabled (the default)
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED "SDL_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED"
+
+/**
  *  \brief  A variable controlling whether the HIDAPI driver for XBox controllers should be used.
  *
  *  This variable can be set to the following values:
@@ -799,7 +851,7 @@
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_XBOX   "SDL_JOYSTICK_HIDAPI_XBOX"
 
- /**
+/**
   *  \brief  A variable controlling whether the RAWINPUT joystick drivers should be used for better handling XInput-capable devices.
   *
   *  This variable can be set to the following values:
@@ -808,7 +860,7 @@
   */
 #define SDL_HINT_JOYSTICK_RAWINPUT "SDL_JOYSTICK_RAWINPUT"
 
- /**
+/**
   *  \brief  A variable controlling whether the RAWINPUT driver should pull correlated data from XInput.
   *
   *  This variable can be set to the following values:
@@ -821,7 +873,7 @@
   */
 #define SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT   "SDL_JOYSTICK_RAWINPUT_CORRELATE_XINPUT"
 
- /**
+/**
   *  \brief  A variable controlling whether the ROG Chakram mice should show up as joysticks
   *
   *  This variable can be set to the following values:
@@ -830,7 +882,7 @@
   */
 #define SDL_HINT_JOYSTICK_ROG_CHAKRAM "SDL_JOYSTICK_ROG_CHAKRAM"
 
- /**
+/**
   *  \brief  A variable controlling whether a separate thread should be used
   *          for handling joystick detection and raw input messages on Windows
   *
@@ -864,7 +916,7 @@
  */
 #define SDL_HINT_KMSDRM_REQUIRE_DRM_MASTER      "SDL_KMSDRM_REQUIRE_DRM_MASTER"
 
- /**
+/**
   *  \brief  A comma separated list of devices to open as joysticks
   *
   *  This variable is currently only used by the Linux joystick driver.
@@ -871,7 +923,25 @@
   */
 #define SDL_HINT_JOYSTICK_DEVICE "SDL_JOYSTICK_DEVICE"
 
- /**
+/**
+  *  \brief  A variable controlling whether joysticks on Linux will always treat 'hat' axis inputs (ABS_HAT0X - ABS_HAT3Y) as 8-way digital hats without checking whether they may be analog.
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - Only map hat axis inputs to digital hat outputs if the input axes appear to actually be digital (the default)
+  *    "1"       - Always handle the input axes numbered ABS_HAT0X to ABS_HAT3Y as digital hats
+  */
+#define SDL_HINT_LINUX_DIGITAL_HATS "SDL_LINUX_DIGITAL_HATS"
+
+/**
+  *  \brief  A variable controlling whether digital hats on Linux will apply deadzones to their underlying input axes or use unfiltered values.
+  *
+  *  This variable can be set to the following values:
+  *    "0"       - Return digital hat values based on unfiltered input axis values
+  *    "1"       - Return digital hat values with deadzones on the input axes taken into account (the default)
+  */
+#define SDL_HINT_LINUX_HAT_DEADZONES "SDL_LINUX_HAT_DEADZONES"
+
+/**
   *  \brief  A variable controlling whether to use the classic /dev/input/js* joystick interface or the newer /dev/input/event* joystick interface on Linux
   *
   *  This variable can be set to the following values:
@@ -882,7 +952,7 @@
   */
 #define SDL_HINT_LINUX_JOYSTICK_CLASSIC "SDL_LINUX_JOYSTICK_CLASSIC"
 
- /**
+/**
   *  \brief  A variable controlling whether joysticks on Linux adhere to their HID-defined deadzones or return unfiltered values.
   *
   *  This variable can be set to the following values:
@@ -908,6 +978,24 @@
 #define SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK "SDL_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK"
 
 /**
+ *  \brief   A variable controlling whether dispatching OpenGL context updates should block the dispatching thread until the main thread finishes processing
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Dispatching OpenGL context updates will block the dispatching thread until the main thread finishes processing (default).
+ *    "1"       - Dispatching OpenGL context updates will allow the dispatching thread to continue execution.
+ *
+ *  Generally you want the default, but if you have OpenGL code in a background thread on a Mac, and the main thread
+ *  hangs because it's waiting for that background thread, but that background thread is also hanging because it's
+ *  waiting for the main thread to do an update, this might fix your issue.
+ *
+ *  This hint only applies to macOS.
+ *
+ *  This hint is available since SDL 2.24.0.
+ *
+ */
+#define SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH "SDL_MAC_OPENGL_ASYNC_DISPATCH"
+
+/**
  *  \brief  A variable setting the double click radius, in pixels.
  */
 #define SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS    "SDL_MOUSE_DOUBLE_CLICK_RADIUS"
@@ -977,6 +1065,17 @@
 #define SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE    "SDL_MOUSE_RELATIVE_SPEED_SCALE"
 
 /**
+ *  \brief  A variable controlling whether a motion event should be generated for mouse warping in relative mode.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Warping the mouse will not generate a motion event in relative mode
+ *    "1"       - Warping the mouse will generate a motion event in relative mode
+ *
+ *  By default warping the mouse will not generate motion events in relative mode. This avoids the application having to filter out large relative motion due to warping.
+ */
+#define SDL_HINT_MOUSE_RELATIVE_WARP_MOTION  "SDL_MOUSE_RELATIVE_WARP_MOTION"
+
+/**
  *  \brief  A variable controlling whether mouse events should generate synthetic touch events
  *
  *  This variable can be set to the following values:
@@ -1181,6 +1280,8 @@
  *
  *  This variable is case insensitive and can be set to the following values:
  *    "direct3d"
+ *    "direct3d11"
+ *    "direct3d12"
  *    "opengl"
  *    "opengles2"
  *    "opengles"
@@ -1237,7 +1338,7 @@
  */
 #define SDL_HINT_RENDER_VSYNC               "SDL_RENDER_VSYNC"
 
- /**
+/**
  * \brief A variable to control whether the return key on the soft keyboard
  *        should hide the soft keyboard on Android and iOS.
  *
@@ -1450,9 +1551,7 @@
  *                SDL_WINDOW_RESIZABLE windows will offer the "fullscreen"
  *                button on their titlebars).
  *
- *  The default value is "1". Spaces are disabled regardless of this hint if
- *   the OS isn't at least Mac OS X Lion (10.7). This hint must be set before
- *   any windows are created.
+ *  The default value is "1". This hint must be set before any windows are created.
  */
 #define SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES    "SDL_VIDEO_MAC_FULLSCREEN_SPACES"
 
@@ -1490,6 +1589,21 @@
 #define SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR "SDL_VIDEO_WAYLAND_PREFER_LIBDECOR"
 
 /**
+ *  \brief  A variable controlling whether video mode emulation is enabled under Wayland.
+ *
+ *  When this hint is set, a standard set of emulated CVT video modes will be exposed for use by the application.
+ *  If it is disabled, the only modes exposed will be the logical desktop size and, in the case of a scaled
+ *  desktop, the native display resolution.
+ *
+ *  This variable can be set to the following values:
+ *    "0"       - Video mode emulation is disabled.
+ *    "1"       - Video mode emulation is enabled.
+ *
+ *  By default video mode emulation is enabled.
+ */
+#define SDL_HINT_VIDEO_WAYLAND_MODE_EMULATION "SDL_VIDEO_WAYLAND_MODE_EMULATION"
+
+/**
 *  \brief  A variable that is the address of another SDL_Window* (as a hex string formatted with "%p").
 *  
 *  If this hint is set before SDL_CreateWindowFrom() and the SDL_Window* it is set to has
@@ -1590,13 +1704,11 @@
 #define SDL_HINT_VIDEO_X11_WINDOW_VISUALID      "SDL_VIDEO_X11_WINDOW_VISUALID"
 
 /**
- *  \brief  A variable controlling whether the X11 Xinerama extension should be used.
+ *  \brief  A no-longer-used variable controlling whether the X11 Xinerama extension should be used.
  *
- *  This variable can be set to the following values:
- *    "0"       - Disable Xinerama
- *    "1"       - Enable Xinerama
- *
- *  By default SDL will use Xinerama if it is available.
+ * Before SDL 2.0.24, this would let apps and users disable Xinerama support on X11.
+ *  Now SDL never uses Xinerama, and does not check for this hint at all.
+ *  The preprocessor define is left here for source compatibility.
  */
 #define SDL_HINT_VIDEO_X11_XINERAMA         "SDL_VIDEO_X11_XINERAMA"
 
@@ -1607,18 +1719,16 @@
  *    "0"       - Disable XRandR
  *    "1"       - Enable XRandR
  *
- *  By default SDL will not use XRandR because of window manager issues.
+ *  By default SDL will use XRandR.
  */
 #define SDL_HINT_VIDEO_X11_XRANDR           "SDL_VIDEO_X11_XRANDR"
 
 /**
- *  \brief  A variable controlling whether the X11 VidMode extension should be used.
+ *  \brief  A no-longer-used variable controlling whether the X11 VidMode extension should be used.
  *
- *  This variable can be set to the following values:
- *    "0"       - Disable XVidMode
- *    "1"       - Enable XVidMode
- *
- *  By default SDL will use XVidMode if it is available.
+ * Before SDL 2.0.24, this would let apps and users disable XVidMode support on X11.
+ *  Now SDL never uses XVidMode, and does not check for this hint at all.
+ *  The preprocessor define is left here for source compatibility.
  */
 #define SDL_HINT_VIDEO_X11_XVIDMODE         "SDL_VIDEO_X11_XVIDMODE"
 
@@ -1779,6 +1889,57 @@
 #define SDL_HINT_WINDOWS_USE_D3D9EX "SDL_WINDOWS_USE_D3D9EX"
 
 /**
+ * \brief Controls whether SDL will declare the process to be DPI aware.
+ *
+ *  This hint must be set before initializing the video subsystem.
+ *
+ *  The main purpose of declaring DPI awareness is to disable OS bitmap scaling of SDL windows on monitors with 
+ *  a DPI scale factor.
+ * 
+ *  This hint is equivalent to requesting DPI awareness via external means (e.g. calling SetProcessDpiAwarenessContext)
+ *  and does not cause SDL to use a virtualized coordinate system, so it will generally give you 1 SDL coordinate = 1 pixel
+ *  even on high-DPI displays.
+ * 
+ *  For more information, see:
+ *  https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
+ * 
+ *  This variable can be set to the following values:
+ *    ""             - Do not change the DPI awareness (default).
+ *    "unaware"      - Declare the process as DPI unaware. (Windows 8.1 and later).
+ *    "system"       - Request system DPI awareness. (Vista and later).
+ *    "permonitor"   - Request per-monitor DPI awareness. (Windows 8.1 and later).
+ *    "permonitorv2" - Request per-monitor V2 DPI awareness. (Windows 10, version 1607 and later).
+ *                     The most visible difference from "permonitor" is that window title bar will be scaled
+ *                     to the visually correct size when dragging between monitors with different scale factors.
+ *                     This is the preferred DPI awareness level.
+ *
+ * If the requested DPI awareness is not available on the currently running OS, SDL will try to request the best
+ * available match.
+ */
+#define SDL_HINT_WINDOWS_DPI_AWARENESS "SDL_WINDOWS_DPI_AWARENESS"
+
+/**
+ * \brief Uses DPI-scaled points as the SDL coordinate system on Windows.
+ * 
+ *  This changes the SDL coordinate system units to be DPI-scaled points, rather than pixels everywhere.
+ *  This means windows will be appropriately sized, even when created on high-DPI displays with scaling.
+ * 
+ *  e.g. requesting a 640x480 window from SDL, on a display with 125% scaling in Windows display settings,
+ *  will create a window with an 800x600 client area (in pixels).
+ *
+ *  Setting this to "1" implicitly requests process DPI awareness (setting SDL_WINDOWS_DPI_AWARENESS is unnecessary),
+ *  and forces SDL_WINDOW_ALLOW_HIGHDPI on all windows.
+ * 
+ *  This variable can be set to the following values:
+ *    "0"       - SDL coordinates equal Windows coordinates. No automatic window resizing when dragging
+ *                between monitors with different scale factors (unless this is performed by
+ *                Windows itself, which is the case when the process is DPI unaware).
+ *    "1"       - SDL coordinates are in DPI-scaled points. Automatically resize windows as needed on
+ *                displays with non-100% scale factors.
+ */
+#define SDL_HINT_WINDOWS_DPI_SCALING "SDL_WINDOWS_DPI_SCALING"
+
+/**
  *  \brief  A variable controlling whether the window frame and title bar are interactive when the cursor is hidden 
  *
  *  This variable can be set to the following values:
@@ -1920,6 +2081,15 @@
  */
 #define SDL_HINT_XINPUT_ENABLED "SDL_XINPUT_ENABLED"
 
+ /**
+  *  \brief  A variable that lets you disable the detection and use of DirectInput gamepad devices
+  *
+  *  The variable can be set to the following values:
+  *    "0"       - Disable DirectInput detection (only uses XInput)
+  *    "1"       - Enable DirectInput detection (the default)
+  */
+#define SDL_HINT_DIRECTINPUT_ENABLED "SDL_DIRECTINPUT_ENABLED"
+
 /**
  *  \brief  A variable that causes SDL to use the old axis and button mapping for XInput devices.
  *
@@ -2039,8 +2209,44 @@
  */
 #define SDL_HINT_AUDIODRIVER "SDL_AUDIODRIVER"
 
+/**
+ *  \brief  A variable that decides what KMSDRM device to use.
+ *
+ *  Internally, SDL might open something like "/dev/dri/cardNN" to
+ *  access KMSDRM functionality, where "NN" is a device index number.
+ *
+ *  SDL makes a guess at the best index to use (usually zero), but the
+ *  app or user can set this hint to a number between 0 and 99 to
+ *  force selection.
+ *
+ *  This hint is available since SDL 2.24.0.
+ */
+#define SDL_HINT_KMSDRM_DEVICE_INDEX "SDL_KMSDRM_DEVICE_INDEX"
 
+
 /**
+ *  \brief  A variable that treats trackpads as touch devices.
+ *
+ *  On macOS (and possibly other platforms in the future), SDL will report
+ *  touches on a trackpad as mouse input, which is generally what users
+ *  expect from this device; however, these are often actually full
+ *  multitouch-capable touch devices, so it might be preferable to some apps
+ *  to treat them as such.
+ *
+ *  Setting this hint to true will make the trackpad input report as a
+ *  multitouch device instead of a mouse. The default is false.
+ *
+ *  Note that most platforms don't support this hint. As of 2.24.0, it
+ *  only supports MacBooks' trackpads on macOS. Others may follow later.
+ *
+ *  This hint is checked during SDL_Init and can not be changed after.
+ *
+ *  This hint is available since SDL 2.24.0.
+ */
+#define SDL_HINT_TRACKPAD_IS_TOUCH_ONLY "SDL_TRACKPAD_IS_TOUCH_ONLY"
+
+
+/**
  *  \brief  An enumeration of hint priorities
  */
 typedef enum
@@ -2090,6 +2296,23 @@
  */
 extern DECLSPEC SDL_bool SDLCALL SDL_SetHint(const char *name,
                                              const char *value);
+
+/**
+ * Reset a hint to the default value.
+ *
+ * This will reset a hint to the value of the environment variable, or NULL if
+ * the environment isn't set. Callbacks will be called normally with this
+ * change.
+ *
+ * \param name the hint to set
+ * \returns SDL_TRUE if the hint was set, SDL_FALSE otherwise.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GetHint
+ * \sa SDL_SetHint
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_ResetHint(const char *name);
 
 /**
  * Get the value of a hint.
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_joystick.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_joystick.h
@@ -43,6 +43,7 @@
 
 #include "SDL_stdinc.h"
 #include "SDL_error.h"
+#include "SDL_guid.h"
 
 #include "begin_code.h"
 /* Set up for C function definitions, even when using C++ */
@@ -69,9 +70,7 @@
 typedef struct _SDL_Joystick SDL_Joystick;
 
 /* A structure that encodes the stable unique id for a joystick device */
-typedef struct {
-    Uint8 data[16];
-} SDL_JoystickGUID;
+typedef SDL_GUID SDL_JoystickGUID;
 
 /**
  * This is a unique ID for a joystick for the time it is connected to the system,
@@ -153,6 +152,7 @@
  * \since This function is available since SDL 2.0.0.
  *
  * \sa SDL_JoystickName
+ * \sa SDL_JoystickPath
  * \sa SDL_JoystickOpen
  */
 extern DECLSPEC int SDLCALL SDL_NumJoysticks(void);
@@ -175,6 +175,23 @@
 extern DECLSPEC const char *SDLCALL SDL_JoystickNameForIndex(int device_index);
 
 /**
+ * Get the implementation dependent path of a joystick.
+ *
+ * This can be called before any joysticks are opened.
+ *
+ * \param device_index the index of the joystick to query (the N'th joystick
+ *                     on the system)
+ * \returns the path of the selected joystick. If no path can be found, this
+ *          function returns NULL; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_JoystickPath
+ * \sa SDL_JoystickOpen
+ */
+extern DECLSPEC const char *SDLCALL SDL_JoystickPathForIndex(int device_index);
+
+/**
  * Get the player index of a joystick, or -1 if it's not available This can be
  * called before any joysticks are opened.
  *
@@ -331,6 +348,54 @@
                                                       int nhats);
 
 /**
+ * The structure that defines an extended virtual joystick description
+ *
+ * The caller must zero the structure and then initialize the version with `SDL_VIRTUAL_JOYSTICK_DESC_VERSION` before passing it to SDL_JoystickAttachVirtualEx()
+ *  All other elements of this structure are optional and can be left 0.
+ *
+ * \sa SDL_JoystickAttachVirtualEx
+ */
+typedef struct SDL_VirtualJoystickDesc
+{
+    Uint16 version;     /**< `SDL_VIRTUAL_JOYSTICK_DESC_VERSION` */
+    Uint16 type;        /**< `SDL_JoystickType` */
+    Uint16 naxes;       /**< the number of axes on this joystick */
+    Uint16 nbuttons;    /**< the number of buttons on this joystick */
+    Uint16 nhats;       /**< the number of hats on this joystick */
+    Uint16 vendor_id;   /**< the USB vendor ID of this joystick */
+    Uint16 product_id;  /**< the USB product ID of this joystick */
+    Uint16 padding;     /**< unused */
+    Uint32 button_mask; /**< A mask of which buttons are valid for this controller
+                             e.g. (1 << SDL_CONTROLLER_BUTTON_A) */
+    Uint32 axis_mask;   /**< A mask of which axes are valid for this controller
+                             e.g. (1 << SDL_CONTROLLER_AXIS_LEFTX) */
+    const char *name;   /**< the name of the joystick */
+
+    void *userdata;     /**< User data pointer passed to callbacks */
+    void (SDLCALL *Update)(void *userdata); /**< Called when the joystick state should be updated */
+    void (SDLCALL *SetPlayerIndex)(void *userdata, int player_index); /**< Called when the player index is set */
+    int (SDLCALL *Rumble)(void *userdata, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble); /**< Implements SDL_JoystickRumble() */
+    int (SDLCALL *RumbleTriggers)(void *userdata, Uint16 left_rumble, Uint16 right_rumble); /**< Implements SDL_JoystickRumbleTriggers() */
+    int (SDLCALL *SetLED)(void *userdata, Uint8 red, Uint8 green, Uint8 blue); /**< Implements SDL_JoystickSetLED() */
+    int (SDLCALL *SendEffect)(void *userdata, const void *data, int size); /**< Implements SDL_JoystickSendEffect() */
+
+} SDL_VirtualJoystickDesc;
+
+/**
+ * \brief The current version of the SDL_VirtualJoystickDesc structure
+ */
+#define SDL_VIRTUAL_JOYSTICK_DESC_VERSION   1
+
+/**
+ * Attach a new virtual joystick with extended properties.
+ *
+ * \returns the joystick's device index, or -1 if an error occurred.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickAttachVirtualEx(const SDL_VirtualJoystickDesc *desc);
+
+/**
  * Detach a virtual joystick.
  *
  * \param device_index a value previously returned from
@@ -420,6 +485,19 @@
 extern DECLSPEC const char *SDLCALL SDL_JoystickName(SDL_Joystick *joystick);
 
 /**
+ * Get the implementation dependent path of a joystick.
+ *
+ * \param joystick the SDL_Joystick obtained from SDL_JoystickOpen()
+ * \returns the path of the selected joystick. If no path can be found, this
+ *          function returns NULL; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_JoystickPathForIndex
+ */
+extern DECLSPEC const char *SDLCALL SDL_JoystickPath(SDL_Joystick *joystick);
+
+/**
  * Get the player index of an opened joystick.
  *
  * For XInput controllers this returns the XInput user index. Many joysticks
@@ -436,7 +514,8 @@
  * Set the player index of an opened joystick.
  *
  * \param joystick the SDL_Joystick obtained from SDL_JoystickOpen()
- * \param player_index the player index to set.
+ * \param player_index Player index to assign to this joystick, or -1 to clear
+ *                     the player index and turn off player LEDs.
  *
  * \since This function is available since SDL 2.0.12.
  */
@@ -494,6 +573,19 @@
  * \since This function is available since SDL 2.0.6.
  */
 extern DECLSPEC Uint16 SDLCALL SDL_JoystickGetProductVersion(SDL_Joystick *joystick);
+
+/**
+ * Get the firmware version of an opened joystick, if available.
+ *
+ * If the firmware version isn't available this function returns 0.
+ *
+ * \param joystick the SDL_Joystick obtained from SDL_JoystickOpen()
+ * \returns the firmware version of the selected joystick, or 0 if
+ *          unavailable.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC Uint16 SDLCALL SDL_JoystickGetFirmwareVersion(SDL_Joystick *joystick);
 
 /**
  * Get the serial number of an opened joystick, if available.
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_keyboard.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_keyboard.h
@@ -90,10 +90,22 @@
  * \since This function is available since SDL 2.0.0.
  *
  * \sa SDL_PumpEvents
+ * \sa SDL_ResetKeyboard
  */
 extern DECLSPEC const Uint8 *SDLCALL SDL_GetKeyboardState(int *numkeys);
 
 /**
+ * Clear the state of the keyboard
+ *
+ * This function will generate key up events for all pressed keys.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GetKeyboardState
+ */
+extern DECLSPEC void SDLCALL SDL_ResetKeyboard(void);
+
+/**
  * Get the current key modifier state for the keyboard.
  *
  * \returns an OR'd combination of the modifier keys for the keyboard. See
@@ -288,7 +300,11 @@
 /**
  * Set the rectangle used to type Unicode text inputs.
  *
- * Note: If you want use system native IME window, try to set hint
+ * To start text input in a given location, this function is intended to be
+ * called before SDL_StartTextInput, although some platforms support moving
+ * the rectangle even while text input (and a composition) is active.
+ *
+ * Note: If you want to use the system native IME window, try setting hint
  * **SDL_HINT_IME_SHOW_UI** to **1**, otherwise this function won't give you
  * any feedback.
  *
@@ -299,7 +315,7 @@
  *
  * \sa SDL_StartTextInput
  */
-extern DECLSPEC void SDLCALL SDL_SetTextInputRect(SDL_Rect *rect);
+extern DECLSPEC void SDLCALL SDL_SetTextInputRect(const SDL_Rect *rect);
 
 /**
  * Check whether the platform has screen keyboard support.
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_keycode.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_keycode.h
@@ -318,7 +318,12 @@
     SDLK_APP2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_APP2),
 
     SDLK_AUDIOREWIND = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOREWIND),
-    SDLK_AUDIOFASTFORWARD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOFASTFORWARD)
+    SDLK_AUDIOFASTFORWARD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOFASTFORWARD),
+
+    SDLK_SOFTLEFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SOFTLEFT),
+    SDLK_SOFTRIGHT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SOFTRIGHT),
+    SDLK_CALL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CALL),
+    SDLK_ENDCALL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_ENDCALL)
 } SDL_KeyCode;
 
 /**
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_log.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_log.h
@@ -47,9 +47,9 @@
 
 
 /**
- *  \brief The maximum size of a log message
+ *  \brief The maximum size of a log message prior to SDL 2.0.24
  *
- *  Messages longer than the maximum size will be truncated
+ *  As of 2.0.24 there is no limit to the length of SDL log messages.
  */
 #define SDL_MAX_LOG_MESSAGE 4096
 
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_main.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_main.h
@@ -51,6 +51,15 @@
 */
 #define SDL_MAIN_NEEDED
 
+#elif defined(__GDK__)
+/* On GDK, SDL provides a main function that initializes the game runtime.
+
+   Please note that #include'ing SDL_main.h is not enough to get a main()
+   function working. You must either link against SDL2main or, if not possible,
+   call the SDL_GDKRunApp function from your entry point.
+*/
+#define SDL_MAIN_NEEDED
+
 #elif defined(__IPHONEOS__)
 /* On iOS SDL provides a main function that creates an application delegate
    and starts the iOS application run loop.
@@ -92,6 +101,13 @@
  */
 #define SDL_MAIN_AVAILABLE
 
+#elif defined(__PS2__)
+#define SDL_MAIN_AVAILABLE
+
+#define SDL_PS2_SKIP_IOP_RESET() \
+   void reset_IOP(); \
+   void reset_IOP() {}
+
 #endif
 #endif /* SDL_MAIN_HANDLED */
 
@@ -145,7 +161,7 @@
  */
 extern DECLSPEC void SDLCALL SDL_SetMainReady(void);
 
-#ifdef __WIN32__
+#if defined(__WIN32__) || defined(__GDK__)
 
 /**
  * Register a win32 window class for SDL's use.
@@ -189,7 +205,7 @@
  */
 extern DECLSPEC void SDLCALL SDL_UnregisterApp(void);
 
-#endif /* __WIN32__ */
+#endif /* defined(__WIN32__) || defined(__GDK__) */
 
 
 #ifdef __WINRT__
@@ -224,6 +240,21 @@
 
 #endif /* __IPHONEOS__ */
 
+#ifdef __GDK__
+
+/**
+ * Initialize and launch an SDL GDK application.
+ *
+ * \param mainFunction the SDL app's C-style main(), an SDL_main_func
+ * \param reserved reserved for future use; should be NULL
+ * \returns 0 on success or -1 on failure; call SDL_GetError() to retrieve
+ *          more information on the failure.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC int SDLCALL SDL_GDKRunApp(SDL_main_func mainFunction, void *reserved);
+
+#endif /* __GDK__ */
 
 #ifdef __cplusplus
 }
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_mouse.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_mouse.h
@@ -154,7 +154,9 @@
 /**
  * Move the mouse cursor to the given position within the window.
  *
- * This function generates a mouse motion event.
+ * This function generates a mouse motion event if relative mode is not
+ * enabled. If relative mode is enabled, you can force mouse events for the
+ * warp by setting the SDL_HINT_MOUSE_RELATIVE_WARP_MOTION hint.
  *
  * Note that this function will appear to succeed, but not actually move the
  * mouse when used over Microsoft Remote Desktop.
@@ -244,6 +246,15 @@
  *
  * While capturing is enabled, the current window will have the
  * `SDL_WINDOW_MOUSE_CAPTURE` flag set.
+ *
+ * Please note that as of SDL 2.0.22, SDL will attempt to "auto capture" the
+ * mouse while the user is pressing a button; this is to try and make mouse
+ * behavior more consistent between platforms, and deal with the common case
+ * of a user dragging the mouse outside of the window. This means that if you
+ * are calling SDL_CaptureMouse() only to deal with this situation, you no
+ * longer have to (although it is safe to do so). If this causes problems for
+ * your app, you can disable auto capture by setting the
+ * `SDL_HINT_MOUSE_AUTO_CAPTURE` hint to zero.
  *
  * \param enabled SDL_TRUE to enable capturing, SDL_FALSE to disable.
  * \returns 0 on success or -1 if not supported; call SDL_GetError() for more
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_platform.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_platform.h
@@ -65,11 +65,15 @@
 #undef __LINUX__ /* do we need to do this? */
 #define __ANDROID__ 1
 #endif
+#if defined(__NGAGE__)
+#undef __NGAGE__
+#define __NGAGE__ 1
+#endif
 
 #if defined(__APPLE__)
 /* lets us know what version of Mac OS X we're compiling on */
-#include "AvailabilityMacros.h"
-#include "TargetConditionals.h"
+#include <AvailabilityMacros.h>
+#include <TargetConditionals.h>
 
 /* Fix building with older SDKs that don't define these
    See this for more information:
@@ -104,9 +108,9 @@
 /* if not compiling for iOS */
 #undef __MACOSX__
 #define __MACOSX__  1
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
-# error SDL for Mac OS X only supports deploying on 10.6 and above.
-#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+# error SDL for Mac OS X only supports deploying on 10.7 and above.
+#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1070 */
 #endif /* TARGET_OS_IPHONE */
 #endif /* defined(__APPLE__) */
 
@@ -140,7 +144,7 @@
 #endif
 
 #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
-/* Try to find out if we're compiling for WinRT or non-WinRT */
+/* Try to find out if we're compiling for WinRT, GDK or non-WinRT/GDK */
 #if defined(_MSC_VER) && defined(__has_include)
 #if __has_include(<winapifamily.h>)
 #define HAVE_WINAPIFAMILY_H 1
@@ -165,6 +169,15 @@
 #if WINAPI_FAMILY_WINRT
 #undef __WINRT__
 #define __WINRT__ 1
+#elif defined(_GAMING_DESKTOP) /* GDK project configuration always defines _GAMING_XXX */
+#undef __WINGDK__
+#define __WINGDK__ 1
+#elif defined(_GAMING_XBOX_XBOXONE)
+#undef __XBOXONE__
+#define __XBOXONE__ 1
+#elif defined(_GAMING_XBOX_SCARLETT)
+#undef __XBOXSERIES__
+#define __XBOXSERIES__ 1
 #else
 #undef __WINDOWS__
 #define __WINDOWS__ 1
@@ -175,9 +188,17 @@
 #undef __WIN32__
 #define __WIN32__ 1
 #endif
+/* This is to support generic "any GDK" separate from a platform-specific GDK */
+#if defined(__WINGDK__) || defined(__XBOXONE__) || defined(__XBOXSERIES__)
+#undef __GDK__
+#define __GDK__ 1
+#endif
 #if defined(__PSP__)
 #undef __PSP__
 #define __PSP__ 1
+#endif
+#if defined(PS2)
+#define __PS2__ 1
 #endif
 
 /* The NACL compiler defines __native_client__ and __pnacl__
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_rect.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_rect.h
@@ -252,10 +252,10 @@
 SDL_FORCE_INLINE SDL_bool SDL_FRectEqualsEpsilon(const SDL_FRect *a, const SDL_FRect *b, const float epsilon)
 {
     return (a && b && ((a == b) ||
-            ((SDL_fabs(a->x - b->x) <= epsilon) &&
-            (SDL_fabs(a->y - b->y) <= epsilon) &&
-            (SDL_fabs(a->w - b->w) <= epsilon) &&
-            (SDL_fabs(a->h - b->h) <= epsilon))))
+            ((SDL_fabsf(a->x - b->x) <= epsilon) &&
+            (SDL_fabsf(a->y - b->y) <= epsilon) &&
+            (SDL_fabsf(a->w - b->w) <= epsilon) &&
+            (SDL_fabsf(a->h - b->h) <= epsilon))))
             ? SDL_TRUE : SDL_FALSE;
 }
 
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_render.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_render.h
@@ -825,10 +825,14 @@
 /**
  * Get device independent resolution for rendering.
  *
- * This may return 0 for `w` and `h` if the SDL_Renderer has never had its
- * logical size set by SDL_RenderSetLogicalSize() and never had a render
- * target set.
+ * When using the main rendering target (eg no target texture is set): this
+ * may return 0 for `w` and `h` if the SDL_Renderer has never had its logical
+ * size set by SDL_RenderSetLogicalSize(). Otherwise it returns the logical
+ * width and height.
  *
+ * When using a target texture: Never return 0 for `w` and `h` at first. Then
+ * it returns the logical width and height that are set.
+ *
  * \param renderer a rendering context
  * \param w an int to be filled with the width
  * \param h an int to be filled with the height
@@ -1000,7 +1004,7 @@
  * and logical renderer size set
  *
  * \param renderer the renderer from which the logical coordinates should be
- *                 calcualted
+ *                 calculated
  * \param windowX the real X coordinate in the window
  * \param windowY the real Y coordinate in the window
  * \param logicalX the pointer filled with the logical x coordinate
@@ -1017,19 +1021,23 @@
                                                             int windowX, int windowY, 
                                                             float *logicalX, float *logicalY);
                                                   
-                                                  /**
- * Get real coordinates of point in window when given logical coordinates of point in renderer.
- * Logical coordinates will differ from real coordinates when render is scaled and logical renderer size set
- * 
- * \param renderer the renderer from which the window coordinates should be calculated
+
+/**
+ * Get real coordinates of point in window when given logical coordinates of
+ * point in renderer.
+ *
+ * Logical coordinates will differ from real coordinates when render is scaled
+ * and logical renderer size set
+ *
+ * \param renderer the renderer from which the window coordinates should be
+ *                 calculated
  * \param logicalX the logical x coordinate
  * \param logicalY the logical y coordinate
  * \param windowX the pointer filled with the real X coordinate in the window
  * \param windowY the pointer filled with the real Y coordinate in the window
- 
- *  
+ *
  * \since This function is available since SDL 2.0.18.
- * 
+ *
  * \sa SDL_RenderGetScale
  * \sa SDL_RenderSetScale
  * \sa SDL_RenderGetLogicalSize
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_revision.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_revision.h
@@ -1,2 +1,2 @@
-#define SDL_REVISION "https://github.com/libsdl-org/SDL.git@53dea9830964eee8b5c2a7ee0a65d6e268dc78a1"
+#define SDL_REVISION "https://github.com/libsdl-org/SDL.git@a1d1946dcba6509f0679f507b57e7b228d32e6f8"
 #define SDL_REVISION_NUMBER 0
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_rwops.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_rwops.h
@@ -45,9 +45,6 @@
 #define SDL_RWOPS_JNIFILE   3U  /**< Android asset */
 #define SDL_RWOPS_MEMORY    4U  /**< Memory stream */
 #define SDL_RWOPS_MEMORY_RO 5U  /**< Read-Only memory stream */
-#if defined(__VITA__)
-#define SDL_RWOPS_VITAFILE  6U  /**< Vita file */
-#endif
 
 /**
  * This is the read/write operation structure -- very basic.
@@ -101,7 +98,7 @@
         {
             void *asset;
         } androidio;
-#elif defined(__WIN32__)
+#elif defined(__WIN32__) || defined(__GDK__)
         struct
         {
             SDL_bool append;
@@ -113,17 +110,6 @@
                 size_t left;
             } buffer;
         } windowsio;
-#elif defined(__VITA__)
-        struct
-        {
-            int h;
-            struct
-            {
-                void *data;
-                size_t size;
-                size_t left;
-            } buffer;
-        } vitaio;
 #endif
 
 #ifdef HAVE_STDIO_H
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_scancode.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_scancode.h
@@ -402,6 +402,26 @@
 
     /* @} *//* Usage page 0x0C (additional media keys) */
 
+    /**
+     *  \name Mobile keys
+     *
+     *  These are values that are often used on mobile phones.
+     */
+    /* @{ */
+
+    SDL_SCANCODE_SOFTLEFT = 287, /**< Usually situated below the display on phones and
+                                      used as a multi-function feature key for selecting
+                                      a software defined function shown on the bottom left
+                                      of the display. */
+    SDL_SCANCODE_SOFTRIGHT = 288, /**< Usually situated below the display on phones and
+                                       used as a multi-function feature key for selecting
+                                       a software defined function shown on the bottom right
+                                       of the display. */
+    SDL_SCANCODE_CALL = 289, /**< Used for accepting phone calls. */
+    SDL_SCANCODE_ENDCALL = 290, /**< Used for rejecting phone calls. */
+
+    /* @} *//* Mobile keys */
+
     /* Add any other keys here. */
 
     SDL_NUM_SCANCODES = 512 /**< not a key, just marks the number of scancodes
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_stdinc.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_stdinc.h
@@ -115,6 +115,12 @@
 # endif
 #endif
 
+#ifdef SIZE_MAX
+# define SDL_SIZE_MAX SIZE_MAX
+#else
+# define SDL_SIZE_MAX ((size_t) -1)
+#endif
+
 /**
  * Check if the compiler supports a given builtin.
  * Supported by virtually all clang versions and recent gcc. Use this
@@ -253,7 +259,7 @@
 #ifndef SDL_PRIs64
 #ifdef PRIs64
 #define SDL_PRIs64 PRIs64
-#elif defined(__WIN32__)
+#elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIs64 "I64d"
 #elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIs64 "ld"
@@ -264,7 +270,7 @@
 #ifndef SDL_PRIu64
 #ifdef PRIu64
 #define SDL_PRIu64 PRIu64
-#elif defined(__WIN32__)
+#elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIu64 "I64u"
 #elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIu64 "lu"
@@ -275,7 +281,7 @@
 #ifndef SDL_PRIx64
 #ifdef PRIx64
 #define SDL_PRIx64 PRIx64
-#elif defined(__WIN32__)
+#elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIx64 "I64x"
 #elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIx64 "lx"
@@ -286,7 +292,7 @@
 #ifndef SDL_PRIX64
 #ifdef PRIX64
 #define SDL_PRIX64 PRIX64
-#elif defined(__WIN32__)
+#elif defined(__WIN32__) || defined(__GDK__)
 #define SDL_PRIX64 "I64X"
 #elif defined(__LINUX__) && defined(__LP64__)
 #define SDL_PRIX64 "lX"
@@ -367,14 +373,22 @@
 #endif
 #endif /* SDL_DISABLE_ANALYZE_MACROS */
 
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
-#define SDL_COMPILE_TIME_ASSERT(name, x) _Static_assert(x, #x)
-#elif defined(__cplusplus) && (__cplusplus >= 201103L)
+#ifndef SDL_COMPILE_TIME_ASSERT
+#if defined(__cplusplus)
+#if (__cplusplus >= 201103L)
 #define SDL_COMPILE_TIME_ASSERT(name, x)  static_assert(x, #x)
-#else /* universal, but may trigger -Wunused-local-typedefs */
+#endif
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+#define SDL_COMPILE_TIME_ASSERT(name, x) _Static_assert(x, #x)
+#endif
+#endif /* !SDL_COMPILE_TIME_ASSERT */
+
+#ifndef SDL_COMPILE_TIME_ASSERT
+/* universal, but may trigger -Wunused-local-typedefs */
 #define SDL_COMPILE_TIME_ASSERT(name, x)               \
        typedef int SDL_compile_time_assert_ ## name[(x) * 2 - 1]
 #endif
+
 /** \cond */
 #ifndef DOXYGEN_SHOULD_IGNORE_THIS
 SDL_COMPILE_TIME_ASSERT(uint8, sizeof(Uint8) == 1);
@@ -433,6 +447,16 @@
 typedef void (SDLCALL *SDL_free_func)(void *mem);
 
 /**
+ * Get the original set of SDL memory functions
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC void SDLCALL SDL_GetOriginalMemoryFunctions(SDL_malloc_func *malloc_func,
+                                                            SDL_calloc_func *calloc_func,
+                                                            SDL_realloc_func *realloc_func,
+                                                            SDL_free_func *free_func);
+
+/**
  * Get the current set of SDL memory functions
  *
  * \since This function is available since SDL 2.0.7.
@@ -462,7 +486,8 @@
 extern DECLSPEC char *SDLCALL SDL_getenv(const char *name);
 extern DECLSPEC int SDLCALL SDL_setenv(const char *name, const char *value, int overwrite);
 
-extern DECLSPEC void SDLCALL SDL_qsort(void *base, size_t nmemb, size_t size, int (*compare) (const void *, const void *));
+extern DECLSPEC void SDLCALL SDL_qsort(void *base, size_t nmemb, size_t size, int (SDLCALL *compare) (const void *, const void *));
+extern DECLSPEC void * SDLCALL SDL_bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (SDLCALL *compare) (const void *, const void *));
 
 extern DECLSPEC int SDLCALL SDL_abs(int x);
 
@@ -486,6 +511,7 @@
 extern DECLSPEC int SDLCALL SDL_toupper(int x);
 extern DECLSPEC int SDLCALL SDL_tolower(int x);
 
+extern DECLSPEC Uint16 SDLCALL SDL_crc16(Uint16 crc, const void *data, size_t len);
 extern DECLSPEC Uint32 SDLCALL SDL_crc32(Uint32 crc, const void *data, size_t len);
 
 extern DECLSPEC void *SDLCALL SDL_memset(SDL_OUT_BYTECAP(len) void *dst, int c, size_t len);
@@ -494,6 +520,11 @@
 #define SDL_zerop(x) SDL_memset((x), 0, sizeof(*(x)))
 #define SDL_zeroa(x) SDL_memset((x), 0, sizeof((x)))
 
+#define SDL_copyp(dst, src)                                                                 \
+    { SDL_COMPILE_TIME_ASSERT(SDL_copyp, sizeof (*(dst)) == sizeof (*(src))); }             \
+    SDL_memcpy((dst), (src), sizeof (*(src)))
+
+
 /* Note that memset() is a byte assignment and this is a 32-bit assignment, so they're not directly equivalent. */
 SDL_FORCE_INLINE void SDL_memset4(void *dst, Uint32 val, size_t dwords)
 {
@@ -554,6 +585,7 @@
 extern DECLSPEC char *SDLCALL SDL_strstr(const char *haystack, const char *needle);
 extern DECLSPEC char *SDLCALL SDL_strtokr(char *s1, const char *s2, char **saveptr);
 extern DECLSPEC size_t SDLCALL SDL_utf8strlen(const char *str);
+extern DECLSPEC size_t SDLCALL SDL_utf8strnlen(const char *str, size_t bytes);
 
 extern DECLSPEC char *SDLCALL SDL_itoa(int value, char *str, int radix);
 extern DECLSPEC char *SDLCALL SDL_uitoa(unsigned int value, char *str, int radix);
@@ -726,6 +758,65 @@
 {
     return SDL_memcpy(dst, src, dwords * 4);
 }
+
+/**
+ * If a * b would overflow, return -1. Otherwise store a * b via ret
+ * and return 0.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+SDL_FORCE_INLINE int SDL_size_mul_overflow (size_t a,
+                                            size_t b,
+                                            size_t *ret)
+{
+    if (a != 0 && b > SDL_SIZE_MAX / a) {
+        return -1;
+    }
+    *ret = a * b;
+    return 0;
+}
+
+#if _SDL_HAS_BUILTIN(__builtin_mul_overflow)
+/* This needs to be wrapped in an inline rather than being a direct #define,
+ * because __builtin_mul_overflow() is type-generic, but we want to be
+ * consistent about interpreting a and b as size_t. */
+SDL_FORCE_INLINE int _SDL_size_mul_overflow_builtin (size_t a,
+                                                     size_t b,
+                                                     size_t *ret)
+{
+    return __builtin_mul_overflow(a, b, ret) == 0 ? 0 : -1;
+}
+#define SDL_size_mul_overflow(a, b, ret) (_SDL_size_mul_overflow_builtin(a, b, ret))
+#endif
+
+/**
+ * If a + b would overflow, return -1. Otherwise store a + b via ret
+ * and return 0.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+SDL_FORCE_INLINE int SDL_size_add_overflow (size_t a,
+                                            size_t b,
+                                            size_t *ret)
+{
+    if (b > SDL_SIZE_MAX - a) {
+        return -1;
+    }
+    *ret = a + b;
+    return 0;
+}
+
+#if _SDL_HAS_BUILTIN(__builtin_add_overflow)
+/* This needs to be wrapped in an inline rather than being a direct #define,
+ * the same as the call to __builtin_mul_overflow() above. */
+SDL_FORCE_INLINE int _SDL_size_add_overflow_builtin (size_t a,
+                                                     size_t b,
+                                                     size_t *ret)
+{
+    return __builtin_add_overflow(a, b, ret) == 0 ? 0 : -1;
+}
+#define SDL_size_add_overflow(a, b, ret) (_SDL_size_add_overflow_builtin(a, b, ret))
+#endif
 
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_surface.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_surface.h
@@ -61,6 +61,8 @@
  */
 #define SDL_MUSTLOCK(S) (((S)->flags & SDL_RLEACCEL) != 0)
 
+typedef struct SDL_BlitMap SDL_BlitMap;  /* this is an opaque type. */
+
 /**
  * \brief A collection of pixels used in software blitting.
  *
@@ -88,7 +90,7 @@
     SDL_Rect clip_rect;         /**< Read-only */
 
     /** info for fast blit mapping to other surfaces */
-    struct SDL_BlitMap *map;    /**< Private */
+    SDL_BlitMap *map;           /**< Private */
 
     /** Reference count -- used when freeing surface */
     int refcount;               /**< Read-mostly */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_system.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_system.h
@@ -41,7 +41,7 @@
 
 
 /* Platform specific functions for Windows */
-#ifdef __WIN32__
+#if defined(__WIN32__) || defined(__GDK__)
 	
 typedef void (SDLCALL * SDL_WindowsMessageHook)(void *userdata, void *hWnd, unsigned int message, Uint64 wParam, Sint64 lParam);
 
@@ -55,6 +55,10 @@
  */
 extern DECLSPEC void SDLCALL SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata);
 
+#endif /* defined(__WIN32__) || defined(__GDK__) */
+
+#if defined(__WIN32__) || defined(__WINGDK__)
+
 /**
  * Get the D3D9 adapter index that matches the specified display index.
  *
@@ -102,7 +106,31 @@
  */
 extern DECLSPEC ID3D11Device* SDLCALL SDL_RenderGetD3D11Device(SDL_Renderer * renderer);
 
+#endif /* defined(__WIN32__) || defined(__WINGDK__) */
+
+#if defined(__WIN32__) || defined(__GDK__)
+
+typedef struct ID3D12Device ID3D12Device;
+
 /**
+ * Get the D3D12 device associated with a renderer.
+ *
+ * Once you are done using the device, you should release it to avoid a
+ * resource leak.
+ *
+ * \param renderer the renderer from which to get the associated D3D12 device
+ * \returns the D3D12 device associated with given renderer or NULL if it is
+ *          not a D3D12 renderer; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC ID3D12Device* SDLCALL SDL_RenderGetD3D12Device(SDL_Renderer* renderer);
+
+#endif /* defined(__WIN32__) || defined(__GDK__) */
+
+#if defined(__WIN32__) || defined(__WINGDK__)
+
+/**
  * Get the DXGI Adapter and Output indices for the specified display index.
  *
  * The DXGI Adapter and Output indices can be passed to `EnumAdapters` and
@@ -122,9 +150,8 @@
  */
 extern DECLSPEC SDL_bool SDLCALL SDL_DXGIGetOutputInfo( int displayIndex, int *adapterIndex, int *outputIndex );
 
-#endif /* __WIN32__ */
+#endif /* defined(__WIN32__) || defined(__WINGDK__) */
 
-
 /* Platform specific functions for Linux */
 #ifdef __LINUX__
 
@@ -178,7 +205,7 @@
  * This function is only available on Apple iOS.
  *
  * For more information see:
- * [README-ios.md](https://hg.libsdl.org/SDL/file/default/docs/README-ios.md)
+ * https://github.com/libsdl-org/SDL/blob/main/docs/README-ios.md
  *
  * This functions is also accessible using the macro
  * SDL_iOSSetAnimationCallback() since SDL 2.0.4.
@@ -195,7 +222,7 @@
  *
  * \sa SDL_iPhoneSetEventPump
  */
-extern DECLSPEC int SDLCALL SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam);
+extern DECLSPEC int SDLCALL SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (SDLCALL *callback)(void*), void *callbackParam);
 
 #define SDL_iOSSetEventPump(enabled) SDL_iPhoneSetEventPump(enabled)
 
@@ -532,7 +559,7 @@
 extern DECLSPEC const char * SDLCALL SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType);
 
 /**
- * Detects the device family of WinRT plattform at runtime.
+ * Detects the device family of WinRT platform at runtime.
  *
  * \returns a value from the SDL_WinRT_DeviceFamily enum.
  *
@@ -562,6 +589,27 @@
 extern DECLSPEC void SDLCALL SDL_OnApplicationDidBecomeActive(void);
 #ifdef __IPHONEOS__
 extern DECLSPEC void SDLCALL SDL_OnApplicationDidChangeStatusBarOrientation(void);
+#endif
+
+/* Functions used only by GDK */
+#if defined(__GDK__)
+typedef struct XTaskQueueObject * XTaskQueueHandle;
+
+/**
+ * Gets a reference to the global async task queue handle for GDK,
+ * initializing if needed.
+ *
+ * Once you are done with the task queue, you should call
+ * XTaskQueueCloseHandle to reduce the reference count to avoid a resource
+ * leak.
+ *
+ * \param outTaskQueue a pointer to be filled in with task queue handle.
+ * \returns 0 if success, -1 if any error occurs.
+ *
+ * \since This function is available since SDL 2.24.0.
+ */
+extern DECLSPEC int SDLCALL SDL_GDKGetTaskQueue(XTaskQueueHandle * outTaskQueue);
+
 #endif
 
 /* Ends C function definitions when using C++ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_common.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_common.h
@@ -50,6 +50,7 @@
 #define VERBOSE_RENDER  0x00000004
 #define VERBOSE_EVENT   0x00000008
 #define VERBOSE_AUDIO   0x00000010
+#define VERBOSE_MOTION  0x00000020
 
 typedef struct
 {
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_font.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_font.h
@@ -38,7 +38,8 @@
 
 /* Function prototypes */
 
-#define FONT_CHARACTER_SIZE  8
+#define FONT_CHARACTER_SIZE 8
+#define FONT_LINE_HEIGHT    (FONT_CHARACTER_SIZE + 2)
 
 /**
  *  \brief Draw a string in the currently set font.
@@ -50,11 +51,13 @@
  *
  *  \returns 0 on success, -1 on failure.
  */
-int SDLTest_DrawCharacter(SDL_Renderer *renderer, int x, int y, char c);
+int SDLTest_DrawCharacter(SDL_Renderer *renderer, int x, int y, Uint32 c);
 
 /**
- *  \brief Draw a string in the currently set font.
+ *  \brief Draw a UTF-8 string in the currently set font.
  *
+ *  The font currently only supports characters in the Basic Latin and Latin-1 Supplement sets.
+ *
  *  \param renderer The renderer to draw on.
  *  \param x The X coordinate of the upper left corner of the string.
  *  \param y The Y coordinate of the upper left corner of the string.
@@ -64,6 +67,90 @@
  */
 int SDLTest_DrawString(SDL_Renderer *renderer, int x, int y, const char *s);
 
+/**
+ *  \brief Data used for multi-line text output
+ */
+typedef struct SDLTest_TextWindow
+{
+    SDL_Rect rect;
+    int current;
+    int numlines;
+    char **lines;
+} SDLTest_TextWindow;
+
+/**
+ *  \brief Create a multi-line text output window
+ *
+ *  \param x The X coordinate of the upper left corner of the window.
+ *  \param y The Y coordinate of the upper left corner of the window.
+ *  \param w The width of the window (currently ignored)
+ *  \param h The height of the window (currently ignored)
+ *
+ *  \returns the new window, or NULL on failure.
+ *
+ *  \since This function is available since SDL 2.24.0
+ */
+SDLTest_TextWindow *SDLTest_TextWindowCreate(int x, int y, int w, int h);
+
+/**
+ *  \brief Display a multi-line text output window
+ *
+ *  This function should be called every frame to display the text
+ *
+ *  \param textwin The text output window
+ *  \param renderer The renderer to use for display
+ *
+ *  \since This function is available since SDL 2.24.0
+ */
+void SDLTest_TextWindowDisplay(SDLTest_TextWindow *textwin, SDL_Renderer *renderer);
+
+/**
+ *  \brief Add text to a multi-line text output window
+ *
+ *  Adds UTF-8 text to the end of the current text. The newline character starts a
+ *  new line of text. The backspace character deletes the last character or, if the
+ *  line is empty, deletes the line and goes to the end of the previous line.
+ *
+ *  \param textwin The text output window
+ *  \param fmt A printf() style format string
+ *  \param ...  additional parameters matching % tokens in the `fmt` string, if any
+ *
+ *  \since This function is available since SDL 2.24.0
+ */
+void SDLTest_TextWindowAddText(SDLTest_TextWindow *textwin, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(2);
+
+/**
+ *  \brief Add text to a multi-line text output window
+ *
+ *  Adds UTF-8 text to the end of the current text. The newline character starts a
+ *  new line of text. The backspace character deletes the last character or, if the
+ *  line is empty, deletes the line and goes to the end of the previous line.
+ *
+ *  \param textwin The text output window
+ *  \param text The text to add to the window
+ *  \param len The length, in bytes, of the text to add to the window
+ *
+ *  \since This function is available since SDL 2.24.0
+ */
+void SDLTest_TextWindowAddTextWithLength(SDLTest_TextWindow *textwin, const char *text, size_t len);
+
+/**
+ *  \brief Clear the text in a multi-line text output window
+ *
+ *  \param textwin The text output window
+ *
+ *  \since This function is available since SDL 2.24.0
+ */
+void SDLTest_TextWindowClear(SDLTest_TextWindow *textwin);
+
+/**
+ *  \brief Free the storage associated with a multi-line text output window
+ *
+ *  \param textwin The text output window
+ *
+ *  \since This function is available since SDL 2.24.0
+ */
+void SDLTest_TextWindowDestroy(SDLTest_TextWindow *textwin);
 
 /**
  *  \brief Cleanup textures used by font drawing functions.
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_thread.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_thread.h
@@ -35,7 +35,7 @@
 #include "SDL_atomic.h"
 #include "SDL_mutex.h"
 
-#if defined(__WIN32__)
+#if defined(__WIN32__) || defined(__GDK__)
 #include <process.h> /* _beginthreadex() and _endthreadex() */
 #endif
 #if defined(__OS2__) /* for _beginthread() and _endthread() */
@@ -88,7 +88,7 @@
 typedef int (SDLCALL * SDL_ThreadFunction) (void *data);
 
 
-#if defined(__WIN32__)
+#if defined(__WIN32__) || defined(__GDK__)
 /**
  *  \file SDL_thread.h
  *
@@ -129,7 +129,7 @@
                  pfnSDL_CurrentEndThread pfnEndThread);
 
 extern DECLSPEC SDL_Thread *SDLCALL
-SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *),
+SDL_CreateThreadWithStackSize(SDL_ThreadFunction fn,
                  const char *name, const size_t stacksize, void *data,
                  pfnSDL_CurrentBeginThread pfnBeginThread,
                  pfnSDL_CurrentEndThread pfnEndThread);
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_version.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_version.h
@@ -58,8 +58,8 @@
 /* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
 */
 #define SDL_MAJOR_VERSION   2
-#define SDL_MINOR_VERSION   0
-#define SDL_PATCHLEVEL      22
+#define SDL_MINOR_VERSION   24
+#define SDL_PATCHLEVEL      1
 
 /**
  * Macro to determine SDL version program was compiled against.
@@ -83,6 +83,8 @@
     (x)->patch = SDL_PATCHLEVEL;                    \
 }
 
+/* TODO: Remove this whole block in SDL 3 */
+#if SDL_MAJOR_VERSION < 3
 /**
  *  This macro turns the version numbers into a numeric value:
  *  \verbatim
@@ -90,6 +92,11 @@
     \endverbatim
  *
  *  This assumes that there will never be more than 100 patchlevels.
+ *
+ *  In versions higher than 2.9.0, the minor version overflows into
+ *  the thousands digit: for example, 2.23.0 is encoded as 4300,
+ *  and 2.255.99 would be encoded as 25799.
+ *  This macro will not be available in SDL 3.x.
  */
 #define SDL_VERSIONNUM(X, Y, Z)                     \
     ((X)*1000 + (Y)*100 + (Z))
@@ -96,15 +103,24 @@
 
 /**
  *  This is the version number macro for the current SDL version.
+ *
+ *  In versions higher than 2.9.0, the minor version overflows into
+ *  the thousands digit: for example, 2.23.0 is encoded as 4300.
+ *  This macro will not be available in SDL 3.x.
+ *
+ *  Deprecated, use SDL_VERSION_ATLEAST or SDL_VERSION instead.
  */
 #define SDL_COMPILEDVERSION \
     SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL)
+#endif /* SDL_MAJOR_VERSION < 3 */
 
 /**
  *  This macro will evaluate to true if compiled with SDL at least X.Y.Z.
  */
 #define SDL_VERSION_ATLEAST(X, Y, Z) \
-    (SDL_COMPILEDVERSION >= SDL_VERSIONNUM(X, Y, Z))
+    ((SDL_MAJOR_VERSION >= X) && \
+     (SDL_MAJOR_VERSION > X || SDL_MINOR_VERSION >= Y) && \
+     (SDL_MAJOR_VERSION > X || SDL_MINOR_VERSION > Y || SDL_PATCHLEVEL >= Z))
 
 /**
  * Get the version of SDL that is linked against your program.
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_video.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_video.h
@@ -248,7 +248,8 @@
     SDL_GL_FRAMEBUFFER_SRGB_CAPABLE,
     SDL_GL_CONTEXT_RELEASE_BEHAVIOR,
     SDL_GL_CONTEXT_RESET_NOTIFICATION,
-    SDL_GL_CONTEXT_NO_ERROR
+    SDL_GL_CONTEXT_NO_ERROR,
+    SDL_GL_FLOATBUFFERS
 } SDL_GLattr;
 
 typedef enum
@@ -444,6 +445,15 @@
  * A failure of this function usually means that either no DPI information is
  * available or the `displayIndex` is out of range.
  *
+ * **WARNING**: This reports the DPI that the hardware reports, and it is not
+ * always reliable! It is almost always better to use SDL_GetWindowSize() to
+ * find the window size, which might be in logical points instead of pixels,
+ * and then SDL_GL_GetDrawableSize(), SDL_Vulkan_GetDrawableSize(),
+ * SDL_Metal_GetDrawableSize(), or SDL_GetRendererOutputSize(), and compare
+ * the two values to get an actual scaling value between the two. We will be
+ * rethinking how high-dpi details should be managed in SDL3 to make things
+ * more consistent, reliable, and clear.
+ *
  * \param displayIndex the index of the display from which DPI information
  *                     should be queried
  * \param ddpi a pointer filled in with the diagonal DPI of the display; may
@@ -588,6 +598,35 @@
 extern DECLSPEC SDL_DisplayMode * SDLCALL SDL_GetClosestDisplayMode(int displayIndex, const SDL_DisplayMode * mode, SDL_DisplayMode * closest);
 
 /**
+ * Get the index of the display containing a point
+ *
+ * \param point the point to query
+ * \returns the index of the display containing the point or a negative error
+ *          code on failure; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GetDisplayBounds
+ * \sa SDL_GetNumVideoDisplays
+ */
+extern DECLSPEC int SDLCALL SDL_GetPointDisplayIndex(const SDL_Point * point);
+
+/**
+ * Get the index of the display primarily containing a rect
+ *
+ * \param rect the rect to query
+ * \returns the index of the display entirely containing the rect or closest
+ *          to the center of the rect on success or a negative error code on
+ *          failure; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.24.0.
+ *
+ * \sa SDL_GetDisplayBounds
+ * \sa SDL_GetNumVideoDisplays
+ */
+extern DECLSPEC int SDLCALL SDL_GetRectDisplayIndex(const SDL_Rect * rect);
+
+/**
  * Get the index of the display associated with a window.
  *
  * \param window the window to query
@@ -697,7 +736,10 @@
  * in pixels may differ from its size in screen coordinates on platforms with
  * high-DPI support (e.g. iOS and macOS). Use SDL_GetWindowSize() to query the
  * client area's size in screen coordinates, and SDL_GL_GetDrawableSize() or
- * SDL_GetRendererOutputSize() to query the drawable size in pixels.
+ * SDL_GetRendererOutputSize() to query the drawable size in pixels. Note that
+ * when this flag is set, the drawable size can vary after the window is
+ * created and should be queried after major window events such as when the
+ * window is resized or moved between displays.
  *
  * If the window is set fullscreen, the width and height parameters `w` and
  * `h` will not be used. However, invalid size parameters (e.g. too large) may
@@ -2009,13 +2051,8 @@
  * retry the call with 1 for the interval.
  *
  * Adaptive vsync is implemented for some glX drivers with
- * GLX_EXT_swap_control_tear:
- *
- * https://www.opengl.org/registry/specs/EXT/glx_swap_control_tear.txt
- *
- * and for some Windows drivers with WGL_EXT_swap_control_tear:
- *
- * https://www.opengl.org/registry/specs/EXT/wgl_swap_control_tear.txt
+ * GLX_EXT_swap_control_tear, and for some Windows drivers with
+ * WGL_EXT_swap_control_tear.
  *
  * Read more on the Khronos wiki:
  * https://www.khronos.org/opengl/wiki/Swap_Interval#Adaptive_Vsync
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/begin_code.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/begin_code.h
@@ -34,7 +34,7 @@
 #define _begin_code_h
 
 #ifndef SDL_DEPRECATED
-#  if (__GNUC__ >= 4)  /* technically, this arrived in gcc 3.1, but oh well. */
+#  if defined(__GNUC__) && (__GNUC__ >= 4)  /* technically, this arrived in gcc 3.1, but oh well. */
 #    define SDL_DEPRECATED __attribute__((deprecated))
 #  else
 #    define SDL_DEPRECATED
@@ -51,7 +51,7 @@
 
 /* Some compilers use a special export keyword */
 #ifndef DECLSPEC
-# if defined(__WIN32__) || defined(__WINRT__) || defined(__CYGWIN__)
+# if defined(__WIN32__) || defined(__WINRT__) || defined(__CYGWIN__) || defined(__GDK__)
 #  ifdef DLL_EXPORT
 #   define DECLSPEC __declspec(dllexport)
 #  else
@@ -74,7 +74,7 @@
 
 /* By default SDL uses the C calling convention */
 #ifndef SDLCALL
-#if (defined(__WIN32__) || defined(__WINRT__)) && !defined(__GNUC__)
+#if (defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__)) && !defined(__GNUC__)
 #define SDLCALL __cdecl
 #elif defined(__OS2__) || defined(__EMX__)
 #define SDLCALL _System
binary files a/vs2019_project/pt2-clone/sdl/lib/SDL2.lib b/vs2019_project/pt2-clone/sdl/lib/SDL2.lib differ
binary files a/vs2019_project/pt2-clone/sdl/lib/SDL2main.lib b/vs2019_project/pt2-clone/sdl/lib/SDL2main.lib differ
binary files a/vs2019_project/pt2-clone/sdl/lib64/SDL2.lib b/vs2019_project/pt2-clone/sdl/lib64/SDL2.lib differ
binary files a/vs2019_project/pt2-clone/sdl/lib64/SDL2main.lib b/vs2019_project/pt2-clone/sdl/lib64/SDL2main.lib differ
binary files a/vs2019_project/x64/Debug/SDL2.dll b/vs2019_project/x64/Debug/SDL2.dll differ